Skip to content
Newer
Older
100644 716 lines (552 sloc) 14.4 KB
e478eee @djcb * reindentation, fix mu_str_ascii_xapian_escape_in_place for '..'
authored
1 /* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
628d154 @djcb * minor / cosmetic changes
authored
2 /*
cf2b81c @djcb * lib: centralize MAX_PATH stuff
authored
3 ** Copyright (C) 2008-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
2b0aca1 @djcb * initial import of mu - the next generation
authored
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 3 of the License, or
8 ** (at your option) any later version.
628d154 @djcb * minor / cosmetic changes
authored
9 **
2b0aca1 @djcb * initial import of mu - the next generation
authored
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
628d154 @djcb * minor / cosmetic changes
authored
14 **
2b0aca1 @djcb * initial import of mu - the next generation
authored
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software Foundation,
628d154 @djcb * minor / cosmetic changes
authored
17 ** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **
2b0aca1 @djcb * initial import of mu - the next generation
authored
19 */
5818c40 @djcb * <many>: fix source code checks; move mu_msg_str_normalize to separa…
authored
20
4f788f6 @djcb * mu-msg-str.[ch], add mu_msg_str_normalize_in_place and some further…
authored
21 #if HAVE_CONFIG_H
22 #include "config.h"
23 #endif /*HAVE_CONFIG_H*/
24
2b0aca1 @djcb * initial import of mu - the next generation
authored
25
26 #include <glib.h>
c09cb13 @djcb * cleanup, improve, refactor message summary
authored
27 #include <string.h>
be06835 @djcb * mu-msg-str: re-implement mu_msg_str_normalize by hand to actually w…
authored
28 #include <ctype.h>
eb4e35f @djcb * improve date range parsing
authored
29 #include <stdlib.h>
d14727c @djcb * dont't require direntry->d_type; this should help the Solaris build.
authored
30 #include <stdio.h>
31
cf2b81c @djcb * lib: centralize MAX_PATH stuff
authored
32 #include "mu-util.h" /* PATH_MAX */
a2dbe36 @djcb * unbreak mu-str
authored
33 #include "mu-str.h"
34 #include "mu-msg-fields.h"
35
36
37 const char*
38 mu_str_size_s (size_t s)
39 {
40 static char buf[32];
41
42 #ifdef HAVE_GLIB216
43 char *tmp;
44
45 tmp = g_format_size_for_display ((goffset)s);
46 strncpy (buf, tmp, sizeof(buf));
47 buf[sizeof(buf) -1] = '\0'; /* just in case */
48 g_free (tmp);
49
50 #else
51 if (s >= 1000 * 1000)
52 g_snprintf(buf, sizeof(buf), "%.1f MB",
53 (double)s/(1000*1000));
54 else
55 g_snprintf(buf, sizeof(buf), "%.1f kB", (double)s/(1000));
56 #endif /*HAVE_GLIB216*/
03ff32d @djcb * cosmetic
authored
57
628d154 @djcb * minor / cosmetic changes
authored
58
a2dbe36 @djcb * unbreak mu-str
authored
59 return buf;
60 }
61
628d154 @djcb * minor / cosmetic changes
authored
62 char*
a2dbe36 @djcb * unbreak mu-str
authored
63 mu_str_size (size_t s)
64 {
65 return g_strdup (mu_str_size_s(s));
66 }
67
68 const char*
a571a3f @djcb * MuMsgFlags => MuFlags
authored
69 mu_str_flags_s (MuFlags flags)
a2dbe36 @djcb * unbreak mu-str
authored
70 {
a571a3f @djcb * MuMsgFlags => MuFlags
authored
71 return mu_flags_to_str_s (flags, MU_FLAG_TYPE_ANY);
a2dbe36 @djcb * unbreak mu-str
authored
72 }
73
74 char*
a571a3f @djcb * MuMsgFlags => MuFlags
authored
75 mu_str_flags (MuFlags flags)
a2dbe36 @djcb * unbreak mu-str
authored
76 {
77 return g_strdup (mu_str_flags_s(flags));
78 }
79
80 char*
81 mu_str_summarize (const char* str, size_t max_lines)
82 {
83 char *summary;
84 size_t nl_seen;
85 unsigned i,j;
86 gboolean last_was_blank;
87
88 g_return_val_if_fail (str, NULL);
89 g_return_val_if_fail (max_lines > 0, NULL);
628d154 @djcb * minor / cosmetic changes
authored
90
a2dbe36 @djcb * unbreak mu-str
authored
91 /* len for summary <= original len */
92 summary = g_new (gchar, strlen(str) + 1);
93
94 /* copy the string up to max_lines lines, replace CR/LF/tab with
95 * single space */
96 for (i = j = 0, nl_seen = 0, last_was_blank = TRUE;
97 nl_seen < max_lines && str[i] != '\0'; ++i) {
98
99 if (str[i] == '\n' || str[i] == '\r' ||
100 str[i] == '\t' || str[i] == ' ' ) {
101
102 if (str[i] == '\n')
103 ++nl_seen;
104
105 /* no double-blanks or blank at end of str */
106 if (!last_was_blank && str[i+1] != '\0')
107 summary[j++] = ' ';
108
109 last_was_blank = TRUE;
110 } else {
111
112 summary[j++] = str[i];
113 last_was_blank = FALSE;
114 }
115 }
116
117 summary[j] = '\0';
118 return summary;
119 }
120
6842c8c @djcb * mu_str_display_contact_s: split, so 'make cc10' is honored
authored
121
122 static void
123 cleanup_contact (char *contact)
124 {
125 char *c, *c2;
628d154 @djcb * minor / cosmetic changes
authored
126
6842c8c @djcb * mu_str_display_contact_s: split, so 'make cc10' is honored
authored
127 /* replace "'<> with space */
128 for (c2 = contact; *c2; ++c2)
129 if (*c2 == '"' || *c2 == '\'' || *c2 == '<' || *c2 == '>')
130 *c2 = ' ';
131
132 /* remove everything between '()' if it's after the 5th pos;
133 * good to cleanup corporate contact address spam... */
134 c = g_strstr_len (contact, -1, "(");
135 if (c && c - contact > 5)
e478eee @djcb * reindentation, fix mu_str_ascii_xapian_escape_in_place for '..'
authored
136 *c = '\0';
628d154 @djcb * minor / cosmetic changes
authored
137
6842c8c @djcb * mu_str_display_contact_s: split, so 'make cc10' is honored
authored
138 g_strstrip (contact);
139 }
140
141
a2dbe36 @djcb * unbreak mu-str
authored
142 /* this is still somewhat simplistic... */
143 const char*
144 mu_str_display_contact_s (const char *str)
145 {
146 static gchar contact[255];
147 gchar *c, *c2;
628d154 @djcb * minor / cosmetic changes
authored
148
a2dbe36 @djcb * unbreak mu-str
authored
149 str = str ? str : "";
150 g_strlcpy (contact, str, sizeof(contact));
151
152 /* we check for '<', so we can strip out the address stuff in
153 * e.g. 'Hello World <hello@world.xx>, but only if there is
154 * something alphanumeric before the <
155 */
156 c = g_strstr_len (contact, -1, "<");
157 if (c != NULL) {
158 for (c2 = contact; c2 < c && !(isalnum(*c2)); ++c2);
159 if (c2 != c) /* apparently, there was something,
160 * so we can remove the <... part*/
161 *c = '\0';
162 }
a7a76e7 @djcb * mu_msg_str: add mu_msg_str_display_contact[_s], to guess the name-p…
authored
163
6842c8c @djcb * mu_str_display_contact_s: split, so 'make cc10' is honored
authored
164 cleanup_contact (contact);
628d154 @djcb * minor / cosmetic changes
authored
165
a2dbe36 @djcb * unbreak mu-str
authored
166 return contact;
167 }
a7a76e7 @djcb * mu_msg_str: add mu_msg_str_display_contact[_s], to guess the name-p…
authored
168
a2dbe36 @djcb * unbreak mu-str
authored
169 char*
170 mu_str_display_contact (const char *str)
171 {
172 g_return_val_if_fail (str, NULL);
a7a76e7 @djcb * mu_msg_str: add mu_msg_str_display_contact[_s], to guess the name-p…
authored
173
a2dbe36 @djcb * unbreak mu-str
authored
174 return g_strdup (mu_str_display_contact_s (str));
175 }
819fe8c @djcb * minor
authored
176
177
6c62a06 @djcb * make time & size checking a bit stricter, report errors to user
authored
178 gint64
179 mu_str_size_parse_bkm (const char* str)
a2dbe36 @djcb * unbreak mu-str
authored
180 {
84662ef @djcb * mu-msg-str: deal with size 0, and add add 'b' for byte in size: que…
authored
181 gint64 num;
6c62a06 @djcb * make time & size checking a bit stricter, report errors to user
authored
182
183 g_return_val_if_fail (str, -1);
184
185 if (!isdigit(str[0]))
186 return -1;
628d154 @djcb * minor / cosmetic changes
authored
187
6c62a06 @djcb * make time & size checking a bit stricter, report errors to user
authored
188 num = atoi(str);
189 for (++str; isdigit(*str); ++str);
628d154 @djcb * minor / cosmetic changes
authored
190
6c62a06 @djcb * make time & size checking a bit stricter, report errors to user
authored
191 switch (tolower(*str)) {
192 case '\0':
193 case 'b' : return num; /* bytes */
194 case 'k': return num * 1000; /* kilobyte */
195 case 'm': return num * 1000 * 1000; /* megabyte */
a2dbe36 @djcb * unbreak mu-str
authored
196 default:
6c62a06 @djcb * make time & size checking a bit stricter, report errors to user
authored
197 return -1;
c5b3059 @djcb * add searching for message size ranges
authored
198 }
199 }
200
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
201
202
203 char*
204 mu_str_from_list (const GSList *lst, char sepa)
205 {
206 const GSList *cur;
207 char *str;
208
209 g_return_val_if_fail (sepa, NULL);
628d154 @djcb * minor / cosmetic changes
authored
210
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
211 for (cur = lst, str = NULL; cur; cur = g_slist_next(cur)) {
212
213 char *tmp;
2b55256 @djcb * mu-str.c: add some dummy bytes, so -Wstack-protector does not complain
authored
214 /* two extra dummy '\0' so -Wstack-protector won't complain */
628d154 @djcb * minor / cosmetic changes
authored
215 char sep[4] = { '\0', '\0', '\0', '\0' };
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
216 sep[0] = cur->next ? sepa : '\0';
217
218 tmp = g_strdup_printf ("%s%s%s",
219 str ? str : "",
220 (gchar*)cur->data,
221 sep);
222 g_free (str);
223 str = tmp;
224 }
628d154 @djcb * minor / cosmetic changes
authored
225
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
226 return str;
227 }
228
229 GSList*
86d7968 @djcb * make mu_msg_to_list optionally strip leading/trailing whitespace
authored
230 mu_str_to_list (const char *str, char sepa, gboolean strip)
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
231 {
232 GSList *lst;
233 gchar **strs, **cur;
2b55256 @djcb * mu-str.c: add some dummy bytes, so -Wstack-protector does not complain
authored
234 /* two extra dummy '\0' so -Wstack-protector won't complain */
628d154 @djcb * minor / cosmetic changes
authored
235 char sep[4] = { '\0', '\0', '\0', '\0' };
236
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
237 g_return_val_if_fail (sepa, NULL);
628d154 @djcb * minor / cosmetic changes
authored
238
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
239 if (!str)
240 return NULL;
241
242 sep[0] = sepa;
243 strs = g_strsplit (str, sep, -1);
244
86d7968 @djcb * make mu_msg_to_list optionally strip leading/trailing whitespace
authored
245 for (cur = strs, lst = NULL; cur && *cur; ++cur) {
246 char *elm;
247 elm = g_strdup(*cur);
248 if (strip)
249 elm = g_strstrip (elm);
628d154 @djcb * minor / cosmetic changes
authored
250
86d7968 @djcb * make mu_msg_to_list optionally strip leading/trailing whitespace
authored
251 lst = g_slist_prepend (lst, elm);
252 }
628d154 @djcb * minor / cosmetic changes
authored
253
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
254 lst = g_slist_reverse (lst);
255 g_strfreev (strs);
256
257 return lst;
258 }
259
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
260
261 static gchar*
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
262 eat_esc_string (char **strlst, GError **err)
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
263 {
264 char *str;
265 gboolean quoted;
266 GString *gstr;
628d154 @djcb * minor / cosmetic changes
authored
267
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
268 str = g_strchug (*strlst);
269 gstr = g_string_sized_new (strlen(str));
628d154 @djcb * minor / cosmetic changes
authored
270
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
271 for (quoted = FALSE; *str; ++str) {
628d154 @djcb * minor / cosmetic changes
authored
272
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
273 if (*str == '"') {
274 quoted = !quoted;
275 continue;
98ca74f * mu-msg-str.c: improve xapian-escaping, string-eating
djcb authored
276 } else if (*str == '\\') {
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
277 if (str[1] != ' ' && str[1] != '"' && str[1] != '\\')
278 goto err; /* invalid escaping */
98ca74f * mu-msg-str.c: improve xapian-escaping, string-eating
djcb authored
279 g_string_append_c (gstr, str[1]);
280 ++str;
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
281 continue;
98ca74f * mu-msg-str.c: improve xapian-escaping, string-eating
djcb authored
282 } else if (*str == ' ' && !quoted) {
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
283 ++str;
284 goto leave;
628d154 @djcb * minor / cosmetic changes
authored
285 } else
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
286 g_string_append_c (gstr, *str);
287 }
288 leave:
289 *strlst = str;
290 return g_string_free (gstr, FALSE);
291 err:
bc6f9eb @djcb * fix glib warnings (compile time, runtime): add error gquark, don't …
authored
292 g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS,
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
293 "error parsing string '%s'", g_strchug(*strlst));
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
294 *strlst = NULL;
295 return g_string_free (gstr, TRUE);
296 }
297
298
299 GSList*
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
300 mu_str_esc_to_list (const char *strings, GError **err)
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
301 {
302 GSList *lst;
628d154 @djcb * minor / cosmetic changes
authored
303 char *mystrings, *freeme;
304 const char* cur;
305
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
306 g_return_val_if_fail (strings, NULL);
307
628d154 @djcb * minor / cosmetic changes
authored
308 for (cur = strings; *cur && (*cur == ' ' || *cur == '\t'); ++cur);
309 freeme = mystrings = g_strdup (cur);
310
311 lst = NULL;
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
312 do {
628d154 @djcb * minor / cosmetic changes
authored
313 gchar *str;
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
314 str = eat_esc_string (&mystrings, err);
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
315 if (str)
316 lst = g_slist_prepend (lst, str);
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
317 else {
318 g_free (freeme);
319 mu_str_free_list (lst);
320 return NULL;
321 }
322
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
323 } while (mystrings && *mystrings);
324
325 g_free (freeme);
326 return g_slist_reverse (lst);
327 }
328
329
330
331
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
332 void
333 mu_str_free_list (GSList *lst)
334 {
335 g_slist_foreach (lst, (GFunc)g_free, NULL);
628d154 @djcb * minor / cosmetic changes
authored
336 g_slist_free (lst);
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
337 }
338
b0fe977 @djcb * mu-str.c: much improved mu_str_normalize_subject (to skip Re:, Fwd:…
authored
339
340 /* this function is critical for sorting performance; therefore, no
341 * regexps, but just some good old c pointer magic */
35f7e2c @djcb * mu-str: add simplistic mu_str_subject_normalize (WIP)
authored
342 const gchar*
343 mu_str_subject_normalize (const gchar* str)
344 {
b0fe977 @djcb * mu-str.c: much improved mu_str_normalize_subject (to skip Re:, Fwd:…
authored
345 const char* cur;
346
35f7e2c @djcb * mu-str: add simplistic mu_str_subject_normalize (WIP)
authored
347 g_return_val_if_fail (str, NULL);
348
b0fe977 @djcb * mu-str.c: much improved mu_str_normalize_subject (to skip Re:, Fwd:…
authored
349 cur = str;
350 while (isspace(*cur)) ++cur; /* skip space */
351
352 /* starts with Re:? */
353 if (tolower(cur[0]) == 'r' && tolower(cur[1]) == 'e')
354 cur += 2;
355 /* starts with Fwd:? */
356 else if (tolower(cur[0]) == 'f' && tolower(cur[1]) == 'w' &&
357 tolower(cur[2]) == 'd')
358 cur += 3;
359 else /* nope, different string */
58fdfa9 @djcb * let mu_str_subject_normalize work with static strings as well
authored
360 return str;
b0fe977 @djcb * mu-str.c: much improved mu_str_normalize_subject (to skip Re:, Fwd:…
authored
361
362 /* we're now past either 'Re' or 'Fwd'. Maybe there's a [<num>] now?
363 * ie., the Re[3]: foo case */
364 if (cur[0] == '[') { /* handle the Re[3]: case */
365 if (isdigit(cur[1])) {
366 do { ++cur; } while (isdigit(*cur));
367 if ( cur[0] != ']') {
368 return str; /* nope: no ending ']' */
369 } else /* skip ']' and space */
370 do { ++cur; } while (isspace(*cur));
371 } else /* nope: no number after '[' */
372 return str;
58fdfa9 @djcb * let mu_str_subject_normalize work with static strings as well
authored
373 }
b0fe977 @djcb * mu-str.c: much improved mu_str_normalize_subject (to skip Re:, Fwd:…
authored
374
375 /* now, cur points past either 're' or 'fwd', possibly with
376 * [<num>]; check if it's really a prefix -- after re or fwd
377 * there should either a ':' and possibly some space */
378 if (cur[0] == ':') {
379 do { ++cur; } while (isspace(*cur));
380 /* note: there may still be another prefix, such as
381 * Re[2]: Fwd: foo */
382 return mu_str_subject_normalize (cur);
383 } else
384 return str; /* nope, it was not a prefix */
35f7e2c @djcb * mu-str: add simplistic mu_str_subject_normalize (WIP)
authored
385 }
386
387
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
388 struct _CheckPrefix {
389 const char *str;
390 gboolean match;
391 gboolean range_field;
392 };
393 typedef struct _CheckPrefix CheckPrefix;
394
395
396
397 static void
398 each_check_prefix (MuMsgFieldId mfid, CheckPrefix *cpfx)
399 {
400 const char *pfx;
401 char pfx_short[3] = { 'X', ':', '\0'};
402 char k;
403
404 if (!cpfx || cpfx->match)
405 return;
406
407 k = pfx_short[0] = mu_msg_field_shortcut (mfid);
408 if (k && g_str_has_prefix (cpfx->str, pfx_short)) {
409 cpfx->match = TRUE;
410 cpfx->range_field = mu_msg_field_is_range_field (mfid);
411 }
412
413 pfx = mu_msg_field_name (mfid);
414 if (pfx && g_str_has_prefix (cpfx->str, pfx) &&
415 cpfx->str[strlen(pfx)] == ':') {
416 cpfx->match = TRUE;
417 cpfx->range_field = mu_msg_field_is_range_field (mfid);
418 }
419 }
420
421
422 static void
9133750 @djcb * mu-str.c: fix bug in check_for_field
authored
423 check_for_field (const char *str, gboolean *is_field,
424 gboolean *is_range_field)
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
425 {
426 CheckPrefix pfx;
427
428 pfx.str = str;
9db1727 @djcb * mu-str.c: do some more massaging for xapian queries with brackets, …
authored
429
430 /* skip any non-alphanum starts in cpfx->str; this is to
431 * handle the case where we have e.g. "(maildir:/abc)"
432 */
9133750 @djcb * mu-str.c: fix bug in check_for_field
authored
433 while (pfx.str && *pfx.str && !isalnum(*pfx.str))
9db1727 @djcb * mu-str.c: do some more massaging for xapian queries with brackets, …
authored
434 ++pfx.str;
435
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
436 pfx.match = pfx.range_field = FALSE;
437
438 mu_msg_field_foreach ((MuMsgFieldForeachFunc)each_check_prefix,
439 &pfx);
440
441 *is_field = pfx.match;
442 *is_range_field = pfx.range_field;
443 }
2ef0799 @djcb * add mu_str_from_list, mu_str_to_list and mu_str_list_free + unit tests
authored
444
e478eee @djcb * reindentation, fix mu_str_ascii_xapian_escape_in_place for '..'
authored
445 /*
446 * Xapian treats various characters such as '@', '-', ':' and '.'
447 * specially; function below is an ugly hack to make it DWIM in most
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
448 * cases...
449 *
450 * function expects search terms (not complete queries)
451 * */
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
452 char*
423a1d7 @djcb * mu4e: use GStringChunk* for string normalization / escaping
authored
453 mu_str_xapian_escape_in_place_try (char *term, gboolean esc_space, GStringChunk *strchunk)
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
454 {
0be852b @djcb * improve support for non-latin languages (cyrillic etc.) (WIP)
authored
455 unsigned char *cur;
c6685a9 * mu-str.c: minor cleanup
djcb authored
456 const char escchar = '_';
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
457 gboolean is_field, is_range_field;
c3f63bb @djcb * mu-str.c, test-mu-query.c: ensure all unit tests pass
authored
458 unsigned colon;
628d154 @djcb * minor / cosmetic changes
authored
459
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
460 g_return_val_if_fail (term, NULL);
461
462 check_for_field (term, &is_field, &is_range_field);
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
463
0be852b @djcb * improve support for non-latin languages (cyrillic etc.) (WIP)
authored
464 for (colon = 0, cur = (unsigned char*)term; *cur; ++cur) {
9454d31 @djcb * mu-str.c: clean up a bit
authored
465
466 switch (*cur) {
0be852b @djcb * improve support for non-latin languages (cyrillic etc.) (WIP)
authored
467
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
468 case '.': /* escape '..' if it's not a range field*/
469 if (is_range_field && cur[1] == '.')
98ca74f * mu-msg-str.c: improve xapian-escaping, string-eating
djcb authored
470 cur += 1;
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
471 else
c6685a9 * mu-str.c: minor cleanup
djcb authored
472 *cur = escchar;
9454d31 @djcb * mu-str.c: clean up a bit
authored
473 break;
474 case ':':
b63bebf @djcb * mu-str.c: improve escaping of query terms
authored
475 /* if there's a registered xapian prefix
c3f63bb @djcb * mu-str.c, test-mu-query.c: ensure all unit tests pass
authored
476 * before the *first* ':', don't touch
477 * it. Otherwise replace ':' with '_'... ugh
478 * yuck ugly...
628d154 @djcb * minor / cosmetic changes
authored
479 */
c3f63bb @djcb * mu-str.c, test-mu-query.c: ensure all unit tests pass
authored
480 if (colon != 0 || !is_field)
98ca74f * mu-msg-str.c: improve xapian-escaping, string-eating
djcb authored
481 *cur = escchar;
c3f63bb @djcb * mu-str.c, test-mu-query.c: ensure all unit tests pass
authored
482 ++colon;
9454d31 @djcb * mu-str.c: clean up a bit
authored
483 break;
9db1727 @djcb * mu-str.c: do some more massaging for xapian queries with brackets, …
authored
484 case '(':
485 case ')':
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
486 case '\'':
487 case '*': /* wildcard */
488 break;
489 default:
0be852b @djcb * improve support for non-latin languages (cyrillic etc.) (WIP)
authored
490 /* escape all other special stuff */
e2a0fc3 @djcb * some small fixes for passing 'make cc10' and 'make line35'
authored
491 if (*cur < 0x80 && !isalnum (*cur))
7f0ec69 @djcb * mu-str etc.: improve escaping (for gmail folder names)
authored
492 *cur = escchar;
e478eee @djcb * reindentation, fix mu_str_ascii_xapian_escape_in_place for '..'
authored
493 }
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
494 }
628d154 @djcb * minor / cosmetic changes
authored
495
0be852b @djcb * improve support for non-latin languages (cyrillic etc.) (WIP)
authored
496 /* downcase try to remove accents etc. */
423a1d7 @djcb * mu4e: use GStringChunk* for string normalization / escaping
authored
497 return mu_str_normalize_in_place_try (term, TRUE, strchunk);
bb5b130 @djcb * mu-str.[ch]: add mu_str_ascii_xapian_escape_in_place, for escaping …
authored
498 }
499
39d71b8 @djcb * use mu_str_ascii_xapian_escape instead of local version; and non-in…
authored
500 char*
423a1d7 @djcb * mu4e: use GStringChunk* for string normalization / escaping
authored
501 mu_str_xapian_escape (const char *query, gboolean esc_space, GStringChunk *strchunk)
39d71b8 @djcb * use mu_str_ascii_xapian_escape instead of local version; and non-in…
authored
502 {
423a1d7 @djcb * mu4e: use GStringChunk* for string normalization / escaping
authored
503 char *mystr;
504
39d71b8 @djcb * use mu_str_ascii_xapian_escape instead of local version; and non-in…
authored
505 g_return_val_if_fail (query, NULL);
506
423a1d7 @djcb * mu4e: use GStringChunk* for string normalization / escaping
authored
507 if (strchunk)
508 mystr = g_string_chunk_insert (strchunk, query);
509 else
510 mystr = g_strdup (query);
511
512 return mu_str_xapian_escape_in_place_try (mystr, esc_space, strchunk);
39d71b8 @djcb * use mu_str_ascii_xapian_escape instead of local version; and non-in…
authored
513 }
d14727c @djcb * dont't require direntry->d_type; this should help the Solaris build.
authored
514
515
516 /* note: this function is *not* re-entrant, it returns a static buffer */
517 const char*
518 mu_str_fullpath_s (const char* path, const char* name)
519 {
520 static char buf[PATH_MAX + 1];
628d154 @djcb * minor / cosmetic changes
authored
521
d14727c @djcb * dont't require direntry->d_type; this should help the Solaris build.
authored
522 g_return_val_if_fail (path, NULL);
628d154 @djcb * minor / cosmetic changes
authored
523
d14727c @djcb * dont't require direntry->d_type; this should help the Solaris build.
authored
524 snprintf (buf, sizeof(buf), "%s%c%s", path, G_DIR_SEPARATOR,
525 name ? name : "");
628d154 @djcb * minor / cosmetic changes
authored
526
d14727c @djcb * dont't require direntry->d_type; this should help the Solaris build.
authored
527 return buf;
528 }
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
529
530
531 char*
424d012 @djcb * mu-str.h make mu_str_escape_c_literal optionionally quote "" its re…
authored
532 mu_str_escape_c_literal (const gchar* str, gboolean in_quotes)
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
533 {
534 const char* cur;
535 GString *tmp;
628d154 @djcb * minor / cosmetic changes
authored
536
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
537 g_return_val_if_fail (str, NULL);
628d154 @djcb * minor / cosmetic changes
authored
538
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
539 tmp = g_string_sized_new (2 * strlen(str));
424d012 @djcb * mu-str.h make mu_str_escape_c_literal optionionally quote "" its re…
authored
540
541 if (in_quotes)
542 g_string_append_c (tmp, '"');
628d154 @djcb * minor / cosmetic changes
authored
543
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
544 for (cur = str; *cur; ++cur)
545 switch (*cur) {
c712267 @djcb * fix json, sexp output
authored
546 case '\\': tmp = g_string_append (tmp, "\\\\"); break;
547 case '"': tmp = g_string_append (tmp, "\\\""); break;
548 default: tmp = g_string_append_c (tmp, *cur);
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
549 }
550
424d012 @djcb * mu-str.h make mu_str_escape_c_literal optionionally quote "" its re…
authored
551 if (in_quotes)
552 g_string_append_c (tmp, '"');
e95908c @djcb * add mu-server (previous commit) functions for parsing commands
authored
553
554 return g_string_free (tmp, FALSE);
f8af665 @djcb * mu-output.c, mu-str.[ch]: fix escaping for JSON, sexps (add mu_str_…
authored
555 }
92108c0 @djcb * cosmetic
authored
556
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
557
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
558
559 /* turn \0-terminated buf into ascii (which is a utf8 subset); convert
560 * any non-ascii into '.'
561 */
562 char*
563 mu_str_asciify_in_place (char *buf)
564 {
565 char *c;
15f7be5 * mu-str: add mu_str_utf8ify
djcb authored
566
567 g_return_val_if_fail (buf, NULL);
568
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
569 for (c = buf; c && *c; ++c)
570 if (!isascii(*c))
571 c[0] = '.';
572
573 return buf;
574 }
575
15f7be5 * mu-str: add mu_str_utf8ify
djcb authored
576 char*
577 mu_str_utf8ify (const char *buf)
578 {
579 char *utf8;
580
581 g_return_val_if_fail (buf, NULL);
582
583 utf8 = g_strdup (buf);
584
585 if (!g_utf8_validate (buf, -1, NULL))
586 mu_str_asciify_in_place (utf8);
587
588 return utf8;
589 }
590
591
592
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
593 gchar*
594 mu_str_convert_to_utf8 (const char* buffer, const char *charset)
595 {
596 GError *err;
597 gchar * utf8;
598
599 g_return_val_if_fail (buffer, NULL);
600 g_return_val_if_fail (charset, NULL );
628d154 @djcb * minor / cosmetic changes
authored
601
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
602 err = NULL;
603 utf8 = g_convert_with_fallback (buffer, -1, "UTF-8",
628d154 @djcb * minor / cosmetic changes
authored
604 charset, NULL,
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
605 NULL, NULL, &err);
3c59b97 @djcb * mu-str.c: make mu_str_convert_to_utf8 slightly more tolerant
authored
606 if (!utf8) /* maybe the charset lied; try 8859-15 */
607 utf8 = g_convert_with_fallback (buffer, -1, "UTF-8",
608 "ISO8859-15", NULL,
609 NULL, NULL, &err);
610 /* final attempt, maybe it was utf-8 already */
611 if (!utf8 && g_utf8_validate (buffer, -1, NULL))
612 utf8 = g_strdup (buffer);
613
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
614 if (!utf8) {
3c59b97 @djcb * mu-str.c: make mu_str_convert_to_utf8 slightly more tolerant
authored
615 g_warning ("%s: conversion failed from %s: %s",
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
616 __FUNCTION__, charset, err ? err->message : "");
3c59b97 @djcb * mu-str.c: make mu_str_convert_to_utf8 slightly more tolerant
authored
617 g_clear_error (&err);
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
618 }
628d154 @djcb * minor / cosmetic changes
authored
619
5695077 @djcb * mu-msg-file.c, mu-str.[ch]: ensure we only return valid UTF8 (becau…
authored
620 return utf8;
621 }
622
623
624
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
625 gchar*
626 mu_str_guess_last_name (const char *name)
627 {
628 const gchar *lastsp;
629
630 if (!name)
631 return g_strdup ("");
628d154 @djcb * minor / cosmetic changes
authored
632
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
633 lastsp = g_strrstr (name, " ");
628d154 @djcb * minor / cosmetic changes
authored
634
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
635 return g_strdup (lastsp ? lastsp + 1 : "");
636 }
637
638
639 gchar*
640 mu_str_guess_first_name (const char *name)
641 {
642 const gchar *lastsp;
643
644 if (!name)
645 return g_strdup ("");
628d154 @djcb * minor / cosmetic changes
authored
646
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
647 lastsp = g_strrstr (name, " ");
648
649 if (lastsp)
650 return g_strndup (name, lastsp - name);
651 else
652 return g_strdup (name);
653 }
654
655 static gchar*
656 cleanup_str (const char* str)
657 {
658 gchar *s;
659 const gchar *cur;
660 unsigned i;
661
662 if (mu_str_is_empty(str))
663 return g_strdup ("");
628d154 @djcb * minor / cosmetic changes
authored
664
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
665 s = g_new0 (char, strlen(str) + 1);
628d154 @djcb * minor / cosmetic changes
authored
666
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
667 for (cur = str, i = 0; *cur; ++cur) {
668 if (ispunct(*cur) || isspace(*cur))
669 continue;
670 else
671 s[i++] = *cur;
672 }
673
674 return s;
675 }
676
677
678 gchar*
679 mu_str_guess_nick (const char* name)
680 {
681 gchar *fname, *lname, *nick;
682 gchar initial[7];
628d154 @djcb * minor / cosmetic changes
authored
683
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
684 fname = mu_str_guess_first_name (name);
685 lname = mu_str_guess_last_name (name);
628d154 @djcb * minor / cosmetic changes
authored
686
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
687 /* if there's no last name, use first name as the nick */
688 if (mu_str_is_empty(fname) || mu_str_is_empty(lname)) {
689 g_free (lname);
690 nick = fname;
691 goto leave;
692 }
628d154 @djcb * minor / cosmetic changes
authored
693
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
694 memset (initial, 0, sizeof(initial));
695 /* couldn't we get an initial for the last name? */
696 if (g_unichar_to_utf8 (g_utf8_get_char (lname), initial) == 0) {
697 g_free (lname);
698 nick = fname;
699 goto leave;
700 }
701
702 nick = g_strdup_printf ("%s%s", fname, initial);
703 g_free (fname);
24f98ce @djcb * mu-str.c: fix leak in mu_str_guess_nick
authored
704 g_free (lname);
628d154 @djcb * minor / cosmetic changes
authored
705
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
706 leave:
707 {
708 gchar *tmp;
709 tmp = cleanup_str (nick);
710 g_free (nick);
711 nick = tmp;
712 }
628d154 @djcb * minor / cosmetic changes
authored
713
9a600e7 @djcb * mu-str: add mu_str_guess_first_name, mu_str_guess_last_name and
authored
714 return nick;
715 }
Something went wrong with that request. Please try again.