7 #include "procheader.h"
15 typedef struct _MatchParser MatchParser;
17 static MatchParser matchparser_tab[] = {
19 {MATCHING_ALL, "all"},
20 {MATCHING_UNREAD, "unread"},
21 {MATCHING_NOT_UNREAD, "~unread"},
22 {MATCHING_NEW, "new"},
23 {MATCHING_NOT_NEW, "~new"},
24 {MATCHING_MARKED, "marked"},
25 {MATCHING_NOT_MARKED, "~marked"},
26 {MATCHING_DELETED, "deleted"},
27 {MATCHING_NOT_DELETED, "~deleted"},
28 {MATCHING_REPLIED, "replied"},
29 {MATCHING_NOT_REPLIED, "~replied"},
30 {MATCHING_FORWARDED, "forwarded"},
31 {MATCHING_NOT_FORWARDED, "~forwarded"},
34 {MATCHING_SUBJECT, "subject"},
35 {MATCHING_NOT_SUBJECT, "~subject"},
36 {MATCHING_FROM, "from"},
37 {MATCHING_NOT_FROM, "~from"},
39 {MATCHING_NOT_TO, "~to"},
41 {MATCHING_NOT_CC, "~cc"},
42 {MATCHING_TO_OR_CC, "to_or_cc"},
43 {MATCHING_NOT_TO_AND_NOT_CC, "~to_or_cc"},
44 {MATCHING_AGE_GREATER, "age_greater"},
45 {MATCHING_AGE_LOWER, "age_lower"},
46 {MATCHING_NEWSGROUPS, "newsgroups"},
47 {MATCHING_NOT_NEWSGROUPS, "~newsgroups"},
48 {MATCHING_INREPLYTO, "inreplyto"},
49 {MATCHING_NOT_INREPLYTO, "~inreplyto"},
50 {MATCHING_REFERENCES, "references"},
51 {MATCHING_NOT_REFERENCES, "~references"},
52 {MATCHING_SCORE_GREATER, "score_greater"},
53 {MATCHING_SCORE_LOWER, "score_lower"},
55 /* content have to be read */
56 {MATCHING_HEADER, "header"},
57 {MATCHING_NOT_HEADER, "~header"},
58 {MATCHING_HEADERS_PART, "headers_part"},
59 {MATCHING_NOT_HEADERS_PART, "~headers_part"},
60 {MATCHING_MESSAGE, "message"},
61 {MATCHING_NOT_MESSAGE, "~message"},
62 {MATCHING_BODY_PART, "body_part"},
63 {MATCHING_NOT_BODY_PART, "~body_part"},
66 {MATCHING_MATCHCASE, "matchcase"},
67 {MATCHING_MATCH, "match"},
68 {MATCHING_REGEXPCASE, "regexpcase"},
69 {MATCHING_REGEXP, "regexp"},
72 {MATCHING_SCORE, "score"},
75 {MATCHING_ACTION_MOVE, "move"},
76 {MATCHING_ACTION_COPY, "copy"},
77 {MATCHING_ACTION_DELETE, "delete"},
78 {MATCHING_ACTION_MARK, "mark"},
79 {MATCHING_ACTION_UNMARK, "unmark"},
80 {MATCHING_ACTION_MARK_AS_READ, "mark_as_read"},
81 {MATCHING_ACTION_MARK_AS_UNREAD, "mark_as_unread"},
82 {MATCHING_ACTION_FORWARD, "forward"},
83 {MATCHING_ACTION_FORWARD_AS_ATTACHEMENT, "forward_as_attachement"},
86 gchar * get_matchparser_tab_str(gint id)
90 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
92 if (matchparser_tab[i].id == id)
93 return matchparser_tab[i].str;
103 header "x-mailing" match "toto"
104 subject match "regexp" & to regexp "regexp"
105 subject match "regexp" | to regexpcase "regexp" | age_sup 5
108 static gboolean matcher_is_blank(gchar ch);
110 /* ******************* parser *********************** */
112 static gboolean matcher_is_blank(gchar ch)
114 return (ch == ' ') || (ch == '\t');
117 /* parse for one condition */
119 MatcherProp * matcherprop_parse(gchar ** str)
127 gchar * header = NULL;
130 key = matcher_parse_keyword(&tmp);
137 case MATCHING_AGE_LOWER:
138 case MATCHING_AGE_GREATER:
139 case MATCHING_SCORE_LOWER:
140 case MATCHING_SCORE_GREATER:
141 value = matcher_parse_number(&tmp);
148 prop = matcherprop_new(key, NULL, 0, NULL, value);
153 case MATCHING_UNREAD:
154 case MATCHING_NOT_UNREAD:
156 case MATCHING_NOT_NEW:
157 case MATCHING_MARKED:
158 case MATCHING_NOT_MARKED:
159 case MATCHING_DELETED:
160 case MATCHING_NOT_DELETED:
161 case MATCHING_REPLIED:
162 case MATCHING_NOT_REPLIED:
163 case MATCHING_FORWARDED:
164 case MATCHING_NOT_FORWARDED:
165 prop = matcherprop_new(key, NULL, 0, NULL, 0);
170 case MATCHING_SUBJECT:
171 case MATCHING_NOT_SUBJECT:
173 case MATCHING_NOT_FROM:
175 case MATCHING_NOT_TO:
177 case MATCHING_NOT_CC:
178 case MATCHING_TO_OR_CC:
179 case MATCHING_NOT_TO_AND_NOT_CC:
180 case MATCHING_NEWSGROUPS:
181 case MATCHING_NOT_NEWSGROUPS:
182 case MATCHING_INREPLYTO:
183 case MATCHING_NOT_REFERENCES:
184 case MATCHING_REFERENCES:
185 case MATCHING_NOT_INREPLYTO:
186 case MATCHING_MESSAGE:
187 case MATCHING_NOT_MESSAGE:
188 case MATCHING_HEADERS_PART:
189 case MATCHING_NOT_HEADERS_PART:
190 case MATCHING_BODY_PART:
191 case MATCHING_NOT_BODY_PART:
192 case MATCHING_HEADER:
193 case MATCHING_NOT_HEADER:
194 if ((key == MATCHING_HEADER) || (key == MATCHING_NOT_HEADER)) {
195 header = matcher_parse_str(&tmp);
202 match = matcher_parse_keyword(&tmp);
211 case MATCHING_REGEXP:
212 case MATCHING_REGEXPCASE:
213 expr = matcher_parse_regexp(&tmp);
221 prop = matcherprop_new(key, header, match, expr, 0);
226 case MATCHING_MATCHCASE:
227 expr = matcher_parse_str(&tmp);
235 prop = matcherprop_new(key, header, match, expr, 0);
251 gint matcher_parse_keyword(gchar ** str)
259 dup = alloca(strlen(* str) + 1);
263 while (matcher_is_blank(*p))
268 while (!matcher_is_blank(*p) && (*p != '\0'))
272 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
274 if ((strlen(matchparser_tab[i].str) == p - start) &&
275 (strncasecmp(matchparser_tab[i].str, start,
290 return matchparser_tab[match].id;
293 gint matcher_parse_number(gchar ** str)
299 dup = alloca(strlen(* str) + 1);
303 while (matcher_is_blank(*p))
308 if (!isdigit(*p) && *p != '-' && *p != '+') {
312 if (*p == '-' || *p == '+')
323 gboolean matcher_parse_boolean_op(gchar ** str)
329 while (matcher_is_blank(*p))
333 *str += p - * str + 1;
336 else if (*p == '&') {
337 *str += p - * str + 1;
346 gchar * matcher_parse_regexp(gchar ** str)
352 dup = alloca(strlen(* str) + 1);
356 while (matcher_is_blank(*p))
374 return g_strdup(start);
377 gchar * matcher_parse_str(gchar ** str)
384 dup = alloca(strlen(* str) + 1);
388 while (matcher_is_blank(*p))
411 *str += dest - dup + 2;
412 return g_strdup(start);
415 /* **************** data structure allocation **************** */
418 MatcherProp * matcherprop_new(gint criteria, gchar * header,
419 gint matchtype, gchar * expr,
424 prop = g_new0(MatcherProp, 1);
425 prop->criteria = criteria;
427 prop->header = g_strdup(header);
431 prop->expr = g_strdup(expr);
434 prop->matchtype = matchtype;
442 void matcherprop_free(MatcherProp * prop)
445 if (prop->preg != NULL) {
453 /* ************** match ******************************/
456 /* match the given string */
458 static gboolean matcherprop_string_match(MatcherProp * prop, gchar * str)
466 switch(prop->matchtype) {
467 case MATCHING_REGEXPCASE:
468 case MATCHING_REGEXP:
469 if (!prop->preg && (prop->error == 0)) {
470 prop->preg = g_new0(regex_t, 1);
471 if (regcomp(prop->preg, prop->expr,
472 REG_NOSUB | REG_EXTENDED
473 | ((prop->matchtype == MATCHING_REGEXPCASE)
474 ? REG_ICASE : 0)) != 0) {
479 if (prop->preg == NULL)
482 if (regexec(prop->preg, str, 0, NULL, 0) == 0)
488 return (strstr(str, prop->expr) != NULL);
490 case MATCHING_MATCHCASE:
491 str2 = alloca(strlen(prop->expr) + 1);
492 strcpy(str2, prop->expr);
494 str1 = alloca(strlen(str) + 1);
497 return (strstr(str1, str2) != NULL);
504 /* match a message and his headers, hlist can be NULL if you don't
505 want to use headers */
507 gboolean matcherprop_match(MatcherProp * prop, MsgInfo * info)
511 switch(prop->criteria) {
514 case MATCHING_UNREAD:
515 return MSG_IS_UNREAD(info->flags);
516 case MATCHING_NOT_UNREAD:
517 return !MSG_IS_UNREAD(info->flags);
519 return MSG_IS_NEW(info->flags);
520 case MATCHING_NOT_NEW:
521 return !MSG_IS_NEW(info->flags);
522 case MATCHING_MARKED:
523 return MSG_IS_MARKED(info->flags);
524 case MATCHING_NOT_MARKED:
525 return !MSG_IS_MARKED(info->flags);
526 case MATCHING_DELETED:
527 return MSG_IS_DELETED(info->flags);
528 case MATCHING_NOT_DELETED:
529 return !MSG_IS_DELETED(info->flags);
530 case MATCHING_REPLIED:
531 return MSG_IS_REPLIED(info->flags);
532 case MATCHING_NOT_REPLIED:
533 return !MSG_IS_REPLIED(info->flags);
534 case MATCHING_FORWARDED:
535 return MSG_IS_FORWARDED(info->flags);
536 case MATCHING_NOT_FORWARDED:
537 return !MSG_IS_FORWARDED(info->flags);
538 case MATCHING_SUBJECT:
539 return matcherprop_string_match(prop, info->subject);
540 case MATCHING_NOT_SUBJECT:
541 return !matcherprop_string_match(prop, info->subject);
543 return matcherprop_string_match(prop, info->from);
544 case MATCHING_NOT_FROM:
545 return !matcherprop_string_match(prop, info->from);
547 return matcherprop_string_match(prop, info->to);
548 case MATCHING_NOT_TO:
549 return !matcherprop_string_match(prop, info->to);
551 return matcherprop_string_match(prop, info->cc);
552 case MATCHING_NOT_CC:
553 return !matcherprop_string_match(prop, info->cc);
554 case MATCHING_TO_OR_CC:
555 return matcherprop_string_match(prop, info->to)
556 || matcherprop_string_match(prop, info->cc);
557 case MATCHING_NOT_TO_AND_NOT_CC:
558 return !(matcherprop_string_match(prop, info->to)
559 || matcherprop_string_match(prop, info->cc));
560 case MATCHING_AGE_GREATER:
562 return ((t - info->date_t) / (60 * 60 * 24)) >= prop->value;
563 case MATCHING_AGE_LOWER:
565 return ((t - info->date_t) / (60 * 60 * 24)) <= prop->value;
566 case MATCHING_SCORE_GREATER:
567 return info->score >= prop->value;
568 case MATCHING_SCORE_LOWER:
569 return info->score <= prop->value;
570 case MATCHING_NEWSGROUPS:
571 return matcherprop_string_match(prop, info->newsgroups);
572 case MATCHING_NOT_NEWSGROUPS:
573 return !matcherprop_string_match(prop, info->newsgroups);
574 case MATCHING_INREPLYTO:
575 return matcherprop_string_match(prop, info->inreplyto);
576 case MATCHING_NOT_INREPLYTO:
577 return !matcherprop_string_match(prop, info->inreplyto);
578 case MATCHING_REFERENCES:
579 return matcherprop_string_match(prop, info->references);
580 case MATCHING_NOT_REFERENCES:
581 return !matcherprop_string_match(prop, info->references);
582 case MATCHING_HEADER:
588 /* ********************* MatcherList *************************** */
591 /* parse for a list of conditions */
593 MatcherList * matcherlist_parse(gchar ** str)
596 MatcherProp * matcher;
597 GSList * matchers_list = NULL;
598 gboolean bool_and = TRUE;
601 gboolean main_bool_and = TRUE;
606 matcher = matcherprop_parse(&tmp);
612 matchers_list = g_slist_append(matchers_list, matcher);
615 bool_and = matcher_parse_boolean_op(&tmp);
621 main_bool_and = bool_and;
622 matcher = matcherprop_parse(&tmp);
625 g_slist_append(matchers_list, matcher);
628 for(l = matchers_list ; l != NULL ;
630 matcherprop_free((MatcherProp *)
632 g_slist_free(matchers_list);
639 cond = matcherlist_new(matchers_list, main_bool_and);
646 MatcherList * matcherlist_new(GSList * matchers, gboolean bool_and)
650 cond = g_new0(MatcherList, 1);
652 cond->matchers = matchers;
653 cond->bool_and = bool_and;
658 void matcherlist_free(MatcherList * cond)
662 for(l = cond->matchers ; l != NULL ; l = g_slist_next(l)) {
663 matcherprop_free((MatcherProp *) l->data);
672 static void matcherlist_skip_headers(FILE *fp)
676 while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
681 matcherprop_match_one_header
682 returns TRUE if buf matchs the MatchersProp criteria
685 static gboolean matcherprop_match_one_header(MatcherProp * matcher,
691 switch(matcher->criteria) {
692 case MATCHING_HEADER:
693 case MATCHING_NOT_HEADER:
694 header = procheader_parse_header(buf);
697 if (procheader_headername_equal(header->name,
699 if (matcher->criteria == MATCHING_HEADER)
700 result = matcherprop_string_match(matcher, header->body);
702 result = !matcherprop_string_match(matcher, header->body);
703 procheader_header_free(header);
707 case MATCHING_HEADERS_PART:
708 case MATCHING_MESSAGE:
709 return matcherprop_string_match(matcher, buf);
710 case MATCHING_NOT_MESSAGE:
711 case MATCHING_NOT_HEADERS_PART:
712 return !matcherprop_string_match(matcher, buf);
718 matcherprop_criteria_header
719 returns TRUE if the headers must be matched
722 static gboolean matcherprop_criteria_headers(MatcherProp * matcher)
724 switch(matcher->criteria) {
725 case MATCHING_HEADER:
726 case MATCHING_NOT_HEADER:
727 case MATCHING_HEADERS_PART:
728 case MATCHING_NOT_HEADERS_PART:
729 case MATCHING_MESSAGE:
730 case MATCHING_NOT_MESSAGE:
738 matcherlist_match_one_header
739 returns TRUE if buf matchs the MatchersList criteria
742 static gboolean matcherlist_match_one_header(MatcherList * matchers,
748 if (matchers->bool_and)
753 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
754 MatcherProp * matcher = (MatcherProp *) l->data;
756 if (matcherprop_criteria_headers(matcher)) {
757 if (matcherprop_match_one_header(matcher, buf)) {
758 if (!matchers->bool_and)
762 if (matchers->bool_and)
772 matcherlist_match_headers
773 returns TRUE if one of the headers matchs the MatcherList criteria
776 static gboolean matcherlist_match_headers(MatcherList * matchers, FILE * fp)
780 while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1)
781 if (matcherlist_match_one_header(matchers, buf))
788 matcherprop_criteria_body
789 returns TRUE if the body must be matched
792 static gboolean matcherprop_criteria_body(MatcherProp * matcher)
794 switch(matcher->criteria) {
795 case MATCHING_BODY_PART:
796 case MATCHING_NOT_BODY_PART:
797 case MATCHING_MESSAGE:
798 case MATCHING_NOT_MESSAGE:
806 matcherprop_match_line
807 returns TRUE if the string matchs the MatcherProp criteria
810 static gboolean matcherprop_match_line(MatcherProp * matcher, gchar * line)
812 switch(matcher->criteria) {
813 case MATCHING_BODY_PART:
814 case MATCHING_MESSAGE:
815 return matcherprop_string_match(matcher, line);
816 case MATCHING_NOT_BODY_PART:
817 case MATCHING_NOT_MESSAGE:
818 return !matcherprop_string_match(matcher, line);
824 matcherlist_match_line
825 returns TRUE if the string matchs the MatcherList criteria
828 static gboolean matcherlist_match_line(MatcherList * matchers, gchar * line)
833 if (matchers->bool_and)
838 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
839 MatcherProp * matcher = (MatcherProp *) l->data;
841 if (matcherprop_criteria_body(matcher)) {
842 if (matcherprop_match_line(matcher, line)) {
843 if (!matchers->bool_and)
847 if (matchers->bool_and)
856 matcherlist_match_body
857 returns TRUE if one line of the body matchs the MatcherList criteria
860 static gboolean matcherlist_match_body(MatcherList * matchers, FILE * fp)
864 while (fgets(buf, sizeof(buf), fp) != NULL)
865 if (matcherlist_match_line(matchers, buf))
871 gboolean matcherlist_match_file(MatcherList * matchers, MsgInfo * info,
874 gboolean read_headers;
880 /* file need to be read ? */
882 read_headers = FALSE;
884 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
885 MatcherProp * matcher = (MatcherProp *) l->data;
887 if (matcherprop_criteria_headers(matcher))
889 if (matcherprop_criteria_body(matcher))
893 if (!read_headers && !read_body)
896 file = procmsg_get_message_file(info);
900 if ((fp = fopen(file, "r")) == NULL) {
901 FILE_OP_ERROR(file, "fopen");
906 /* read the headers */
909 if (matcherlist_match_headers(matchers, fp)) {
910 if (!matchers->bool_and)
914 if (matchers->bool_and)
919 matcherlist_skip_headers(fp);
924 if (matcherlist_match_body(matchers, fp)) {
925 if (!matchers->bool_and)
929 if (matchers->bool_and)
941 /* test a list of condition */
943 gboolean matcherlist_match(MatcherList * matchers, MsgInfo * info)
948 if (matchers->bool_and)
953 /* test the condition on the file */
955 if (matcherlist_match_file(matchers, info, result)) {
956 if (!matchers->bool_and)
960 if (matchers->bool_and)
964 /* test the cached elements */
966 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
967 MatcherProp * matcher = (MatcherProp *) l->data;
969 switch(matcher->criteria) {
971 case MATCHING_UNREAD:
972 case MATCHING_NOT_UNREAD:
974 case MATCHING_NOT_NEW:
975 case MATCHING_MARKED:
976 case MATCHING_NOT_MARKED:
977 case MATCHING_DELETED:
978 case MATCHING_NOT_DELETED:
979 case MATCHING_REPLIED:
980 case MATCHING_NOT_REPLIED:
981 case MATCHING_FORWARDED:
982 case MATCHING_NOT_FORWARDED:
983 case MATCHING_SUBJECT:
984 case MATCHING_NOT_SUBJECT:
986 case MATCHING_NOT_FROM:
988 case MATCHING_NOT_TO:
990 case MATCHING_NOT_CC:
991 case MATCHING_TO_OR_CC:
992 case MATCHING_NOT_TO_AND_NOT_CC:
993 case MATCHING_AGE_GREATER:
994 case MATCHING_AGE_LOWER:
995 case MATCHING_NEWSGROUPS:
996 case MATCHING_NOT_NEWSGROUPS:
997 case MATCHING_INREPLYTO:
998 case MATCHING_NOT_INREPLYTO:
999 case MATCHING_REFERENCES:
1000 case MATCHING_NOT_REFERENCES:
1001 case MATCHING_SCORE_GREATER:
1002 case MATCHING_SCORE_LOWER:
1003 if (matcherprop_match(matcher, info)) {
1004 if (!matchers->bool_and) {
1010 if (matchers->bool_and) {
1022 static void matcherprop_print(MatcherProp * matcher)
1026 if (matcher == NULL) {
1027 printf("no matcher\n");
1031 switch (matcher->matchtype) {
1032 case MATCHING_MATCH:
1035 case MATCHING_REGEXP:
1038 case MATCHING_MATCHCASE:
1039 printf("matchcase\n");
1041 case MATCHING_REGEXPCASE:
1042 printf("regexpcase\n");
1046 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
1048 if (matchparser_tab[i].id == matcher->criteria)
1049 printf("%s\n", matchparser_tab[i].str);
1053 printf("expr : %s\n", matcher->expr);
1055 printf("age: %i\n", matcher->value;
1057 printf("compiled : %s\n", matcher->preg != NULL ? "yes" : "no");
1058 printf("error: %i\n", matcher->error);
1062 gchar * matcherprop_to_string(MatcherProp * matcher)
1064 gchar * matcher_str = NULL;
1065 gchar * criteria_str;
1066 gchar * matchtype_str;
1073 criteria_str = NULL;
1074 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
1076 if (matchparser_tab[i].id == matcher->criteria)
1077 criteria_str = matchparser_tab[i].str;
1079 if (criteria_str == NULL)
1082 switch(matcher->criteria) {
1083 case MATCHING_AGE_GREATER:
1084 case MATCHING_AGE_LOWER:
1085 case MATCHING_SCORE_GREATER:
1086 case MATCHING_SCORE_LOWER:
1087 return g_strdup_printf("%s %i", criteria_str, matcher->value);
1090 case MATCHING_UNREAD:
1091 case MATCHING_NOT_UNREAD:
1093 case MATCHING_NOT_NEW:
1094 case MATCHING_MARKED:
1095 case MATCHING_NOT_MARKED:
1096 case MATCHING_DELETED:
1097 case MATCHING_NOT_DELETED:
1098 case MATCHING_REPLIED:
1099 case MATCHING_NOT_REPLIED:
1100 case MATCHING_FORWARDED:
1101 case MATCHING_NOT_FORWARDED:
1102 return g_strdup(criteria_str);
1105 matchtype_str = NULL;
1106 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
1108 if (matchparser_tab[i].id == matcher->matchtype)
1109 matchtype_str = matchparser_tab[i].str;
1112 if (matchtype_str == NULL)
1115 switch (matcher->matchtype) {
1116 case MATCHING_MATCH:
1117 case MATCHING_MATCHCASE:
1119 for(p = matcher->expr; *p != 0 ; p++)
1120 if (*p == '\"') count ++;
1122 expr_str = g_new(char, strlen(matcher->expr) + count + 1);
1124 for(p = matcher->expr, out = expr_str ; *p != 0 ; p++, out++) {
1134 if (matcher->header)
1136 g_strdup_printf("%s \"%s\" %s \"%s\"",
1137 criteria_str, matcher->header,
1138 matchtype_str, expr_str);
1141 g_strdup_printf("%s %s \"%s\"", criteria_str,
1142 matchtype_str, expr_str);
1148 case MATCHING_REGEXP:
1149 case MATCHING_REGEXPCASE:
1151 if (matcher->header)
1153 g_strdup_printf("%s \"%s\" %s /%s/",
1154 criteria_str, matcher->header,
1155 matchtype_str, matcher->expr);
1158 g_strdup_printf("%s %s /%s/", criteria_str,
1159 matchtype_str, matcher->expr);
1167 gchar * matcherlist_to_string(MatcherList * matchers)
1175 count = g_slist_length(matchers->matchers);
1176 vstr = g_new(gchar *, count + 1);
1178 for (l = matchers->matchers, cur_str = vstr ; l != NULL ;
1179 l = g_slist_next(l), cur_str ++) {
1180 *cur_str = matcherprop_to_string((MatcherProp *) l->data);
1181 if (*cur_str == NULL)
1186 if (matchers->bool_and)
1187 result = g_strjoinv(" & ", vstr);
1189 result = g_strjoinv(" | ", vstr);
1191 for(cur_str = vstr ; *cur_str != NULL ; cur_str ++)