2009-09-28 [colin] 3.7.2cvs41
[claws.git] / src / matcher.c
index a3fb9be44ec3ed6e9ae9754b89960796a4beda9e..5626e3d9f296bdb9ec252f2b2bebb6a44a2e89f1 100644 (file)
@@ -85,6 +85,10 @@ static const MatchParser matchparser_tab[] = {
        {MATCHCRITERIA_NOT_WATCH_THREAD, "~watch_thread"},
        {MATCHCRITERIA_SPAM, "spam"},
        {MATCHCRITERIA_NOT_SPAM, "~spam"},
+       {MATCHCRITERIA_HAS_ATTACHMENT, "has_attachment"},
+       {MATCHCRITERIA_HAS_NO_ATTACHMENT, "~has_attachment"},
+       {MATCHCRITERIA_SIGNED, "signed"},
+       {MATCHCRITERIA_NOT_SIGNED, "~signed"},
 
        /* msginfo headers */
        {MATCHCRITERIA_SUBJECT, "subject"},
@@ -257,11 +261,7 @@ MatcherProp *matcherprop_new(gint criteria, const gchar *header,
        prop->criteria = criteria;
        prop->header = header != NULL ? g_strdup(header) : NULL;
 
-       if (matchtype == MATCHTYPE_MATCHCASE ||
-           matchtype == MATCHTYPE_REGEXPCASE)
-               prop->expr = expr != NULL ? g_utf8_casefold(expr, -1) : NULL;
-       else
-               prop->expr = expr != NULL ? g_strdup(expr) : NULL;
+       prop->expr = expr != NULL ? g_strdup(expr) : NULL;
 
        prop->matchtype = matchtype;
        prop->preg = NULL;
@@ -355,13 +355,13 @@ static gboolean match_with_addresses_in_addressbook
        gboolean found = FALSE;
        gchar *path = NULL;
 
-       g_return_val_if_fail(address_list != NULL, FALSE);
+       cm_return_val_if_fail(address_list != NULL, FALSE);
 
        debug_print("match_with_addresses_in_addressbook(%d, %s)\n",
                                g_slist_length(address_list), folderpath?folderpath:"(null)");
 
        if (folderpath == NULL ||
-               strcasecmp(folderpath, _("Any")) == 0 ||
+               strcasecmp(folderpath, "Any") == 0 ||
                *folderpath == '\0')
                path = NULL;
        else
@@ -398,7 +398,7 @@ static gboolean match_with_addresses_in_addressbook
                                && prefs_common.filtering_debug_level >= FILTERING_DEBUG_LEVEL_HIGH
                                && !found) {
                        log_print(LOG_DEBUG_FILTERING,
-                                       "address [ %s ] doesn't match\n",
+                                       "address [ %s ] does NOT match\n",
                                        (gchar *)walk->data);
                }
                g_free(walk->data);
@@ -447,6 +447,7 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
                                         const gchar *debug_context)
 {
        gchar *str1;
+       gchar *down_expr;
        gboolean ret = FALSE;
        gboolean should_free = FALSE;
        if (str == NULL)
@@ -455,19 +456,22 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
        if (prop->matchtype == MATCHTYPE_REGEXPCASE ||
            prop->matchtype == MATCHTYPE_MATCHCASE) {
                str1 = g_utf8_casefold(str, -1);
+               down_expr = g_utf8_casefold(prop->expr, -1);
                should_free = TRUE;
        } else {
                str1 = (gchar *)str;
+               down_expr = (gchar *)prop->expr;
                should_free = FALSE;
        }
 
        switch (prop->matchtype) {
        case MATCHTYPE_REGEXPCASE:
        case MATCHTYPE_REGEXP:
+#ifndef G_OS_WIN32
                if (!prop->preg && (prop->error == 0)) {
                        prop->preg = g_new0(regex_t, 1);
                        /* if regexp then don't use the escaped string */
-                       if (regcomp(prop->preg, prop->expr,
+                       if (regcomp(prop->preg, down_expr,
                                    REG_NOSUB | REG_EXTENDED
                                    | ((prop->matchtype == MATCHTYPE_REGEXPCASE)
                                    ? REG_ICASE : 0)) != 0) {
@@ -476,8 +480,10 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
                                prop->preg = NULL;
                        }
                }
-               if (prop->preg == NULL)
-                       return FALSE;
+               if (prop->preg == NULL) {
+                       ret = FALSE;
+                       goto free_strs;
+               }
                
                if (regexec(prop->preg, str1, 0, NULL, 0) == 0)
                        ret = TRUE;
@@ -497,17 +503,17 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
                                                prop->matchtype == MATCHTYPE_REGEXP ? _("Case sensitive"):_("Case insensitive"));
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "%s value [ %s ] doesn't matches regular expression [ %s ] (%s)\n",
+                                               "%s value [ %s ] does NOT match regular expression [ %s ] (%s)\n",
                                                debug_context, stripped, prop->expr,
                                                prop->matchtype == MATCHTYPE_REGEXP ? _("Case sensitive"):_("Case insensitive"));
                        }
                        g_free(stripped);
                }
                break;
-                       
+#endif                 
        case MATCHTYPE_MATCHCASE:
        case MATCHTYPE_MATCH:
-               ret = (strstr(str1, prop->expr) != NULL);
+               ret = (strstr(str1, down_expr) != NULL);
 
                /* debug output */
                if (debug_filtering_session
@@ -522,7 +528,7 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
                                                prop->matchtype == MATCHTYPE_MATCH ? _("Case sensitive"):_("Case insensitive"));
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "%s value [ %s ] doesn't contains [ %s ] (%s)\n",
+                                               "%s value [ %s ] does NOT contain [ %s ] (%s)\n",
                                                debug_context, stripped, prop->expr,
                                                prop->matchtype == MATCHTYPE_MATCH ? _("Case sensitive"):_("Case insensitive"));
                        }
@@ -534,8 +540,10 @@ static gboolean matcherprop_string_match(MatcherProp *prop, const gchar *str,
                break;
        }
        
+free_strs:
        if (should_free) {
                g_free(str1);
+               g_free(down_expr);
        }
        return ret;
 }
@@ -681,13 +689,21 @@ static gboolean matcherprop_match_test(const MatcherProp *prop,
 #endif
 
        file = procmsg_get_message_file(info);
-       if (file == NULL)
+       if (file == NULL) {
+#ifdef USE_PTHREAD
+               g_free(td);
+#endif
                return FALSE;
+       }
        g_free(file);           
 
        cmd = matching_build_command(prop->expr, info);
-       if (cmd == NULL)
+       if (cmd == NULL) {
+#ifdef USE_PTHREAD
+               g_free(td);
+#endif 
                return FALSE;
+}
 
 #ifdef USE_PTHREAD
        /* debug output */
@@ -794,6 +810,14 @@ gboolean matcherprop_match(MatcherProp *prop,
                return MSG_IS_SPAM(info->flags);
        case MATCHCRITERIA_NOT_SPAM:
                return !MSG_IS_SPAM(info->flags);
+       case MATCHCRITERIA_HAS_ATTACHMENT:
+               return MSG_IS_WITH_ATTACHMENT(info->flags);
+       case MATCHCRITERIA_HAS_NO_ATTACHMENT:
+               return !MSG_IS_WITH_ATTACHMENT(info->flags);
+       case MATCHCRITERIA_SIGNED:
+               return MSG_IS_SIGNED(info->flags);
+       case MATCHCRITERIA_NOT_SIGNED:
+               return !MSG_IS_SIGNED(info->flags);
        case MATCHCRITERIA_COLORLABEL:
        {
                gint color = MSG_GET_COLORLABEL_VALUE(info->flags);
@@ -808,7 +832,7 @@ gboolean matcherprop_match(MatcherProp *prop,
                                                color, prop->value);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message color value [ %d ] doesn't matches color value [ %d ]\n",
+                                               "message color value [ %d ] does NOT match color value [ %d ]\n",
                                                color, prop->value);
                        }
                }
@@ -828,7 +852,7 @@ gboolean matcherprop_match(MatcherProp *prop,
                                                color, prop->value);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message color value [ %d ] doesn't matches color value [ %d ]\n",
+                                               "message color value [ %d ] does NOT match color value [ %d ]\n",
                                                color, prop->value);
                        }
                }
@@ -1030,76 +1054,76 @@ gboolean matcherprop_match(MatcherProp *prop,
        }
        case MATCHCRITERIA_SIZE_GREATER:
        {
-               /* FIXME: info->size is an off_t */
-               gboolean ret = (info->size > (off_t) prop->value);
+               /* FIXME: info->size is a goffset */
+               gboolean ret = (info->size > (goffset) prop->value);
 
                /* debug output */
                if (debug_filtering_session
                                && prefs_common.filtering_debug_level >= FILTERING_DEBUG_LEVEL_HIGH) {
                        if (ret) {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is greater than [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is greater than [ %d ]\n",
+                                               prop->value);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is not greater than [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is not greater than [ %d ]\n",
+                                               prop->value);
                        }
                }
                return ret;
        }
        case MATCHCRITERIA_SIZE_SMALLER:
        {
-               /* FIXME: info->size is an off_t */
-               gboolean ret = (info->size < (off_t) prop->value);
+               /* FIXME: info->size is a goffset */
+               gboolean ret = (info->size < (goffset) prop->value);
 
                /* debug output */
                if (debug_filtering_session
                                && prefs_common.filtering_debug_level >= FILTERING_DEBUG_LEVEL_HIGH) {
                        if (ret) {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is smaller than [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is smaller than [ %d ]\n",
+                                               prop->value);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is not smaller than [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is not smaller than [ %d ]\n",
+                                               prop->value);
                        }
                }
                return ret;
        }
        case MATCHCRITERIA_SIZE_EQUAL:
        {
-               /* FIXME: info->size is an off_t */
-               gboolean ret = (info->size == (off_t) prop->value);
+               /* FIXME: info->size is a goffset */
+               gboolean ret = (info->size == (goffset) prop->value);
 
                /* debug output */
                if (debug_filtering_session
                                && prefs_common.filtering_debug_level >= FILTERING_DEBUG_LEVEL_HIGH) {
                        if (ret) {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is equal to [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is equal to [ %d ]\n",
+                                               prop->value);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message size [ %ld ] is not equal to [ %d ]\n",
-                                               info->size, prop->value);
+                                               "message size is not equal to [ %d ]\n",
+                                               prop->value);
                        }
                }
                return ret;
        }
        case MATCHCRITERIA_PARTIAL:
        {
-               /* FIXME: info->size is an off_t */
-               gboolean ret = (info->total_size != 0 && info->size != (off_t)info->total_size);
+               /* FIXME: info->size is a goffset */
+               gboolean ret = (info->total_size != 0 && info->size != (goffset)info->total_size);
 
                /* debug output */
                if (debug_filtering_session
                                && prefs_common.filtering_debug_level >= FILTERING_DEBUG_LEVEL_HIGH) {
                        if (ret) {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message is partially downloaded, size [ %ld ] is less than total size [ %d ])\n",
-                                               info->size, info->total_size);
+                                               "message is partially downloaded, size is less than total size [ %d ])\n",
+                                               info->total_size);
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
                                                "message is not partially downloaded\n");
@@ -1109,8 +1133,8 @@ gboolean matcherprop_match(MatcherProp *prop,
        }
        case MATCHCRITERIA_NOT_PARTIAL:
        {
-               /* FIXME: info->size is an off_t */
-               gboolean ret = (info->total_size == 0 || info->size == (off_t)info->total_size);
+               /* FIXME: info->size is a goffset */
+               gboolean ret = (info->total_size == 0 || info->size == (goffset)info->total_size);
 
                /* debug output */
                if (debug_filtering_session
@@ -1120,8 +1144,8 @@ gboolean matcherprop_match(MatcherProp *prop,
                                                "message is not partially downloaded\n");
                        } else {
                                log_print(LOG_DEBUG_FILTERING,
-                                               "message is partially downloaded, size [ %ld ] is less than total size [ %d ])\n",
-                                               info->size, info->total_size);
+                                               "message is partially downloaded, size is less than total size [ %d ])\n",
+                                               info->total_size);
                        }
                }
                return ret;
@@ -1202,10 +1226,11 @@ void matcherlist_free(MatcherList *cond)
 {
        GSList *l;
 
-       g_return_if_fail(cond);
+       cm_return_if_fail(cond);
        for (l = cond->matchers ; l != NULL ; l = g_slist_next(l)) {
                matcherprop_free((MatcherProp *) l->data);
        }
+       g_slist_free(cond->matchers);
        g_free(cond);
 }
 
@@ -1271,9 +1296,9 @@ static gboolean matcherprop_match_one_header(MatcherProp *matcher,
                        gboolean found = FALSE;
 
                        /* how many address headers are me trying to mach? */
-                       if (strcasecmp(matcher->header, _("Any")) == 0)
+                       if (strcasecmp(matcher->header, "Any") == 0)
                                match = MATCH_ANY;
-                       else if (strcasecmp(matcher->header, Q_("Filtering Matcher Menu|All")) == 0)
+                       else if (strcasecmp(matcher->header, "All") == 0)
                                        match = MATCH_ALL;
 
                        if (match == MATCH_ONE) {
@@ -1333,16 +1358,9 @@ static gboolean matcherprop_criteria_headers(const MatcherProp *matcher)
        case MATCHCRITERIA_NOT_HEADER:
        case MATCHCRITERIA_HEADERS_PART:
        case MATCHCRITERIA_NOT_HEADERS_PART:
-               return TRUE;
        case MATCHCRITERIA_FOUND_IN_ADDRESSBOOK:
        case MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK:
-               if (!strcasecmp(matcher->header, Q_("Filtering Matcher Menu|All")) ||
-                   !strcasecmp(matcher->header, _("Any")) ||
-                   !strcasecmp(matcher->header, "Sender") ||
-                   !strcasecmp(matcher->header, "Reply-To"))
-                       return TRUE;
-               else
-                       return FALSE;
+               return TRUE;
        default:
                return FALSE;
        }
@@ -1411,9 +1429,9 @@ static gboolean matcherlist_match_headers(MatcherList *matchers, FILE *fp)
                                         procheader_headername_equal(header->name, "Reply-To") ||
                                         procheader_headername_equal(header->name, "Sender"))) {
 
-                                       if (strcasecmp(matcher->header, _("Any")) == 0)
+                                       if (strcasecmp(matcher->header, "Any") == 0)
                                                match = MATCH_ANY;
-                                       else if (strcasecmp(matcher->header, Q_("Filtering Matcher Menu|All")) == 0)
+                                       else if (strcasecmp(matcher->header, "All") == 0)
                                                match = MATCH_ALL;
                                        else
                                                match = MATCH_ONE;
@@ -1688,6 +1706,10 @@ gboolean matcherlist_match(MatcherList *matchers, MsgInfo *info)
                case MATCHCRITERIA_NOT_LOCKED:
                case MATCHCRITERIA_SPAM:
                case MATCHCRITERIA_NOT_SPAM:
+               case MATCHCRITERIA_HAS_ATTACHMENT:
+               case MATCHCRITERIA_HAS_NO_ATTACHMENT:
+               case MATCHCRITERIA_SIGNED:
+               case MATCHCRITERIA_NOT_SIGNED:
                case MATCHCRITERIA_COLORLABEL:
                case MATCHCRITERIA_NOT_COLORLABEL:
                case MATCHCRITERIA_IGNORE_THREAD:
@@ -1883,6 +1905,10 @@ gchar *matcherprop_to_string(MatcherProp *matcher)
        case MATCHCRITERIA_NOT_LOCKED:
        case MATCHCRITERIA_SPAM:
        case MATCHCRITERIA_NOT_SPAM:
+       case MATCHCRITERIA_HAS_ATTACHMENT:
+       case MATCHCRITERIA_HAS_NO_ATTACHMENT:
+       case MATCHCRITERIA_SIGNED:
+       case MATCHCRITERIA_NOT_SIGNED:
        case MATCHCRITERIA_PARTIAL:
        case MATCHCRITERIA_NOT_PARTIAL:
        case MATCHCRITERIA_IGNORE_THREAD:
@@ -2005,9 +2031,9 @@ static void add_str_default(gchar ** dest,
 
 /* matching_build_command() - preferably cmd should be unescaped */
 /*!
- *\brief       Build the command line to execute
+ *\brief       Build the command-line to execute
  *
- *\param       cmd String with command line specifiers
+ *\param       cmd String with command-line specifiers
  *\param       info Message info to use for command
  *
  *\return      gchar * Newly allocated string
@@ -2374,8 +2400,17 @@ static void matcher_add_rulenames(const gchar *rcpath)
        FILE *dst = g_fopen(newpath, "wb");
        gchar buf[BUFFSIZE];
        int r;
+       if (src == NULL) {
+               perror("fopen");
+               if (dst)
+                       fclose(dst);
+               g_free(newpath);
+               return;
+       }
        if (dst == NULL) {
                perror("fopen");
+               if (src)
+                       fclose(src);
                g_free(newpath);
                return;
        }