static gint camel_ustrncasecmp (const gchar *ps1, const gchar *ps2, gsize len) { gunichar u1, u2 = 0; const guchar *s1 = (const guchar *)ps1; const guchar *s2 = (const guchar *)ps2; CAMEL_SEARCH_COMPARE (s1, s2, NULL); u1 = camel_utf8_getc (&s1); u2 = camel_utf8_getc (&s2); while (len > 0 && u1 && u2) { u1 = g_unichar_tolower (u1); u2 = g_unichar_tolower (u2); if (u1 < u2) return -1; else if (u1 > u2) return 1; len--; u1 = camel_utf8_getc (&s1); u2 = camel_utf8_getc (&s2); } if (len == 0) return 0; /* end of one of the strings ? */ CAMEL_SEARCH_COMPARE (u1, u2, 0); /* if we have invalid utf8 sequence ? */ CAMEL_SEARCH_COMPARE (s1, s2, NULL); return 0; }
static int camel_ustrcasecmp (const char *ps1, const char *ps2) { gunichar u1, u2 = 0; const unsigned char *s1 = (const unsigned char *)ps1; const unsigned char *s2 = (const unsigned char *)ps2; CAMEL_SEARCH_COMPARE (s1, s2, NULL); u1 = camel_utf8_getc(&s1); u2 = camel_utf8_getc(&s2); while (u1 && u2) { u1 = g_unichar_tolower (u1); u2 = g_unichar_tolower (u2); if (u1 < u2) return -1; else if (u1 > u2) return 1; u1 = camel_utf8_getc(&s1); u2 = camel_utf8_getc(&s2); } /* end of one of the strings ? */ CAMEL_SEARCH_COMPARE (u1, u2, 0); /* if we have invalid utf8 sequence ? */ CAMEL_SEARCH_COMPARE (s1, s2, NULL); return 0; }
/* value is the match value suitable for exact match if required */ static int header_match(const char *value, const char *match, camel_search_match_t how) { const unsigned char *p; int vlen, mlen; gunichar c; if (how == CAMEL_SEARCH_MATCH_SOUNDEX) return header_soundex (value, match); vlen = strlen(value); mlen = strlen(match); if (vlen < mlen) return FALSE; /* from dan the man, if we have mixed case, perform a case-sensitive match, otherwise not */ p = (const unsigned char *)match; c = camel_utf8_getc (&p); while (c) { if (g_unichar_isupper(c)) { switch (how) { case CAMEL_SEARCH_MATCH_EXACT: return strcmp(value, match) == 0; case CAMEL_SEARCH_MATCH_CONTAINS: return strstr(value, match) != NULL; case CAMEL_SEARCH_MATCH_STARTS: return strncmp(value, match, mlen) == 0; case CAMEL_SEARCH_MATCH_ENDS: return strcmp(value + vlen - mlen, match) == 0; default: break; } return FALSE; } c = camel_utf8_getc (&p); } switch (how) { case CAMEL_SEARCH_MATCH_EXACT: return camel_ustrcasecmp(value, match) == 0; case CAMEL_SEARCH_MATCH_CONTAINS: return camel_ustrstrcase(value, match) != NULL; case CAMEL_SEARCH_MATCH_STARTS: return camel_ustrncasecmp(value, match, mlen) == 0; case CAMEL_SEARCH_MATCH_ENDS: return camel_ustrcasecmp(value + vlen - mlen, match) == 0; default: break; } return FALSE; }
const gchar * camel_ustrstrcase (const gchar *haystack, const gchar *needle) { gunichar *nuni, *puni; gunichar u; const guchar *p; g_return_val_if_fail (haystack != NULL, NULL); g_return_val_if_fail (needle != NULL, NULL); if (strlen (needle) == 0) return haystack; if (strlen (haystack) == 0) return NULL; puni = nuni = g_alloca (sizeof (gunichar) * strlen (needle)); p = (const guchar *) needle; while ((u = camel_utf8_getc (&p))) *puni++ = g_unichar_tolower (u); /* NULL means there was illegal utf-8 sequence */ if (!p) return NULL; p = (const guchar *)haystack; while ((u = camel_utf8_getc (&p))) { gunichar c; c = g_unichar_tolower (u); /* We have valid stripped gchar */ if (c == nuni[0]) { const guchar *q = p; gint npos = 1; while (nuni + npos < puni) { u = camel_utf8_getc (&q); if (!q || !u) return NULL; c = g_unichar_tolower (u); if (c != nuni[npos]) break; npos++; } if (nuni + npos == puni) return (const gchar *) p; } } return NULL; }
struct _camel_search_words * camel_search_words_split (const guchar *in) { gint type = CAMEL_SEARCH_WORD_SIMPLE, all = 0; GString *w; struct _camel_search_words *words; GPtrArray *list = g_ptr_array_new (); guint32 c; gint inquote = 0; words = g_malloc0 (sizeof (*words)); w = g_string_new(""); do { c = camel_utf8_getc (&in); if (c == 0 || (inquote && c == '"') || (!inquote && g_unichar_isspace (c))) { output_w (w, list, type); all |= type; type = CAMEL_SEARCH_WORD_SIMPLE; inquote = 0; } else { if (c == '\\') { c = camel_utf8_getc (&in); if (c) output_c (w, c, &type); else { output_w (w, list, type); all |= type; } } else if (c == '\"') { inquote = 1; } else { output_c (w, c, &type); } } } while (c); g_string_free (w, TRUE); words->len = list->len; words->words = (struct _camel_search_word **)list->pdata; words->type = all; g_ptr_array_free (list, FALSE); return words; }
/* takes an existing 'words' list, and converts it to another consisting of only simple words, with any punctuation etc stripped */ struct _camel_search_words * camel_search_words_simple (struct _camel_search_words *wordin) { gint i; const guchar *ptr, *start, *last; gint type = CAMEL_SEARCH_WORD_SIMPLE, all = 0; GPtrArray *list = g_ptr_array_new (); struct _camel_search_word *word; struct _camel_search_words *words; guint32 c; words = g_malloc0 (sizeof (*words)); for (i=0;i<wordin->len;i++) { if ((wordin->words[i]->type & CAMEL_SEARCH_WORD_COMPLEX) == 0) { word = g_malloc0 (sizeof (*word)); word->type = wordin->words[i]->type; word->word = g_strdup (wordin->words[i]->word); g_ptr_array_add (list, word); } else { ptr = (const guchar *) wordin->words[i]->word; start = last = ptr; do { c = camel_utf8_getc (&ptr); if (c == 0 || !g_unichar_isalnum (c)) { if (last > start) { word = g_malloc0 (sizeof (*word)); word->word = g_strndup ((gchar *) start, last-start); word->type = type; g_ptr_array_add (list, word); all |= type; type = CAMEL_SEARCH_WORD_SIMPLE; } start = ptr; } if (c > 0x80) type = CAMEL_SEARCH_WORD_8BIT; last = ptr; } while (c); } } words->len = list->len; words->words = (struct _camel_search_word **)list->pdata; words->type = all; g_ptr_array_free (list, FALSE); return words; }
/** * clean_name code from mail-to-task plugin (gpl) **/ static gchar * clean_name(const guchar *s) { GString *out = g_string_new(""); guint32 c; gchar *r; while ((c = camel_utf8_getc((const guchar **) & s))) { if (!g_unichar_isprint(c) || (c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c))) c = '_'; g_string_append_u(out, c); } r = g_strdup(out->str); g_string_free(out, TRUE); return r; }
char * camel_nntp_store_summary_path_to_full (CamelNNTPStoreSummary *s, const char *path, char dir_sep) { char *full, *f; guint32 c, v = 0; const char *p; int state=0; char *subpath, *last = NULL; CamelStoreInfo *si; /* check to see if we have a subpath of path already defined */ subpath = g_alloca (strlen (path) + 1); strcpy (subpath, path); do { si = camel_store_summary_path ((CamelStoreSummary *) s, subpath); if (si == NULL) { last = strrchr (subpath, '/'); if (last) *last = 0; } } while (si == NULL && last); /* path is already present, use the raw version we have */ if (si && strlen (subpath) == strlen (path)) { f = g_strdup (camel_nntp_store_info_full_name (s, si)); camel_store_summary_info_free ((CamelStoreSummary *) s, si); return f; } f = full = g_alloca (strlen (path)*2+1); if (si) p = path + strlen (subpath); else p = path; while ((c = camel_utf8_getc ((const unsigned char **) &p))) { switch (state) { case 0: if (c == '%') { state = 1; } else { if (c == '/') c = dir_sep; camel_utf8_putc((unsigned char **) &f, c); } break; case 1: state = 2; v = hexnib (c) << 4; break; case 2: state = 0; v |= hexnib (c); camel_utf8_putc ((unsigned char **) &f, v); break; } } camel_utf8_putc ((unsigned char **) &f, c); /* merge old path part if required */ f = camel_utf8_utf7 (full); if (si) { full = g_strdup_printf ("%s%s", camel_nntp_store_info_full_name (s, si), f); g_free (f); camel_store_summary_info_free ((CamelStoreSummary *) s, si); f = full; } return f; }
/* searhces for match inside value, if match is mixed case, hten use case-sensitive, else insensitive */ gboolean camel_search_header_match (const gchar *value, const gchar *match, camel_search_match_t how, camel_search_t type, const gchar *default_charset) { const gchar *name, *addr; const guchar *ptr; gint truth = FALSE, i; CamelInternetAddress *cia; gchar *v, *vdom, *mdom; gunichar c; ptr = (const guchar *)value; while ((c = camel_utf8_getc (&ptr)) && g_unichar_isspace (c)) value = (const gchar *)ptr; switch (type) { case CAMEL_SEARCH_TYPE_ENCODED: v = camel_header_decode_string (value, default_charset); /* FIXME: Find header charset */ truth = header_match (v, match, how); g_free (v); break; case CAMEL_SEARCH_TYPE_MLIST: /* Special mailing list old-version domain hack If one of the mailing list names doesn't have an @ in it, its old-style, so only match against the pre-domain part, which should be common */ vdom = strchr (value, '@'); mdom = strchr (match, '@'); if (mdom == NULL && vdom != NULL) { v = g_alloca (vdom-value+1); memcpy (v, value, vdom-value); v[vdom-value] = 0; value = (gchar *)v; } else if (mdom != NULL && vdom == NULL) { v = g_alloca (mdom-match+1); memcpy (v, match, mdom-match); v[mdom-match] = 0; match = (gchar *)v; } /* Falls through */ case CAMEL_SEARCH_TYPE_ASIS: truth = header_match (value, match, how); break; case CAMEL_SEARCH_TYPE_ADDRESS_ENCODED: case CAMEL_SEARCH_TYPE_ADDRESS: /* possible simple case to save some work if we can */ if (header_match (value, match, how)) return TRUE; /* Now we decode any addresses, and try asis matches on name and address parts */ cia = camel_internet_address_new (); if (type == CAMEL_SEARCH_TYPE_ADDRESS_ENCODED) camel_address_decode ((CamelAddress *)cia, value); else camel_address_unformat ((CamelAddress *)cia, value); for (i=0; !truth && camel_internet_address_get (cia, i, &name, &addr);i++) truth = (name && header_match (name, match, how)) || (addr && header_match (addr, match, how)); g_object_unref (cia); break; } return truth; }