FILE *procmsg_open_message(MsgInfo *msginfo) { FILE *fp; gchar *file; g_return_val_if_fail(msginfo != NULL, NULL); file = procmsg_get_message_file_path(msginfo); g_return_val_if_fail(file != NULL, NULL); if (!is_file_exist(file)) { g_free(file); file = procmsg_get_message_file(msginfo); if (!file) return NULL; } if ((fp = fopen(file, "rb")) == NULL) { FILE_OP_ERROR(file, "fopen"); g_free(file); return NULL; } g_free(file); if (MSG_IS_QUEUED(msginfo->flags) || MSG_IS_DRAFT(msginfo->flags)) { gchar buf[BUFFSIZE]; while (fgets(buf, sizeof(buf), fp) != NULL) if (buf[0] == '\r' || buf[0] == '\n') break; } return fp; }
GSList *procmsg_get_message_file_list(GSList *mlist) { GSList *file_list = NULL; MsgInfo *msginfo; MsgFileInfo *fileinfo; gchar *file; while (mlist != NULL) { msginfo = (MsgInfo *)mlist->data; file = procmsg_get_message_file(msginfo); if (!file) { procmsg_message_file_list_free(file_list); return NULL; } fileinfo = g_new(MsgFileInfo, 1); fileinfo->msginfo = procmsg_msginfo_new_ref(msginfo); fileinfo->file = file; fileinfo->flags = g_new(MsgFlags, 1); *fileinfo->flags = msginfo->flags; file_list = g_slist_prepend(file_list, fileinfo); mlist = mlist->next; } file_list = g_slist_reverse(file_list); return file_list; }
MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo) { MsgInfo *full_msginfo; gchar *file; if (msginfo == NULL) return NULL; file = procmsg_get_message_file_path(msginfo); if (!file || !is_file_exist(file)) { g_free(file); file = procmsg_get_message_file(msginfo); } if (!file || !is_file_exist(file)) { g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n"); return NULL; } full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE, FALSE); g_free(file); if (!full_msginfo) return NULL; /* CLAWS: make sure we add the missing members; see: * procheader.c::procheader_get_headernames() */ if (!msginfo->xface) msginfo->xface = g_strdup(full_msginfo->xface); if (!msginfo->dispositionnotificationto) msginfo->dispositionnotificationto = g_strdup(full_msginfo->dispositionnotificationto); if (!msginfo->returnreceiptto) msginfo->returnreceiptto = g_strdup (full_msginfo->returnreceiptto); if (!msginfo->partial_recv && full_msginfo->partial_recv) msginfo->partial_recv = g_strdup (full_msginfo->partial_recv); msginfo->total_size = full_msginfo->total_size; if (!msginfo->account_server && full_msginfo->account_server) msginfo->account_server = g_strdup (full_msginfo->account_server); if (!msginfo->account_login && full_msginfo->account_login) msginfo->account_login = g_strdup (full_msginfo->account_login); msginfo->planned_download = full_msginfo->planned_download; procmsg_msginfo_free(full_msginfo); return procmsg_msginfo_new_ref(msginfo); }
void source_window_show_msg(SourceWindow *sourcewin, MsgInfo *msginfo) { gchar *file; gchar *title; FILE *fp; gchar buf[BUFFSIZE]; cm_return_if_fail(msginfo != NULL); sourcewin->updating = TRUE; file = procmsg_get_message_file(msginfo); sourcewin->updating = FALSE; if (sourcewin->deferred_destroy) { g_free(file); source_window_destroy(sourcewin); return; } cm_return_if_fail(file != NULL); if ((fp = g_fopen(file, "rb")) == NULL) { FILE_OP_ERROR(file, "fopen"); g_free(file); return; } debug_print("Displaying the source of %s ...\n", file); title = g_strdup_printf(_("%s - Source"), file); gtk_window_set_title(GTK_WINDOW(sourcewin->window), title); g_free(title); g_free(file); while (fgets(buf, sizeof(buf), fp) != NULL) source_window_append(sourcewin, buf); fclose(fp); }
static gint mh_copy_msgs(Folder *folder, FolderItem *dest, MsgInfoList *msglist, GHashTable *relation) { gboolean dest_need_scan = FALSE; gboolean src_need_scan = FALSE; FolderItem *src = NULL; gchar *srcfile; gchar *destfile; FolderItemPrefs *prefs; MsgInfo *msginfo = NULL; MsgInfoList *cur = NULL; gint curnum = 0, total = 0; gchar *srcpath = NULL; gboolean full_fetch = FALSE; time_t last_dest_mtime = (time_t)0; time_t last_src_mtime = (time_t)0; cm_return_val_if_fail(dest != NULL, -1); cm_return_val_if_fail(msglist != NULL, -1); msginfo = (MsgInfo *)msglist->data; cm_return_val_if_fail(msginfo != NULL, -1); if (msginfo->folder == dest) { g_warning("the src folder is identical to the dest.\n"); return -1; } if (msginfo->folder->folder != dest->folder) full_fetch = TRUE; if (FOLDER_TYPE(msginfo->folder->folder) == F_MH) { src = msginfo->folder; } if (dest->last_num < 0) { mh_get_last_num(folder, dest); if (dest->last_num < 0) return -1; } prefs = dest->prefs; srcpath = folder_item_get_path(msginfo->folder); dest_need_scan = mh_scan_required(dest->folder, dest); last_dest_mtime = dest->mtime; if (src) { src_need_scan = mh_scan_required(src->folder, src); last_src_mtime = src->mtime; } total = g_slist_length(msglist); if (total > 100) { if (MSG_IS_MOVE(msginfo->flags)) statusbar_print_all(_("Moving messages...")); else statusbar_print_all(_("Copying messages...")); } for (cur = msglist; cur; cur = cur->next) { msginfo = (MsgInfo *)cur->data; if (!msginfo) { goto err_reset_status; } if (!full_fetch) { srcfile = g_strconcat(srcpath, G_DIR_SEPARATOR_S, itos(msginfo->msgnum), NULL); } else { srcfile = procmsg_get_message_file(msginfo); } if (!srcfile) { goto err_reset_status; } destfile = mh_get_new_msg_filename(dest); if (!destfile) { g_free(srcfile); goto err_reset_status; } if (total > 100) { statusbar_progress_all(curnum, total, 100); if (curnum % 100 == 0) GTK_EVENTS_FLUSH(); curnum++; } debug_print("Copying message %s%c%d to %s ...\n", msginfo->folder->path, G_DIR_SEPARATOR, msginfo->msgnum, dest->path); if (MSG_IS_MOVE(msginfo->flags)) { msginfo->flags.tmp_flags &= ~MSG_MOVE_DONE; if (move_file(srcfile, destfile, TRUE) < 0) { FILE_OP_ERROR(srcfile, "move"); if (copy_file(srcfile, destfile, TRUE) < 0) { FILE_OP_ERROR(srcfile, "copy"); g_free(srcfile); g_free(destfile); goto err_reset_status; } } else { /* say unlinking's not necessary */ msginfo->flags.tmp_flags |= MSG_MOVE_DONE; } } else if (copy_file(srcfile, destfile, TRUE) < 0) { FILE_OP_ERROR(srcfile, "copy"); g_free(srcfile); g_free(destfile); goto err_reset_status; } if (prefs && prefs->enable_folder_chmod && prefs->folder_chmod) { if (chmod(destfile, prefs->folder_chmod) < 0) FILE_OP_ERROR(destfile, "chmod"); } if (relation) { if (g_hash_table_lookup(relation, msginfo) != NULL) g_warning("already in : %p", msginfo); g_hash_table_insert(relation, msginfo, GINT_TO_POINTER(dest->last_num+1)); } g_free(srcfile); g_free(destfile); dest->last_num++; } g_free(srcpath); mh_write_sequences(dest, TRUE); if (dest->mtime == last_dest_mtime && !dest_need_scan) { mh_set_mtime(folder, dest); } if (src && src->mtime == last_src_mtime && !src_need_scan) { mh_set_mtime(folder, src); } if (total > 100) { statusbar_progress_all(0,0,0); statusbar_pop_all(); } return dest->last_num; err_reset_status: g_free(srcpath); mh_write_sequences(dest, TRUE); if (total > 100) { statusbar_progress_all(0,0,0); statusbar_pop_all(); } return -1; }
int bogofilter_learn(MsgInfo *msginfo, GSList *msglist, gboolean spam) { gchar *cmd = NULL; gchar *file = NULL; const gchar *bogo_exec = (config.bogopath && *config.bogopath) ? config.bogopath:"bogofilter"; gint status = 0; if (msginfo == NULL && msglist == NULL) { return -1; } if (msginfo) { file = procmsg_get_message_file(msginfo); if (file == NULL) { return -1; } else { if (message_callback != NULL) message_callback(_("Bogofilter: learning from message..."), 0, 0, FALSE); if (spam) /* learn as spam */ cmd = g_strdup_printf("%s -s -I '%s'", bogo_exec, file); else if (MSG_IS_SPAM(msginfo->flags)) /* correct bogofilter, this wasn't spam */ cmd = g_strdup_printf("%s -Sn -I '%s'", bogo_exec, file); else /* learn as ham */ cmd = g_strdup_printf("%s -n -I '%s'", bogo_exec, file); debug_print("%s\n", cmd); if ((status = execute_command_line(cmd, FALSE, NULL)) != 0) log_error(LOG_PROTOCOL, _("Learning failed; `%s` returned with status %d."), cmd, status); g_free(cmd); g_free(file); if (message_callback != NULL) message_callback(NULL, 0, 0, FALSE); } } else if (msglist) { GSList *cur = msglist; MsgInfo *info; int total = g_slist_length(msglist); int done = 0; gboolean some_correction = FALSE, some_no_correction = FALSE; if (message_callback != NULL) message_callback(_("Bogofilter: learning from messages..."), total, 0, FALSE); for (cur = msglist; cur && status == 0; cur = cur->next) { info = (MsgInfo *)cur->data; if (spam) some_no_correction = TRUE; else if (MSG_IS_SPAM(info->flags)) /* correct bogofilter, this wasn't spam */ some_correction = TRUE; else some_no_correction = TRUE; } if (some_correction && some_no_correction) { /* we potentially have to do different stuff for every mail */ for (cur = msglist; cur && status == 0; cur = cur->next) { info = (MsgInfo *)cur->data; file = procmsg_get_message_file(info); if (spam) /* learn as spam */ cmd = g_strdup_printf("%s -s -I '%s'", bogo_exec, file); else if (MSG_IS_SPAM(info->flags)) /* correct bogofilter, this wasn't spam */ cmd = g_strdup_printf("%s -Sn -I '%s'", bogo_exec, file); else /* learn as ham */ cmd = g_strdup_printf("%s -n -I '%s'", bogo_exec, file); debug_print("%s\n", cmd); if ((status = execute_command_line(cmd, FALSE, NULL)) != 0) log_error(LOG_PROTOCOL, _("Learning failed; `%s` returned with status %d."), cmd, status); g_free(cmd); g_free(file); done++; if (message_callback != NULL) message_callback(NULL, total, done, FALSE); } } else if (some_correction || some_no_correction) { cur = msglist; gchar *bogo_args[4]; GPid bogo_pid; gint bogo_stdin; GError *error = NULL; gboolean bogo_forked; bogo_args[0] = (gchar *)bogo_exec; if (some_correction && !some_no_correction) bogo_args[1] = "-Sn"; else if (some_no_correction && !some_correction) bogo_args[1] = spam ? "-s":"-n"; bogo_args[2] = "-b"; bogo_args[3] = NULL; debug_print("|%s %s %s ...\n", bogo_args[0], bogo_args[1], bogo_args[2]); bogo_forked = g_spawn_async_with_pipes( NULL, bogo_args,NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &bogo_pid, &bogo_stdin, NULL, NULL, &error); while (bogo_forked && cur) { gchar *tmp = NULL; info = (MsgInfo *)cur->data; file = procmsg_get_message_file(info); if (file) { tmp = g_strdup_printf("%s\n", file); write_all(bogo_stdin, tmp, strlen(tmp)); g_free(tmp); } g_free(file); done++; if (message_callback != NULL) message_callback(NULL, total, done, FALSE); cur = cur->next; } if (bogo_forked) { close(bogo_stdin); waitpid(bogo_pid, &status, 0); if (!WIFEXITED(status)) status = -1; else status = WEXITSTATUS(status); } if (!bogo_forked || status != 0) { log_error(LOG_PROTOCOL, _("Learning failed; `%s %s %s` returned with error:\n%s"), bogo_args[0], bogo_args[1], bogo_args[2], error ? error->message:_("Unknown error")); if (error) g_error_free(error); } } if (message_callback != NULL) message_callback(NULL, 0, 0, FALSE); } return 0; }
static gboolean mail_filtering_hook(gpointer source, gpointer data) { MailFilteringData *mail_filtering_data = (MailFilteringData *) source; MsgInfo *msginfo = mail_filtering_data->msginfo; GSList *msglist = mail_filtering_data->msglist; GSList *cur = NULL; static gboolean warned_error = FALSE; int status = 0; int total = 0, curnum = 0; GSList *new_hams = NULL, *new_spams = NULL; GSList *new_unsure, *whitelisted_new_spams = NULL; gchar *bogo_exec = (config.bogopath && *config.bogopath) ? config.bogopath:"bogofilter"; gchar *bogo_args[4]; gboolean ok_to_thread = TRUE; bogo_args[0] = bogo_exec; bogo_args[1] = "-T"; bogo_args[2] = "-b"; bogo_args[3] = NULL; if (!config.process_emails) { return FALSE; } if (msglist == NULL && msginfo != NULL) { g_warning("wrong call to bogofilter mail_filtering_hook"); return FALSE; } total = g_slist_length(msglist); /* we have to make sure the mails are cached - or it'll break on IMAP */ if (message_callback != NULL) message_callback(_("Bogofilter: fetching bodies..."), total, 0, FALSE); for (cur = msglist; cur; cur = cur->next) { gchar *file = procmsg_get_message_file((MsgInfo *)cur->data); if (file == NULL) ok_to_thread = FALSE; if (message_callback != NULL) message_callback(NULL, total, curnum++, FALSE); g_free(file); } if (message_callback != NULL) message_callback(NULL, 0, 0, FALSE); if (message_callback != NULL) message_callback(_("Bogofilter: filtering messages..."), total, 0, FALSE); #ifdef USE_PTHREAD while (pthread_mutex_trylock(&list_mutex) != 0) { GTK_EVENTS_FLUSH(); usleep(100); } #endif to_filter_data = g_new0(BogoFilterData, 1); to_filter_data->msglist = msglist; to_filter_data->mail_filtering_data = mail_filtering_data; to_filter_data->new_hams = NULL; to_filter_data->new_unsure = NULL; to_filter_data->new_spams = NULL; to_filter_data->whitelisted_new_spams = NULL; to_filter_data->done = FALSE; to_filter_data->status = -1; to_filter_data->bogo_args = bogo_args; #ifdef USE_PTHREAD to_filter_data->in_thread = (filter_th != 0 && ok_to_thread); #else to_filter_data->in_thread = FALSE; #endif #ifdef USE_PTHREAD pthread_mutex_unlock(&list_mutex); if (filter_th != 0 && ok_to_thread) { debug_print("waking thread to let it filter things\n"); pthread_mutex_lock(&wait_mutex); pthread_cond_broadcast(&wait_cond); pthread_mutex_unlock(&wait_mutex); while (!to_filter_data->done) { GTK_EVENTS_FLUSH(); usleep(100); } } while (pthread_mutex_trylock(&list_mutex) != 0) { GTK_EVENTS_FLUSH(); usleep(100); } if (filter_th == 0 || !ok_to_thread) bogofilter_do_filter(to_filter_data); #else bogofilter_do_filter(to_filter_data); #endif new_hams = to_filter_data->new_hams; new_unsure = to_filter_data->new_unsure; new_spams = to_filter_data->new_spams; whitelisted_new_spams = to_filter_data->whitelisted_new_spams; status = to_filter_data->status; g_free(to_filter_data); to_filter_data = NULL; #ifdef USE_PTHREAD pthread_mutex_unlock(&list_mutex); #endif /* unflag hams */ for (cur = new_hams; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0); debug_print("unflagging ham: %d\n", msginfo->msgnum); } /* unflag unsure */ for (cur = new_unsure; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0); debug_print("unflagging unsure: %d\n", msginfo->msgnum); } if (config.learn_from_whitelist && whitelisted_new_spams) { /* flag whitelisted spams */ for (cur = whitelisted_new_spams; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0); debug_print("flagging whitelisted non-ham: %d\n", msginfo->msgnum); } /* correct bogo */ bogofilter_learn(NULL, whitelisted_new_spams, FALSE); /* unflag them */ for (cur = whitelisted_new_spams; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0); debug_print("unflagging whitelisted non-ham: %d\n", msginfo->msgnum); } } else { for (cur = whitelisted_new_spams; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0); debug_print("not flagging whitelisted non-ham: %d\n", msginfo->msgnum); } } /* flag spams and delete them if config.receive_spam == 0 * (if config.receive_spam is set to 1, we'll move them later, * mark as spam only if set to 2) */ for (cur = new_spams; cur; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; if (config.receive_spam != SPAM_DELETE) { if (config.mark_as_read) procmsg_msginfo_unset_flags(msginfo, ~0, 0); procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0); } else { folder_item_remove_msg(msginfo->folder, msginfo->msgnum); } } if (status < 0 || status > 2) { /* I/O or other errors */ gchar *msg = NULL; if (status == 3) msg = g_strdup_printf(_("The Bogofilter plugin couldn't filter " "a message. The probable cause of the " "error is that it didn't learn from any mail.\n" "Use \"/Mark/Mark as spam\" and \"/Mark/Mark as " "ham\" to train Bogofilter with a few hundred " "spam and ham messages.")); else msg = g_strdup_printf(_("The Bogofilter plugin couldn't filter " "a message. The command `%s %s %s` couldn't be run."), bogo_args[0], bogo_args[1], bogo_args[2]); if (!prefs_common_get_prefs()->no_recv_err_panel) { if (!warned_error) { alertpanel_error("%s", msg); } warned_error = TRUE; } else { log_error(LOG_PROTOCOL, "%s\n", msg); } g_free(msg); } if (status < 0 || status > 2) { g_slist_free(mail_filtering_data->filtered); g_slist_free(mail_filtering_data->unfiltered); mail_filtering_data->filtered = NULL; mail_filtering_data->unfiltered = NULL; } else { if (config.receive_spam == SPAM_MARK_AND_SAVE && new_spams) { FolderItem *save_folder = NULL; if ((!config.save_folder) || (config.save_folder[0] == '\0') || ((save_folder = folder_find_item_from_identifier(config.save_folder)) == NULL)) { if (mail_filtering_data->account && mail_filtering_data->account->set_trash_folder) { save_folder = folder_find_item_from_identifier( mail_filtering_data->account->trash_folder); if (save_folder) debug_print("found trash folder from account's advanced settings\n"); } if (save_folder == NULL && mail_filtering_data->account && mail_filtering_data->account->folder) { save_folder = mail_filtering_data->account->folder->trash; if (save_folder) debug_print("found trash folder from account's trash\n"); } if (save_folder == NULL && mail_filtering_data->account && !mail_filtering_data->account->folder) { if (mail_filtering_data->account->inbox) { FolderItem *item = folder_find_item_from_identifier( mail_filtering_data->account->inbox); if (item && item->folder->trash) { save_folder = item->folder->trash; debug_print("found trash folder from account's inbox\n"); } } if (!save_folder && mail_filtering_data->account->local_inbox) { FolderItem *item = folder_find_item_from_identifier( mail_filtering_data->account->local_inbox); if (item && item->folder->trash) { save_folder = item->folder->trash; debug_print("found trash folder from account's local_inbox\n"); } } } if (save_folder == NULL) { debug_print("using default trash folder\n"); save_folder = folder_get_default_trash(); } } if (save_folder) { for (cur = new_spams; cur; cur = cur->next) { msginfo = (MsgInfo *)cur->data; msginfo->filter_op = IS_MOVE; msginfo->to_filter_folder = save_folder; } } } if (config.save_unsure && new_unsure) { FolderItem *save_unsure_folder = NULL; if ((!config.save_unsure_folder) || (config.save_unsure_folder[0] == '\0') || ((save_unsure_folder = folder_find_item_from_identifier(config.save_unsure_folder)) == NULL)) { if (mail_filtering_data->account) save_unsure_folder = folder_find_item_from_identifier( mail_filtering_data->account->inbox); if (save_unsure_folder == NULL && mail_filtering_data->account && mail_filtering_data->account->folder) save_unsure_folder = mail_filtering_data->account->folder->inbox; if (save_unsure_folder == NULL && mail_filtering_data->account && !mail_filtering_data->account->folder) { if (mail_filtering_data->account->inbox) { FolderItem *item = folder_find_item_from_identifier( mail_filtering_data->account->inbox); if (item) { save_unsure_folder = item; } } if (!save_unsure_folder && mail_filtering_data->account->local_inbox) { FolderItem *item = folder_find_item_from_identifier( mail_filtering_data->account->local_inbox); if (item) { save_unsure_folder = item; } } } if (save_unsure_folder == NULL) save_unsure_folder = folder_get_default_inbox(); } if (save_unsure_folder) { for (cur = new_unsure; cur; cur = cur->next) { msginfo = (MsgInfo *)cur->data; msginfo->filter_op = IS_MOVE; msginfo->to_filter_folder = save_unsure_folder; } } } } g_slist_free(new_hams); g_slist_free(new_unsure); g_slist_free(new_spams); g_slist_free(whitelisted_new_spams); if (message_callback != NULL) message_callback(NULL, 0, 0, FALSE); mail_filtering_data->filtered = g_slist_reverse( mail_filtering_data->filtered); mail_filtering_data->unfiltered = g_slist_reverse( mail_filtering_data->unfiltered); return FALSE; }
static void bogofilter_do_filter(BogoFilterData *data) { GPid bogo_pid; gint bogo_stdin, bogo_stdout; GError *error = NULL; gboolean bogo_forked; int status = 0; MsgInfo *msginfo; GSList *cur = NULL; int total = 0, curnum = 1; gchar *file = NULL; gchar buf[BUFSIZ]; total = g_slist_length(data->msglist); bogo_forked = g_spawn_async_with_pipes( NULL, data->bogo_args,NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &bogo_pid, &bogo_stdin, &bogo_stdout, NULL, &error); if (bogo_forked == FALSE) { g_warning("%s", error ? error->message:"ERROR???"); g_error_free(error); error = NULL; status = -1; } else { if (config.whitelist_ab) { gchar *ab_folderpath; if (*config.whitelist_ab_folder == '\0' || strcasecmp(config.whitelist_ab_folder, "Any") == 0) { /* match the whole addressbook */ ab_folderpath = NULL; } else { /* match the specific book/folder of the addressbook */ ab_folderpath = config.whitelist_ab_folder; } start_address_completion(ab_folderpath); } for (cur = data->msglist; cur; cur = cur->next) { gboolean whitelisted = FALSE; msginfo = (MsgInfo *)cur->data; debug_print("Filtering message %d (%d/%d)\n", msginfo->msgnum, curnum, total); if (message_callback != NULL) message_callback(NULL, total, curnum++, data->in_thread); if (config.whitelist_ab && msginfo->from && found_in_addressbook(msginfo->from)) whitelisted = TRUE; /* can set flags (SCANNED, ATTACHMENT) but that's ok * as GUI updates are hooked not direct */ file = procmsg_get_message_file(msginfo); if (file) { gchar *tmp = g_strdup_printf("%s\n",file); /* send filename to bogofilter */ write_all(bogo_stdin, tmp, strlen(tmp)); g_free(tmp); memset(buf, 0, sizeof(buf)); /* get the result */ if (read(bogo_stdout, buf, sizeof(buf)-1) < 0) { g_warning("bogofilter short read"); debug_print("message %d is ham\n", msginfo->msgnum); data->mail_filtering_data->unfiltered = g_slist_prepend( data->mail_filtering_data->unfiltered, msginfo); data->new_hams = g_slist_prepend(data->new_hams, msginfo); } else { gchar **parts = NULL; buf[sizeof(buf) - 1] = '\0'; if (strchr(buf, '/')) { tmp = strrchr(buf, '/')+1; } else { tmp = buf; } parts = g_strsplit(tmp, " ", 0); debug_print("read %s\n", buf); /* note the result if the header if needed */ if (parts && parts[0] && parts[1] && parts[2] && FOLDER_TYPE(msginfo->folder->folder) == F_MH && config.insert_header) { gchar *tmpfile = get_tmp_file(); FILE *input = claws_fopen(file, "r"); FILE *output = claws_fopen(tmpfile, "w"); if (strstr(parts[2], "\n")) *(strstr(parts[2], "\n")) = '\0'; if (input && !output) claws_fclose (input); else if (!input && output) claws_fclose (output); else if (input && output) { gchar tmpbuf[BUFFSIZE]; gboolean err = FALSE; const gchar *bogosity = *parts[1] == 'S' ? "Spam": (*parts[1] == 'H' ? "Ham":"Unsure"); gchar *tmpstr = g_strdup_printf( "X-Bogosity: %s, spamicity=%s%s\n", bogosity, parts[2], whitelisted?" [whitelisted]":""); if (claws_fwrite(tmpstr, 1, strlen(tmpstr), output) < strlen(tmpstr)) { err = TRUE; } else { while (claws_fgets(tmpbuf, sizeof(buf), input)) { if (claws_fputs(tmpbuf, output) == EOF) { err = TRUE; break; } } } claws_fclose(input); if (claws_safe_fclose(output) == EOF) err = TRUE; if (!err) move_file(tmpfile, file, TRUE); g_free(tmpstr); } g_free(tmpfile); } /* file the mail */ if (!whitelisted && parts && parts[0] && parts[1] && *parts[1] == 'S') { debug_print("message %d is spam\n", msginfo->msgnum); /* Spam will be filtered away, unless we want "mark only". * In that case, we want it among unfiltered messages, so * it gets processed further. */ if (config.receive_spam == SPAM_MARK_ONLY) { data->mail_filtering_data->unfiltered = g_slist_prepend( data->mail_filtering_data->unfiltered, msginfo); } else { data->mail_filtering_data->filtered = g_slist_prepend( data->mail_filtering_data->filtered, msginfo); } data->new_spams = g_slist_prepend(data->new_spams, msginfo); } else if (whitelisted && parts && parts[0] && parts[1] && (*parts[1] == 'S' || *parts[1] == 'U')) { debug_print("message %d is whitelisted %s\n", msginfo->msgnum, *parts[1] == 'S' ? "spam":"unsure"); /* Whitelisted spam will *not* be filtered away, but continue * their trip through filtering as if it was ham. */ data->mail_filtering_data->unfiltered = g_slist_prepend( data->mail_filtering_data->unfiltered, msginfo); /* But it gets put in a different list, so that we * can still flag it and inform the user that it is * considered a spam (so that he can teach bogo that * it was not). */ data->whitelisted_new_spams = g_slist_prepend(data->whitelisted_new_spams, msginfo); } else if (config.save_unsure && parts && parts[0] && parts[1] && *parts[1] == 'U') { debug_print("message %d is unsure\n", msginfo->msgnum); /* Spam will be filtered away */ data->mail_filtering_data->filtered = g_slist_prepend( data->mail_filtering_data->filtered, msginfo); data->new_unsure = g_slist_prepend(data->new_unsure, msginfo); } else { debug_print("message %d is ham\n", msginfo->msgnum); data->mail_filtering_data->unfiltered = g_slist_prepend( data->mail_filtering_data->unfiltered, msginfo); data->new_hams = g_slist_prepend(data->new_hams, msginfo); } g_strfreev(parts); } g_free(file); } else { data->mail_filtering_data->unfiltered = g_slist_prepend( data->mail_filtering_data->unfiltered, msginfo); data->new_hams = g_slist_prepend(data->new_hams, msginfo); } } if (config.whitelist_ab) end_address_completion(); } if (status != -1) { close(bogo_stdout); close(bogo_stdin); waitpid(bogo_pid, &status, 0); if (!WIFEXITED(status)) status = -1; else status = WEXITSTATUS(status); } to_filter_data->status = status; }
int spamassassin_learn(MsgInfo *msginfo, GSList *msglist, gboolean spam) { gchar *cmd = NULL; gchar *file = NULL; const gchar *shell = g_getenv("SHELL"); gchar *spamc_wrapper = NULL; if (msginfo == NULL && msglist == NULL) { return -1; } if (config.transport == SPAMASSASSIN_TRANSPORT_TCP && prefs_common_get_prefs()->work_offline && !inc_offline_should_override(TRUE, _("Claws Mail needs network access in order " "to feed the mail to the remote learner."))) { return -1; } if (msginfo) { file = procmsg_get_message_file(msginfo); if (file == NULL) { return -1; } if (config.transport == SPAMASSASSIN_TRANSPORT_TCP) { spamc_wrapper = spamassassin_create_tmp_spamc_wrapper(spam); if (spamc_wrapper != NULL) { cmd = g_strconcat(shell?shell:"sh", " ", spamc_wrapper, " ", file, NULL); } } else { cmd = g_strdup_printf("sa-learn -u %s%s %s %s", config.username, prefs_common_get_prefs()->work_offline?" -L":"", spam?"--spam":"--ham", file); } } if (msglist) { GSList *cur = msglist; MsgInfo *info; if (config.transport == SPAMASSASSIN_TRANSPORT_TCP) { /* execute n-times the spamc command */ for (; cur; cur = cur->next) { info = (MsgInfo *)cur->data; gchar *tmpcmd = NULL; gchar *tmpfile = get_tmp_file(); if (spamc_wrapper == NULL) { spamc_wrapper = spamassassin_create_tmp_spamc_wrapper(spam); } if (spamc_wrapper && tmpfile && copy_file(procmsg_get_message_file(info), tmpfile, TRUE) == 0) { tmpcmd = g_strconcat(shell?shell:"sh", " ", spamc_wrapper, " ", tmpfile, NULL); debug_print("%s\n", tmpcmd); execute_command_line(tmpcmd, FALSE, NULL); g_free(tmpcmd); } g_free(tmpfile); } g_free(spamc_wrapper); return 0; } else { cmd = g_strdup_printf("sa-learn -u %s%s %s", config.username, prefs_common_get_prefs()->work_offline?" -L":"", spam?"--spam":"--ham"); /* concatenate all message tmpfiles to the sa-learn command-line */ for (; cur; cur = cur->next) { info = (MsgInfo *)cur->data; gchar *tmpcmd = NULL; gchar *tmpfile = get_tmp_file(); if (tmpfile && copy_file(procmsg_get_message_file(info), tmpfile, TRUE) == 0) { tmpcmd = g_strconcat(cmd, " ", tmpfile, NULL); g_free(cmd); cmd = tmpcmd; } g_free(tmpfile); } } } if (cmd == NULL) { return -1; } debug_print("%s\n", cmd); /* only run sync calls to sa-learn/spamc to prevent system lockdown */ execute_command_line(cmd, FALSE, NULL); g_free(cmd); g_free(spamc_wrapper); return 0; }