2005-11-30 [colin] 1.9.100cvs46
[claws.git] / src / matcher.c
index 5cb0620fa6965d4a1161e76d6ff25138b49bba25..3c71b93703a0ace145e740dfc4bd2bfa9d1ef8c3 100644 (file)
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include <glib.h>
@@ -660,41 +660,6 @@ static gboolean matcherprop_criteria_message(MatcherProp *matcher)
        }
 }
 
-/*!
- *\brief       Check if a list of conditions match a header
- *
- *\param       matchers One set of conditions
- *\param       buf Name of header
- *
- *\return      gboolean TRUE if matching should stop
- */
-static gboolean matcherlist_match_one_header(MatcherList *matchers,
-                                            gchar *buf)
-{
-       GSList *l;
-
-       for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
-               MatcherProp *matcher = (MatcherProp *) l->data;
-               
-               /* see if a single condition matches */
-               if (matcherprop_criteria_headers(matcher) ||
-                   matcherprop_criteria_message(matcher)) {
-                       if (matcherprop_match_one_header(matcher, buf)) {
-                               matcher->result = TRUE;
-                       }
-               }
-
-               if (matcherprop_criteria_headers(matcher)) {
-                       if (matcher->result) {
-                               if (!matchers->bool_and)
-                                       return TRUE;
-                       }
-               }
-       }
-
-       return FALSE;
-}
-
 /*!
  *\brief       Check if a list of conditions matches one header in
  *             a message file.
@@ -707,12 +672,44 @@ static gboolean matcherlist_match_one_header(MatcherList *matchers,
  */
 static gboolean matcherlist_match_headers(MatcherList *matchers, FILE *fp)
 {
+       GSList *l;
        gchar buf[BUFFSIZE];
 
-       while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1)
-               if (matcherlist_match_one_header(matchers, buf))
-                       return TRUE;
-
+       while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
+               for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
+                       MatcherProp *matcher = (MatcherProp *) l->data;
+
+                       if (matcher->done)
+                               continue;
+
+                       /* if the criteria is ~headers_part or ~message, ZERO lines
+                        * must NOT match for the rule to match. */
+                       if (matcher->criteria == MATCHCRITERIA_NOT_HEADERS_PART ||
+                           matcher->criteria == MATCHCRITERIA_NOT_MESSAGE) {
+                               if (matcherprop_match_one_header(matcher, buf)) {
+                                       matcher->result = TRUE;
+                               } else {
+                                       matcher->result = FALSE;
+                                       matcher->done = TRUE;
+                               }
+                       /* else, just one line matching is enough for the rule to match
+                        */
+                       } else if (matcherprop_criteria_headers(matcher) ||
+                                  matcherprop_criteria_message(matcher)){
+                               if (matcherprop_match_one_header(matcher, buf)) {
+                                       matcher->result = TRUE;
+                                       matcher->done = TRUE;
+                               }
+                       }
+                       
+                       /* if the rule matched and the matchers are OR, no need to
+                        * check the others */
+                       if (matcher->result && matcher->done) {
+                               if (!matchers->bool_and)
+                                       return TRUE;
+                       }
+               }
+       }
        return FALSE;
 }
 
@@ -756,36 +753,6 @@ static gboolean matcherprop_match_line(MatcherProp *matcher, const gchar *line)
        return FALSE;
 }
 
-/*!
- *\brief       Check if a list of conditions matches a (line) string
- *
- *\param       matchers List of matchers
- *\param       line String to match
- *
- *\return      gboolean TRUE if string matches list of criteria
- */
-static gboolean matcherlist_match_line(MatcherList *matchers, const gchar *line)
-{
-       GSList *l;
-
-       for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
-               MatcherProp *matcher = (MatcherProp *) l->data;
-
-               if (matcherprop_criteria_body(matcher) ||
-                   matcherprop_criteria_message(matcher)) {
-                       if (matcherprop_match_line(matcher, line)) {
-                               matcher->result = TRUE;
-                       }
-               }
-                       
-               if (matcher->result) {
-                       if (!matchers->bool_and)
-                               return TRUE;
-               }
-       }
-       return FALSE;
-}
-
 /*!
  *\brief       Check if a line in a message file's body matches
  *             the criteria
@@ -797,12 +764,43 @@ static gboolean matcherlist_match_line(MatcherList *matchers, const gchar *line)
  */
 static gboolean matcherlist_match_body(MatcherList *matchers, FILE *fp)
 {
+       GSList *l;
        gchar buf[BUFFSIZE];
+       
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               for (l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
+                       MatcherProp *matcher = (MatcherProp *) l->data;
+                       
+                       if (matcher->done) 
+                               continue;
+
+                       /* if the criteria is ~body_part or ~message, ZERO lines
+                        * must NOT match for the rule to match. */
+                       if (matcher->criteria == MATCHCRITERIA_NOT_BODY_PART ||
+                           matcher->criteria == MATCHCRITERIA_NOT_MESSAGE) {
+                               if (matcherprop_match_line(matcher, buf)) {
+                                       matcher->result = TRUE;
+                               } else {
+                                       matcher->result = FALSE;
+                                       matcher->done = TRUE;
+                               }
+                       /* else, just one line has to match */
+                       } else if (matcherprop_criteria_body(matcher) ||
+                                  matcherprop_criteria_message(matcher)) {
+                               if (matcherprop_match_line(matcher, buf)) {
+                                       matcher->result = TRUE;
+                                       matcher->done = TRUE;
+                               }
+                       }
 
-       while (fgets(buf, sizeof(buf), fp) != NULL)
-               if (matcherlist_match_line(matchers, buf))
-                       return TRUE;
-
+                       /* if the matchers are OR'ed and the rule matched,
+                        * no need to check the others. */
+                       if (matcher->result && matcher->done) {
+                               if (!matchers->bool_and)
+                                       return TRUE;
+                       }
+               }
+       }
        return FALSE;
 }
 
@@ -840,6 +838,7 @@ gboolean matcherlist_match_file(MatcherList *matchers, MsgInfo *info,
                        read_body = TRUE;
                }
                matcher->result = FALSE;
+               matcher->done = FALSE;
        }
 
        if (!read_headers && !read_body)
@@ -860,8 +859,7 @@ gboolean matcherlist_match_file(MatcherList *matchers, MsgInfo *info,
        if (read_headers) {
                if (matcherlist_match_headers(matchers, fp))
                        read_body = FALSE;
-       }
-       else {
+       } else {
                matcherlist_skip_headers(fp);
        }
 
@@ -1384,6 +1382,7 @@ static void prefs_filtering_write(FILE *fp, GSList *prefs_filtering)
 
        for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
                gchar *filtering_str;
+               gchar *tmp_name = NULL;
                FilteringProp *prop;
 
                if (NULL == (prop = (FilteringProp *) cur->data))
@@ -1391,8 +1390,32 @@ static void prefs_filtering_write(FILE *fp, GSList *prefs_filtering)
                
                if (NULL == (filtering_str = filteringprop_to_string(prop)))
                        continue;
-               
-               if (fputs(filtering_str, fp) == EOF ||
+                               
+               if (fputs("rulename \"", fp) == EOF) {
+                       FILE_OP_ERROR("filtering config", "fputs || fputc");
+                       g_free(filtering_str);
+                       return;
+               }
+               tmp_name = prop->name;
+               while (tmp_name && *tmp_name != '\0') {
+                       if (*tmp_name != '"') {
+                               if (fputc(*tmp_name, fp) == EOF) {
+                                       FILE_OP_ERROR("filtering config", "fputc");
+                                       g_free(filtering_str);
+                                       return;
+                               }
+                       } else if (*tmp_name == '"') {
+                               if (fputc('\\', fp) == EOF ||
+                                   fputc('"', fp) == EOF) {
+                                       FILE_OP_ERROR("filtering config", "fputc");
+                                       g_free(filtering_str);
+                                       return;
+                               }
+                       }
+                       tmp_name ++;
+               }
+               if(fputs("\" ", fp) == EOF ||
+                   fputs(filtering_str, fp) == EOF ||
                    fputc('\n', fp) == EOF) {
                        FILE_OP_ERROR("filtering config", "fputs || fputc");
                        g_free(filtering_str);
@@ -1502,18 +1525,56 @@ void prefs_matcher_write_config(void)
 
 /* ******************************************************************* */
 
+void matcher_add_rulenames(const gchar *rcpath)
+{
+       gchar *newpath = g_strconcat(rcpath, ".new", NULL);
+       FILE *src = g_fopen(rcpath, "rb");
+       FILE *dst = g_fopen(newpath, "wb");
+       gchar buf[BUFFSIZE];
+
+       if (dst == NULL) {
+               perror("fopen");
+               g_free(newpath);
+               return;
+       }
+
+       while (fgets (buf, sizeof(buf), src) != NULL) {
+               if (strlen(buf) > 2 && buf[0] != '['
+               && strncmp(buf, "rulename \"", 10)) {
+                       fwrite("rulename \"\" ",
+                               strlen("rulename \"\" "), 1, dst);
+               }
+               fwrite(buf, strlen(buf), 1, dst);
+       }
+       fclose(dst);
+       fclose(src);
+       move_file(newpath, rcpath, TRUE);
+       g_free(newpath);
+}
+
 /*!
  *\brief       Read matcher configuration
  */
 void prefs_matcher_read_config(void)
 {
        gchar *rcpath;
+       gchar *rc_old_format;
        FILE *f;
 
        create_matchparser_hashtab();
        prefs_filtering_clear();
 
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MATCHER_RC, NULL);
+       rc_old_format = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MATCHER_RC, 
+                               ".pre_names", NULL);
+       
+       if (!is_file_exist(rc_old_format) && is_file_exist(rcpath)) {
+               /* backup file with no rules names, in case 
+                * anything goes wrong */
+               copy_file(rcpath, rc_old_format, FALSE);
+               /* now hack the file in order to have it to the new format */
+               matcher_add_rulenames(rcpath);
+       }
        f = g_fopen(rcpath, "rb");
        g_free(rcpath);