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
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/>.
23 #include <glib/gi18n-lib.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"
34 mail_ffe_build_header_sexp (const gchar
*word
,
36 const gchar
* const *header_names
)
38 GString
*sexp
= NULL
, *encoded_word
;
39 const gchar
*compare_type
= NULL
;
42 g_return_val_if_fail (header_names
!= NULL
, NULL
);
43 g_return_val_if_fail (header_names
[0] != NULL
, NULL
);
49 struct _KnownOptions
{
50 const gchar
*compare_type
;
51 const gchar
*alt_name
;
56 { "starts-with", "sw" },
57 { "ends-with", "ew" },
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
;
73 compare_type
= "contains";
75 encoded_word
= g_string_new ("");
76 camel_sexp_encode_string (encoded_word
, word
);
78 if (!header_names
[1]) {
80 sexp
= g_string_new ("");
82 sexp
= g_string_new ("(or ");
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
);
92 g_string_append (sexp
, ")");
94 g_string_free (encoded_word
, TRUE
);
96 return sexp
? g_string_free (sexp
, FALSE
) : NULL
;
100 mail_ffe_recips (const gchar
*word
,
101 const gchar
*options
,
104 const gchar
*header_names
[] = { "To", "Cc", "Subject", NULL
};
106 /* Include Subject only in the default expression. */
108 header_names
[2] = NULL
;
110 return mail_ffe_build_header_sexp (word
, options
, header_names
);
114 mail_ffe_from (const gchar
*word
,
115 const gchar
*options
,
118 const gchar
*header_names
[] = { "From", NULL
};
120 return mail_ffe_build_header_sexp (word
, options
, header_names
);
124 mail_ffe_to (const gchar
*word
,
125 const gchar
*options
,
128 const gchar
*header_names
[] = { "To", NULL
};
130 return mail_ffe_build_header_sexp (word
, options
, header_names
);
134 mail_ffe_cc (const gchar
*word
,
135 const gchar
*options
,
138 const gchar
*header_names
[] = { "Cc", NULL
};
140 return mail_ffe_build_header_sexp (word
, options
, header_names
);
144 mail_ffe_subject (const gchar
*word
,
145 const gchar
*options
,
148 const gchar
*header_names
[] = { "Subject", NULL
};
150 return mail_ffe_build_header_sexp (word
, options
, header_names
);
154 mail_ffe_header (const gchar
*word
,
155 const gchar
*options
,
158 const gchar
*header_names
[] = { NULL
, NULL
};
160 gchar
*header_name
, *sexp
;
162 equal
= word
? strchr (word
, '=') : 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
);
177 mail_ffe_exists (const gchar
*word
,
178 const gchar
*options
,
181 GString
*encoded_word
;
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
);
198 mail_ffe_tag (const gchar
*word
,
199 const gchar
*options
,
202 GString
*encoded_word
;
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
);
219 mail_ffe_flag (const gchar
*word
,
220 const gchar
*options
,
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"),
229 NC_("ffe", "Flagged"),
231 NC_("ffe", "Attachment")
233 GString
*encoded_word
;
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
]);
252 sexp
= g_strdup_printf ("(match-all (not (= (user-tag %s) \"\")))", encoded_word
->str
);
254 g_string_free (encoded_word
, TRUE
);
260 mail_ffe_label (const gchar
*word
,
261 const gchar
*options
,
264 GString
*encoded_word
;
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
);
282 mail_ffe_size (const gchar
*word
,
283 const gchar
*options
,
286 GString
*encoded_word
;
288 const gchar
*cmp
= "=";
294 if (g_ascii_strcasecmp (options
, "<") == 0 ||
295 g_ascii_strcasecmp (options
, ">") == 0)
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
);
310 mail_ffe_score (const gchar
*word
,
311 const gchar
*options
,
314 GString
*encoded_word
;
316 const gchar
*cmp
= "=";
322 if (g_ascii_strcasecmp (options
, "<") == 0 ||
323 g_ascii_strcasecmp (options
, ">") == 0)
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
);
338 mail_ffe_body (const gchar
*word
,
339 const gchar
*options
,
342 GString
*encoded_word
;
344 const gchar
*cmp
= "contains";
350 if (g_ascii_strcasecmp (options
, "regex") == 0 ||
351 g_ascii_strcasecmp (options
, "re") == 0 ||
352 g_ascii_strcasecmp (options
, "r") == 0)
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
);
367 mail_ffe_decode_date_time (const gchar
*word
,
372 g_return_val_if_fail (word
!= NULL
, FALSE
);
373 g_return_val_if_fail (tv
!= NULL
, FALSE
);
376 if (strlen (word
) == 10 && word
[4] == '-' && word
[7] == '-') {
380 mm
= atoi (word
+ 5);
381 dd
= atoi (word
+ 8);
383 if (g_date_valid_dmy (dd
, mm
, yy
)) {
386 date
= g_date_new_dmy (dd
, mm
, yy
);
387 g_date_to_struct_tm (date
, &tm
);
390 tv
->tv_sec
= mktime (&tm
);
397 if (g_time_val_from_iso8601 (word
, tv
))
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
);
412 mail_ffe_process_date (const gchar
*get_date_fnc
,
414 const gchar
*options
)
417 gchar
*endptr
= NULL
;
418 const gchar
*op
= ">";
421 g_return_val_if_fail (get_date_fnc
!= NULL
, NULL
);
424 if (g_ascii_strcasecmp (options
, "<") == 0) {
426 } else if (g_ascii_strcasecmp (options
, "=") == 0) {
428 } else if (g_ascii_strcasecmp (options
, ">") == 0) {
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
);
446 mail_ffe_sent (const gchar
*word
,
447 const gchar
*options
,
453 return mail_ffe_process_date ("get-sent-date", word
, options
);
457 mail_ffe_received (const gchar
*word
,
458 const gchar
*options
,
464 return mail_ffe_process_date ("get-received-date", word
, options
);
468 mail_ffe_attachment (const gchar
*word
,
469 const gchar
*options
,
472 gboolean is_neg
= FALSE
;
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) {
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
},
510 get_filter_input_value (EFilterPart
*part
,
513 EFilterElement
*elem
;
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
;
533 g_string_append_c (value
, ' ');
534 g_string_append (value
, val
);
538 return g_string_free (value
, FALSE
);
542 e_mail_free_form_exp_to_sexp (EFilterElement
*element
,
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
);
553 g_string_append (out
, sexp
);