From 623a8d83ce693c5250d85e81c674f899234ce70d Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Wed, 9 Jan 2002 21:34:07 +0000 Subject: If the mbox file is a symlink, follow the symlink and get the One True 2002-01-09 Jeffrey Stedfast * providers/local/camel-mbox-folder.c (camel_mbox_folder_new): If the mbox file is a symlink, follow the symlink and get the One True Path so that we can rewrite the mbox later without worrying about clobbering the symlink. 2002-01-08 Jeffrey Stedfast * camel-filter-search.c (TODO): There are a few sexp callbacks that could be modified to use fms->info rather than using a message object (like date and possibly mlist stuff) but *only* if the date exists on the CamelMessageInfo object (since it may be blank except for message flags). (camel_filter_search_get_message): New internal convenience function to make sure that the FilterMessageSearch has loaded the message (and to load the message if this isn't the case). (check_header): Call camel_filter_search_get_message(). (header_exists): Same. (header_regex): Here too. (header_full_regex): And here. (body_contains): Again here. (body_regex): Here too. (get_sent_date): Here also. (get_received_date): Same. (get_source): Here if we need to. (camel_filter_search_match): Now takes a callback function/data pair for on-demand message loading so that we don't necessarily have to load the message if the defined filter rules don't require it. * camel-filter-driver.c (camel_filter_driver_filter_folder): Don't bother fetching the message here, let camel_filter_driver_filter_message() worry about this. (get_message_cb): New utility callback to fetch a message. (camel_filter_driver_filter_message): Only fetch the message if we absolutely need it to get a CamelMessageInfo. Instead of passing a message object to camel_filter_search_match(), pass get_message_cb and some user_data so that the matching code can fetch the message on demand. svn path=/trunk/; revision=15276 --- camel/ChangeLog | 41 +++++++++++ camel/camel-filter-driver.c | 107 ++++++++++++++++++++++------- camel/camel-filter-search.c | 85 ++++++++++++++++++----- camel/camel-filter-search.h | 7 +- camel/providers/local/camel-local-folder.c | 12 +++- 5 files changed, 206 insertions(+), 46 deletions(-) (limited to 'camel') diff --git a/camel/ChangeLog b/camel/ChangeLog index d887f6a785..c4c35dbc78 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,44 @@ +2002-01-09 Jeffrey Stedfast + + * providers/local/camel-mbox-folder.c (camel_mbox_folder_new): If + the mbox file is a symlink, follow the symlink and get the One + True Path so that we can rewrite the mbox later without worrying + about clobbering the symlink. + +2002-01-08 Jeffrey Stedfast + + * camel-filter-search.c (TODO): There are a few sexp callbacks + that could be modified to use fms->info rather than using a + message object (like date and possibly mlist stuff) but *only* if + the date exists on the CamelMessageInfo object (since it may be + blank except for message flags). + (camel_filter_search_get_message): New internal convenience + function to make sure that the FilterMessageSearch has loaded the + message (and to load the message if this isn't the case). + (check_header): Call camel_filter_search_get_message(). + (header_exists): Same. + (header_regex): Here too. + (header_full_regex): And here. + (body_contains): Again here. + (body_regex): Here too. + (get_sent_date): Here also. + (get_received_date): Same. + (get_source): Here if we need to. + (camel_filter_search_match): Now takes a callback function/data + pair for on-demand message loading so that we don't necessarily + have to load the message if the defined filter rules don't require + it. + + * camel-filter-driver.c (camel_filter_driver_filter_folder): Don't + bother fetching the message here, let + camel_filter_driver_filter_message() worry about this. + (get_message_cb): New utility callback to fetch a message. + (camel_filter_driver_filter_message): Only fetch the message if we + absolutely need it to get a CamelMessageInfo. Instead of passing a + message object to camel_filter_search_match(), pass get_message_cb + and some user_data so that the matching code can fetch the message + on demand. + 2002-01-07 Jeffrey Stedfast * camel-folder.c (filter_filter): Flush the only-once actions. diff --git a/camel/camel-filter-driver.c b/camel/camel-filter-driver.c index 9a05b91b2c..c9720b621f 100644 --- a/camel/camel-filter-driver.c +++ b/camel/camel-filter-driver.c @@ -791,7 +791,7 @@ camel_filter_driver_flush (CamelFilterDriver *driver, CamelException *ex) data.driver = driver; data.ex = ex; - g_hash_table_foreach_remove (p->only_once, run_only_once, &data); + g_hash_table_foreach_remove (p->only_once, (GHRFunc) run_only_once, &data); } /** @@ -917,14 +917,13 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folde GPtrArray *uids, gboolean remove, CamelException *ex) { struct _CamelFilterDriverPrivate *p = _PRIVATE (driver); - int i; - int freeuids = FALSE; - CamelMimeMessage *message; + gboolean freeuids = FALSE; CamelMessageInfo *info; char *source_url, *service_url; const char *folder_name; int status = 0; int need_sep = 0; + int i; service_url = camel_service_get_url (CAMEL_SERVICE (camel_folder_get_parent_store (folder))); folder_name = camel_folder_get_full_name (folder); @@ -934,9 +933,8 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folde if (service_url && *service_url && !need_sep) { need_sep = (service_url[strlen (service_url)-1] != '/'); } - source_url = g_strdup_printf ("%s%s%s", - service_url, - need_sep ? "/" : "", + + source_url = g_strdup_printf ("%s%s%s", service_url, need_sep ? "/" : "", folder_name); g_free (service_url); @@ -951,20 +949,12 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folde report_status (driver, CAMEL_FILTER_STATUS_START, pc, _("Getting message %d of %d"), i+1, uids->len); - message = camel_folder_get_message (folder, uids->pdata[i], ex); - if (!message || camel_exception_is_set (ex)) { - report_status (driver, CAMEL_FILTER_STATUS_END, 100, _("Failed at message %d of %d"), - i+1, uids->len); - status = -1; - break; - } - if (camel_folder_has_summary_capability (folder)) info = camel_folder_get_message_info (folder, uids->pdata[i]); else info = NULL; - status = camel_filter_driver_filter_message (driver, message, info, uids->pdata[i], + status = camel_filter_driver_filter_message (driver, NULL, info, uids->pdata[i], folder, source_url, source_url, ex); if (camel_folder_has_summary_capability (folder)) @@ -983,8 +973,6 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folde if (cache) camel_uid_cache_save_uid (cache, uids->pdata[i]); - - camel_object_unref (CAMEL_OBJECT (message)); } if (freeuids) @@ -1004,10 +992,44 @@ camel_filter_driver_filter_folder (CamelFilterDriver *driver, CamelFolder *folde } +struct _get_message { + struct _CamelFilterDriverPrivate *p; + const char *source_url; +}; + + +static CamelMimeMessage * +get_message_cb (void *data, CamelException *ex) +{ + struct _get_message *msgdata = data; + struct _CamelFilterDriverPrivate *p = msgdata->p; + const char *source_url = msgdata->source_url; + CamelMimeMessage *message; + + if (p->message) { + message = p->message; + camel_object_ref (CAMEL_OBJECT (message)); + } else { + const char *uid; + + if (p->uid) + uid = p->uid; + else + uid = camel_message_info_uid (p->info); + + message = camel_folder_get_message (p->source, uid, ex); + } + + if (source_url && camel_mime_message_get_source (message) == NULL) + camel_mime_message_set_source (message, source_url); + + return message; +} + /** * camel_filter_driver_filter_message: * @driver: CamelFilterDriver - * @message: message to filter + * @message: message to filter or NULL * @info: message info or NULL * @uid: message uid or NULL * @source: source folder or NULL @@ -1039,14 +1061,34 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver, CamelMimeMessage ESExpResult *r; int result; + /* FIXME: make me into a g_return_if_fail/g_assert or whatever... */ + if (message == NULL && (source == NULL || uid == NULL)) { + g_warning ("there is no way to fetch the message using the information provided..."); + return -1; + } + if (info == NULL) { - struct _header_raw *h = CAMEL_MIME_PART (message)->headers; + struct _header_raw *h; + + if (message) { + camel_object_ref (CAMEL_OBJECT (message)); + } else { + message = camel_folder_get_message (source, uid, ex); + if (!message) + return -1; + } + h = CAMEL_MIME_PART (message)->headers; info = camel_message_info_new_from_header (h); freeinfo = TRUE; } else { if (info->flags & CAMEL_MESSAGE_DELETED) return 0; + + uid = camel_message_info_uid (info); + + if (message) + camel_object_ref (CAMEL_OBJECT (message)); } p->ex = ex; @@ -1058,15 +1100,20 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver, CamelMimeMessage p->uid = uid; p->source = source; - if (original_source_url && camel_mime_message_get_source (message) == NULL) + if (message && original_source_url && camel_mime_message_get_source (message) == NULL) camel_mime_message_set_source (message, original_source_url); - node = (struct _filter_rule *)p->rules.head; + node = (struct _filter_rule *) p->rules.head; result = CAMEL_SEARCH_NOMATCH; while (node->next && !p->terminated) { + struct _get_message data; + d(fprintf (stderr, "applying rule %s\naction %s\n", node->match, node->action)); - result = camel_filter_search_match (p->message, p->info, + data.p = p; + data.source_url = original_source_url; + + result = camel_filter_search_match (get_message_cb, &data, p->info, original_source_url ? original_source_url : source_url, node->match, p->ex); @@ -1119,19 +1166,31 @@ camel_filter_driver_filter_message (CamelFilterDriver *driver, CamelMimeMessage camel_folder_copy_messages_to (p->source, uids, p->defaultfolder, p->ex); g_ptr_array_free (uids, TRUE); } else { + if (p->message == NULL) { + p->message = camel_folder_get_message (source, uid, ex); + if (!p->message) + goto error; + } + camel_folder_append_message (p->defaultfolder, p->message, p->info, p->ex); } } + if (p->message) + camel_object_unref (CAMEL_OBJECT (p->message)); + if (freeinfo) camel_message_info_free (info); return 0; -error: + error: if (filtered) camel_filter_driver_log (driver, FILTER_LOG_END, NULL); + if (p->message) + camel_object_unref (CAMEL_OBJECT (p->message)); + if (freeinfo) camel_message_info_free (info); diff --git a/camel/camel-filter-search.c b/camel/camel-filter-search.c index 430f614349..c888887edd 100644 --- a/camel/camel-filter-search.c +++ b/camel/camel-filter-search.c @@ -54,6 +54,8 @@ #define d(x) typedef struct { + CamelFilterSearchGetMessageFunc get_message; + void *get_message_data; CamelMimeMessage *message; CamelMessageInfo *info; const char *source; @@ -111,6 +113,21 @@ static struct { { "get-size", (ESExpFunc *) get_size, 0 }, }; + +static CamelMimeMessage * +camel_filter_search_get_message (FilterMessageSearch *fms, struct _ESExp *sexp) +{ + if (fms->message) + return fms->message; + + fms->message = fms->get_message (fms->get_message_data, fms->ex); + + if (fms->message == NULL) + e_sexp_fatal_error (sexp, _("Failed to retrieve message")); + + return fms->message; +} + static ESExpResult * check_header (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms, camel_search_match_t how) { @@ -124,21 +141,24 @@ check_header (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMess camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED; CamelContentType *ct; const char *charset = NULL; - + if (strcasecmp(name, "x-camel-mlist") == 0) { header = camel_message_info_mlist(fms->info); type = CAMEL_SEARCH_TYPE_MLIST; } else { - header = camel_medium_get_header(CAMEL_MEDIUM(fms->message), argv[0]->value.string); + CamelMimeMessage *message = camel_filter_search_get_message (fms, f); + + header = camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string); + /* FIXME: what about Resent-To, Resent-Cc and Resent-From? */ if (strcasecmp("to", name) == 0 || strcasecmp("cc", name) == 0 || strcasecmp("from", name) == 0) type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED; else { - ct = camel_mime_part_get_content_type(CAMEL_MIME_PART(fms->message)); + ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message)); if (ct) charset = e_iconv_charset_name(header_content_type_param(ct, "charset")); } } - + if (header) { for (i=1; itype == ESEXP_RES_STRING) @@ -187,13 +207,16 @@ header_soundex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMe static ESExpResult * header_exists (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { + CamelMimeMessage *message; gboolean matched = FALSE; ESExpResult *r; int i; + message = camel_filter_search_get_message (fms, f); + for (i = 0; i < argc && !matched; i++) { if (argv[i]->type == ESEXP_RES_STRING) - matched = camel_medium_get_header (CAMEL_MEDIUM (fms->message), argv[i]->value.string) != NULL; + matched = camel_medium_get_header (CAMEL_MEDIUM (message), argv[i]->value.string) != NULL; } r = e_sexp_result_new (f, ESEXP_RES_BOOL); @@ -206,11 +229,14 @@ static ESExpResult * header_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL); + CamelMimeMessage *message; regex_t pattern; const char *contents; + message = camel_filter_search_get_message (fms, f); + if (argc > 1 && argv[0]->type == ESEXP_RES_STRING - && (contents = camel_medium_get_header (CAMEL_MEDIUM (fms->message), argv[0]->value.string)) + && (contents = camel_medium_get_header (CAMEL_MEDIUM (message), argv[0]->value.string)) && camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE, argc-1, argv+1, fms->ex) == 0) { r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0; regfree (&pattern); @@ -250,12 +276,14 @@ static ESExpResult * header_full_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL); + CamelMimeMessage *message; regex_t pattern; char *contents; if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_NEWLINE, argc, argv, fms->ex) == 0) { - contents = get_full_header (fms->message); + message = camel_filter_search_get_message (fms, f); + contents = get_full_header (message); r->value.bool = regexec (&pattern, contents, 0, NULL, 0) == 0; g_free (contents); regfree (&pattern); @@ -284,10 +312,12 @@ static ESExpResult * body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { ESExpResult *r = e_sexp_result_new (f, ESEXP_RES_BOOL); + CamelMimeMessage *message; regex_t pattern; if (camel_search_build_match_regex (&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, fms->ex) == 0) { - r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *)fms->message, &pattern); + message = camel_filter_search_get_message (fms, f); + r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *) message, &pattern); regfree (&pattern); } else r->value.bool = FALSE; @@ -299,11 +329,13 @@ static ESExpResult * body_regex (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { ESExpResult *r = e_sexp_result_new(f, ESEXP_RES_BOOL); + CamelMimeMessage *message; regex_t pattern; if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE|CAMEL_SEARCH_MATCH_REGEX|CAMEL_SEARCH_MATCH_NEWLINE, argc, argv, fms->ex) == 0) { - r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *)fms->message, &pattern); + message = camel_filter_search_get_message (fms, f); + r->value.bool = camel_search_message_body_contains ((CamelDataWrapper *) message, &pattern); regfree (&pattern); } else r->value.bool = FALSE; @@ -365,10 +397,12 @@ user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageS static ESExpResult * get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { + CamelMimeMessage *message; ESExpResult *r; + message = camel_filter_search_get_message (fms, f); r = e_sexp_result_new (f, ESEXP_RES_INT); - r->value.number = camel_mime_message_get_date (fms->message, NULL); + r->value.number = camel_mime_message_get_date (message, NULL); return r; } @@ -376,10 +410,12 @@ get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMes static ESExpResult * get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { + CamelMimeMessage *message; ESExpResult *r; + message = camel_filter_search_get_message (fms, f); r = e_sexp_result_new (f, ESEXP_RES_INT); - r->value.number = camel_mime_message_get_date_received (fms->message, NULL); + r->value.number = camel_mime_message_get_date_received (message, NULL); return r; } @@ -415,6 +451,7 @@ get_score (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessage static ESExpResult * get_source (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms) { + CamelMimeMessage *message; ESExpResult *r; char *src = NULL; char *tmp; @@ -428,17 +465,18 @@ get_source (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessag camel_url_free (url); } } else { - src = g_strdup (camel_mime_message_get_source (fms->message)); + message = camel_filter_search_get_message (fms, f); + src = g_strdup (camel_mime_message_get_source (message)); } /* This is an abusive hack */ - if ( src && (tmp = strstr (src, "://")) ) { + if (src && (tmp = strstr (src, "://"))) { tmp += 3; tmp = strchr (tmp, '/'); if (tmp) *tmp = '\0'; } - + if (src) { r = e_sexp_result_new (f, ESEXP_RES_STRING); r->value.string = src; @@ -473,8 +511,9 @@ get_size (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageS * Returns one of CAMEL_SEARCH_MATCHED, CAMEL_SEARCH_NOMATCH, or CAMEL_SEARCH_ERROR. **/ int -camel_filter_search_match (CamelMimeMessage *message, CamelMessageInfo *info, - const char *source, const char *expression, CamelException *ex) +camel_filter_search_match (CamelFilterSearchGetMessageFunc get_message, void *data, + CamelMessageInfo *info, const char *source, + const char *expression, CamelException *ex) { FilterMessageSearch fms; ESExp *sexp; @@ -482,7 +521,9 @@ camel_filter_search_match (CamelMimeMessage *message, CamelMessageInfo *info, gboolean retval; int i; - fms.message = message; + fms.get_message = get_message; + fms.get_message_data = data; + fms.message = NULL; fms.info = info; fms.source = source; fms.ex = ex; @@ -503,6 +544,7 @@ camel_filter_search_match (CamelMimeMessage *message, CamelMessageInfo *info, e_sexp_error (sexp), expression); goto error; } + result = e_sexp_eval (sexp); if (result == NULL) { if (!camel_exception_is_set (ex)) @@ -519,9 +561,16 @@ camel_filter_search_match (CamelMimeMessage *message, CamelMessageInfo *info, e_sexp_result_free (sexp, result); e_sexp_unref (sexp); + if (fms.message) + camel_object_unref (CAMEL_OBJECT (fms.message)); + return retval; -error: + error: + if (fms.message) + camel_object_unref (CAMEL_OBJECT (fms.message)); + e_sexp_unref (sexp); + return CAMEL_SEARCH_ERROR; } diff --git a/camel/camel-filter-search.h b/camel/camel-filter-search.h index 1010603b2b..d54c3c03b7 100644 --- a/camel/camel-filter-search.h +++ b/camel/camel-filter-search.h @@ -40,8 +40,11 @@ enum { CAMEL_SEARCH_MATCHED = 1, }; -int camel_filter_search_match (CamelMimeMessage *message, CamelMessageInfo *info, - const char *source, const char *expression, CamelException *ex); +typedef CamelMimeMessage * (*CamelFilterSearchGetMessageFunc) (void *data, CamelException *ex); + +int camel_filter_search_match (CamelFilterSearchGetMessageFunc get_message, void *data, + CamelMessageInfo *info, const char *source, + const char *expression, CamelException *ex); #ifdef __cplusplus } diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c index 0a4d581bdf..b6d6ef8ab2 100644 --- a/camel/providers/local/camel-local-folder.c +++ b/camel/providers/local/camel-local-folder.c @@ -24,6 +24,7 @@ #endif #include +#include #include #include #include @@ -172,6 +173,7 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con CamelFolderInfo *fi; CamelFolder *folder; const char *root_dir_path, *name; + char folder_path[PATH_MAX]; struct stat st; int forceindex; @@ -191,13 +193,19 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con lf->folder_path = g_strdup_printf("%s/%s", root_dir_path, full_name); lf->summary_path = g_strdup_printf("%s/%s.ev-summary", root_dir_path, full_name); lf->index_path = g_strdup_printf("%s/%s.ibex", root_dir_path, full_name); - + + /* follow any symlinks to the mailbox */ + if (lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) && + realpath (lf->folder_path, folder_path) != NULL) { + g_free (lf->folder_path); + lf->folder_path = g_strdup (folder_path); + } + lf->changes = camel_folder_change_info_new(); /* if we have no index file, force it */ forceindex = stat(lf->index_path, &st) == -1; if (flags & CAMEL_STORE_FOLDER_BODY_INDEX) { - lf->index = ibex_open(lf->index_path, O_CREAT | O_RDWR, 0600); if (lf->index == NULL) { /* yes, this isn't fatal at all */ -- cgit v1.2.3