Updated Hungarian translation
[evolution.git] / mail / e-mail-free-form-exp.c
blobfb7864b89b23747d5ba8bc6b9b81cb74927cfe3f
1 /*
2 * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com)
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <glib.h>
23 #include <glib/gi18n-lib.h>
25 #include <string.h>
27 #include <camel/camel.h>
28 #include <e-util/e-util.h>
29 #include <libedataserver/libedataserver.h>
31 #include "e-mail-free-form-exp.h"
33 static gchar *
34 mail_ffe_build_header_sexp (const gchar *word,
35 const gchar *options,
36 const gchar * const *header_names)
38 GString *sexp = NULL, *encoded_word;
39 const gchar *compare_type = NULL;
40 gint ii;
42 g_return_val_if_fail (header_names != NULL, NULL);
43 g_return_val_if_fail (header_names[0] != NULL, NULL);
45 if (!word)
46 return NULL;
48 if (options) {
49 struct _KnownOptions {
50 const gchar *compare_type;
51 const gchar *alt_name;
52 } known_options[] = {
53 { "contains", "c" },
54 { "has-words", "w" },
55 { "matches", "m" },
56 { "starts-with", "sw" },
57 { "ends-with", "ew" },
58 { "soundex", "se" },
59 { "regex", "r" },
60 { "full-regex", "fr" }
63 for (ii = 0; ii < G_N_ELEMENTS (known_options); ii++) {
64 if (g_ascii_strcasecmp (options, known_options[ii].compare_type) == 0 ||
65 (known_options[ii].alt_name && g_ascii_strcasecmp (options, known_options[ii].alt_name) == 0)) {
66 compare_type = known_options[ii].compare_type;
67 break;
72 if (!compare_type)
73 compare_type = "contains";
75 encoded_word = g_string_new ("");
76 camel_sexp_encode_string (encoded_word, word);
78 if (!header_names[1]) {
79 if (!sexp)
80 sexp = g_string_new ("");
81 } else if (!sexp) {
82 sexp = g_string_new ("(or ");
83 } else {
84 g_string_append (sexp, "(or ");
87 for (ii = 0; header_names[ii]; ii++) {
88 g_string_append_printf (sexp, "(match-all (header-%s \"%s\" %s))", compare_type, header_names[ii], encoded_word->str);
91 if (header_names[1])
92 g_string_append (sexp, ")");
94 g_string_free (encoded_word, TRUE);
96 return sexp ? g_string_free (sexp, FALSE) : NULL;
99 static gchar *
100 mail_ffe_recips (const gchar *word,
101 const gchar *options,
102 const gchar *hint)
104 const gchar *header_names[] = { "To", "Cc", "Subject", NULL };
106 /* Include Subject only in the default expression. */
107 if (!hint)
108 header_names[2] = NULL;
110 return mail_ffe_build_header_sexp (word, options, header_names);
113 static gchar *
114 mail_ffe_from (const gchar *word,
115 const gchar *options,
116 const gchar *hint)
118 const gchar *header_names[] = { "From", NULL };
120 return mail_ffe_build_header_sexp (word, options, header_names);
123 static gchar *
124 mail_ffe_to (const gchar *word,
125 const gchar *options,
126 const gchar *hint)
128 const gchar *header_names[] = { "To", NULL };
130 return mail_ffe_build_header_sexp (word, options, header_names);
133 static gchar *
134 mail_ffe_cc (const gchar *word,
135 const gchar *options,
136 const gchar *hint)
138 const gchar *header_names[] = { "Cc", NULL };
140 return mail_ffe_build_header_sexp (word, options, header_names);
143 static gchar *
144 mail_ffe_subject (const gchar *word,
145 const gchar *options,
146 const gchar *hint)
148 const gchar *header_names[] = { "Subject", NULL };
150 return mail_ffe_build_header_sexp (word, options, header_names);
153 static gchar *
154 mail_ffe_header (const gchar *word,
155 const gchar *options,
156 const gchar *hint)
158 const gchar *header_names[] = { NULL, NULL };
159 const gchar *equal;
160 gchar *header_name, *sexp;
162 equal = word ? strchr (word, '=') : NULL;
163 if (!equal)
164 return NULL;
166 header_name = g_strndup (word, equal - word);
167 header_names[0] = header_name;
169 sexp = mail_ffe_build_header_sexp (equal + 1, options, header_names);
171 g_free (header_name);
173 return sexp;
176 static gchar *
177 mail_ffe_exists (const gchar *word,
178 const gchar *options,
179 const gchar *hint)
181 GString *encoded_word;
182 gchar *sexp;
184 if (!word)
185 return NULL;
187 encoded_word = g_string_new ("");
188 camel_sexp_encode_string (encoded_word, word);
190 sexp = g_strdup_printf ("(match-all (header-exists %s))", encoded_word->str);
192 g_string_free (encoded_word, TRUE);
194 return sexp;
197 static gchar *
198 mail_ffe_tag (const gchar *word,
199 const gchar *options,
200 const gchar *hint)
202 GString *encoded_word;
203 gchar *sexp;
205 if (!word)
206 return NULL;
208 encoded_word = g_string_new ("");
209 camel_sexp_encode_string (encoded_word, word);
211 sexp = g_strdup_printf ("(match-all (not (= (user-tag %s) \"\")))", encoded_word->str);
213 g_string_free (encoded_word, TRUE);
215 return sexp;
218 static gchar *
219 mail_ffe_flag (const gchar *word,
220 const gchar *options,
221 const gchar *hint)
223 const gchar *system_flags[] = {
224 /* Translators: This is a name of a flag, the same as all strings in the 'ffe' context.
225 The translated value should not contain spaces. */
226 NC_("ffe", "Answered"),
227 NC_("ffe", "Deleted"),
228 NC_("ffe", "Draft"),
229 NC_("ffe", "Flagged"),
230 NC_("ffe", "Seen"),
231 NC_("ffe", "Attachment")
233 GString *encoded_word;
234 gchar *sexp = NULL;
235 gint ii;
237 if (!word)
238 return NULL;
240 encoded_word = g_string_new ("");
241 camel_sexp_encode_string (encoded_word, word);
243 for (ii = 0; ii < G_N_ELEMENTS (system_flags); ii++) {
244 if (g_ascii_strcasecmp (word, system_flags[ii]) == 0 ||
245 g_ascii_strcasecmp (word, g_dpgettext2 (NULL, "ffe", system_flags[ii])) == 0) {
246 sexp = g_strdup_printf ("(match-all (system-flag \"%s\"))", system_flags[ii]);
247 break;
251 if (!sexp)
252 sexp = g_strdup_printf ("(match-all (not (= (user-tag %s) \"\")))", encoded_word->str);
254 g_string_free (encoded_word, TRUE);
256 return sexp;
259 static gchar *
260 mail_ffe_label (const gchar *word,
261 const gchar *options,
262 const gchar *hint)
264 GString *encoded_word;
265 gchar *sexp;
267 if (!word)
268 return NULL;
270 encoded_word = g_string_new ("");
271 camel_sexp_encode_string (encoded_word, word);
273 sexp = g_strdup_printf ("(match-all (or ((= (user-tag \"label\") %s) (user-flag (+ \"$Label\" %s)) (user-flag %s)))",
274 encoded_word->str, encoded_word->str, encoded_word->str);
276 g_string_free (encoded_word, TRUE);
278 return sexp;
281 static gchar *
282 mail_ffe_size (const gchar *word,
283 const gchar *options,
284 const gchar *hint)
286 GString *encoded_word;
287 gchar *sexp;
288 const gchar *cmp = "=";
290 if (!word)
291 return NULL;
293 if (options) {
294 if (g_ascii_strcasecmp (options, "<") == 0 ||
295 g_ascii_strcasecmp (options, ">") == 0)
296 cmp = options;
299 encoded_word = g_string_new ("");
300 camel_sexp_encode_string (encoded_word, word);
302 sexp = g_strdup_printf ("(match-all (%s (get-size) (cast-int %s)))", cmp, encoded_word->str);
304 g_string_free (encoded_word, TRUE);
306 return sexp;
309 static gchar *
310 mail_ffe_score (const gchar *word,
311 const gchar *options,
312 const gchar *hint)
314 GString *encoded_word;
315 gchar *sexp;
316 const gchar *cmp = "=";
318 if (!word)
319 return NULL;
321 if (options) {
322 if (g_ascii_strcasecmp (options, "<") == 0 ||
323 g_ascii_strcasecmp (options, ">") == 0)
324 cmp = options;
327 encoded_word = g_string_new ("");
328 camel_sexp_encode_string (encoded_word, word);
330 sexp = g_strdup_printf ("(match-all (%s (cast-int (user-tag \"score\")) (cast-int %s)))", cmp, encoded_word->str);
332 g_string_free (encoded_word, TRUE);
334 return sexp;
337 static gchar *
338 mail_ffe_body (const gchar *word,
339 const gchar *options,
340 const gchar *hint)
342 GString *encoded_word;
343 gchar *sexp;
344 const gchar *cmp = "contains";
346 if (!word)
347 return NULL;
349 if (options) {
350 if (g_ascii_strcasecmp (options, "regex") == 0 ||
351 g_ascii_strcasecmp (options, "re") == 0 ||
352 g_ascii_strcasecmp (options, "r") == 0)
353 cmp = "regex";
356 encoded_word = g_string_new ("");
357 camel_sexp_encode_string (encoded_word, word);
359 sexp = g_strdup_printf ("(match-all (body-%s %s))", cmp, encoded_word->str);
361 g_string_free (encoded_word, TRUE);
363 return sexp;
366 static gboolean
367 mail_ffe_decode_date_time (const gchar *word,
368 GTimeVal *tv)
370 struct tm tm;
372 g_return_val_if_fail (word != NULL, FALSE);
373 g_return_val_if_fail (tv != NULL, FALSE);
375 /* YYYY-MM-DD */
376 if (strlen (word) == 10 && word[4] == '-' && word[7] == '-') {
377 gint yy, mm, dd;
379 yy = atoi (word);
380 mm = atoi (word + 5);
381 dd = atoi (word + 8);
383 if (g_date_valid_dmy (dd, mm, yy)) {
384 GDate *date;
386 date = g_date_new_dmy (dd, mm, yy);
387 g_date_to_struct_tm (date, &tm);
388 g_date_free (date);
390 tv->tv_sec = mktime (&tm);
391 tv->tv_usec = 0;
393 return TRUE;
397 if (g_time_val_from_iso8601 (word, tv))
398 return TRUE;
400 if (e_time_parse_date_and_time (word, &tm) == E_TIME_PARSE_OK ||
401 e_time_parse_date (word, &tm) == E_TIME_PARSE_OK) {
402 tv->tv_sec = mktime (&tm);
403 tv->tv_usec = 0;
405 return TRUE;
408 return FALSE;
411 static gchar *
412 mail_ffe_process_date (const gchar *get_date_fnc,
413 const gchar *word,
414 const gchar *options)
416 gint64 rel_days;
417 gchar *endptr = NULL;
418 const gchar *op = ">";
419 GTimeVal tv;
421 g_return_val_if_fail (get_date_fnc != NULL, NULL);
423 if (options) {
424 if (g_ascii_strcasecmp (options, "<") == 0) {
425 op = "<";
426 } else if (g_ascii_strcasecmp (options, "=") == 0) {
427 op = "=";
428 } else if (g_ascii_strcasecmp (options, ">") == 0) {
429 op = ">";
433 rel_days = g_ascii_strtoll (word, &endptr, 10);
434 if (rel_days != 0 && endptr && !*endptr) {
435 return g_strdup_printf ("(match-all (%s (%s) (%s (get-current-date) %" G_GINT64_FORMAT ")))", op, get_date_fnc,
436 rel_days < 0 ? "+" : "-", (rel_days < 0 ? -1 : 1) * rel_days * 24 * 60 * 60);
439 if (!mail_ffe_decode_date_time (word, &tv))
440 return g_strdup_printf ("(match-all (%s (%s) (get-current-date)))", op, get_date_fnc);
442 return g_strdup_printf ("(match-all (%s (%s) %" G_GINT64_FORMAT "))", op, get_date_fnc, (gint64) tv.tv_sec);
445 static gchar *
446 mail_ffe_sent (const gchar *word,
447 const gchar *options,
448 const gchar *hint)
450 if (!word)
451 return NULL;
453 return mail_ffe_process_date ("get-sent-date", word, options);
456 static gchar *
457 mail_ffe_received (const gchar *word,
458 const gchar *options,
459 const gchar *hint)
461 if (!word)
462 return NULL;
464 return mail_ffe_process_date ("get-received-date", word, options);
467 static gchar *
468 mail_ffe_attachment (const gchar *word,
469 const gchar *options,
470 const gchar *hint)
472 gboolean is_neg = FALSE;
474 if (!word)
475 return NULL;
477 if (g_ascii_strcasecmp (word, "no") == 0 ||
478 g_ascii_strcasecmp (word, "false") == 0 ||
479 g_ascii_strcasecmp (word, C_("ffe", "no")) == 0 ||
480 g_ascii_strcasecmp (word, C_("ffe", "false")) == 0 ||
481 g_ascii_strcasecmp (word, "0") == 0) {
482 is_neg = TRUE;
485 return g_strdup_printf ("(match-all %s(system-flag \"Attachment\")%s)", is_neg ? "(not " : "", is_neg ? ")" : "");
488 static const EFreeFormExpSymbol mail_ffe_symbols[] = {
489 { "", "1", mail_ffe_recips },
490 { "from:f", NULL, mail_ffe_from },
491 { "to:t", NULL, mail_ffe_to },
492 { "cc:c:", NULL, mail_ffe_cc },
493 { "recips:r", NULL, mail_ffe_recips },
494 { "subject:s", NULL, mail_ffe_subject },
495 { "header:h", NULL, mail_ffe_header },
496 { "exists:e", NULL, mail_ffe_exists },
497 { "tag", NULL, mail_ffe_tag },
498 { "flag", NULL, mail_ffe_flag },
499 { "label:l", NULL, mail_ffe_label },
500 { "size:sz", NULL, mail_ffe_size },
501 { "score:sc", NULL, mail_ffe_score },
502 { "body:b", NULL, mail_ffe_body },
503 { "sent", NULL, mail_ffe_sent },
504 { "received:rcv", NULL, mail_ffe_received },
505 { "attachment:a", NULL, mail_ffe_attachment },
506 { NULL, NULL, NULL}
509 static gchar *
510 get_filter_input_value (EFilterPart *part,
511 const gchar *name)
513 EFilterElement *elem;
514 EFilterInput *input;
515 GString *value;
516 GList *link;
518 g_return_val_if_fail (part != NULL, NULL);
519 g_return_val_if_fail (name != NULL, NULL);
521 elem = e_filter_part_find_element (part, name);
522 g_return_val_if_fail (elem != NULL, NULL);
523 g_return_val_if_fail (E_IS_FILTER_INPUT (elem), NULL);
525 input = E_FILTER_INPUT (elem);
526 value = g_string_new ("");
528 for (link = input->values; link; link = g_list_next (link)) {
529 const gchar *val = link->data;
531 if (val && *val) {
532 if (value->len > 0)
533 g_string_append_c (value, ' ');
534 g_string_append (value, val);
538 return g_string_free (value, FALSE);
541 void
542 e_mail_free_form_exp_to_sexp (EFilterElement *element,
543 GString *out,
544 EFilterPart *part)
546 gchar *ffe, *sexp;
548 ffe = get_filter_input_value (part, "ffe");
549 g_return_if_fail (ffe != NULL);
551 sexp = e_free_form_exp_to_sexp (ffe, mail_ffe_symbols);
552 if (sexp)
553 g_string_append (out, sexp);
555 g_free (sexp);
556 g_free (ffe);