diff options
Diffstat (limited to 'plugin/attachment_tool/attachment_tool.c')
| -rw-r--r-- | plugin/attachment_tool/attachment_tool.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/plugin/attachment_tool/attachment_tool.c b/plugin/attachment_tool/attachment_tool.c new file mode 100644 index 0000000..de299a2 --- /dev/null +++ b/plugin/attachment_tool/attachment_tool.c | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /* | ||
| 2 | * Attachment Tool Plug-in -- an attachment processing plug-in for Sylpheed | ||
| 3 | * Copyright (C) 2010 Hiroyuki Yamamoto | ||
| 4 | * | ||
| 5 | * This library is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; either | ||
| 8 | * version 2.1 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This library is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this library; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include "defs.h" | ||
| 21 | |||
| 22 | #include <glib.h> | ||
| 23 | #include <gtk/gtk.h> | ||
| 24 | |||
| 25 | #include <stdio.h> | ||
| 26 | #include <sys/stat.h> | ||
| 27 | |||
| 28 | #include "sylmain.h" | ||
| 29 | #include "plugin.h" | ||
| 30 | #include "procmsg.h" | ||
| 31 | #include "procmime.h" | ||
| 32 | #include "utils.h" | ||
| 33 | |||
| 34 | #include <glib/gi18n-lib.h> | ||
| 35 | |||
| 36 | static SylPluginInfo info = { | ||
| 37 | "Attachment Tool Plug-in", | ||
| 38 | "0.1.0", | ||
| 39 | "Hiroyuki Yamamoto", | ||
| 40 | "Attachment processing plug-in for Sylpheed" | ||
| 41 | }; | ||
| 42 | |||
| 43 | static void remove_attachment_cb(void); | ||
| 44 | |||
| 45 | void plugin_load(void) | ||
| 46 | { | ||
| 47 | debug_print("initializing attachment_tool plug-in\n"); | ||
| 48 | |||
| 49 | syl_plugin_add_menuitem("/Tools", NULL, NULL, NULL); | ||
| 50 | syl_plugin_add_menuitem("/Tools", _("Remove attachments"), remove_attachment_cb, NULL); | ||
| 51 | |||
| 52 | debug_print("attachment_tool plug-in loading done.\n"); | ||
| 53 | } | ||
| 54 | |||
| 55 | void plugin_unload(void) | ||
| 56 | { | ||
| 57 | debug_print("attachment_tool plug-in unloaded.\n"); | ||
| 58 | } | ||
| 59 | |||
| 60 | SylPluginInfo *plugin_info(void) | ||
| 61 | { | ||
| 62 | return &info; | ||
| 63 | } | ||
| 64 | |||
| 65 | gint plugin_interface_version(void) | ||
| 66 | { | ||
| 67 | return SYL_PLUGIN_INTERFACE_VERSION; | ||
| 68 | } | ||
| 69 | |||
| 70 | static gboolean remove_attachment_rec(MimeInfo *partinfo, FILE *fp, FILE *outfp) | ||
| 71 | { | ||
| 72 | gchar buf[BUFFSIZE]; | ||
| 73 | gchar *boundary = NULL; | ||
| 74 | gint boundary_len = 0; | ||
| 75 | gboolean err = FALSE; | ||
| 76 | |||
| 77 | while (partinfo) { | ||
| 78 | gboolean is_attach_part = FALSE; | ||
| 79 | gint count; | ||
| 80 | |||
| 81 | debug_print("------------------------------------------------- begin %s\n", partinfo->content_type); | ||
| 82 | debug_print("fpos = %ld\n", partinfo->fpos); | ||
| 83 | debug_print("content_type = %s\n", partinfo->content_type); | ||
| 84 | |||
| 85 | if (partinfo->filename || partinfo->name) { | ||
| 86 | is_attach_part = TRUE; | ||
| 87 | debug_print("skip this body\n"); | ||
| 88 | } | ||
| 89 | |||
| 90 | if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) { | ||
| 91 | perror("fseek"); | ||
| 92 | err = TRUE; | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | /* write part headers */ | ||
| 96 | count = 0; | ||
| 97 | while (fgets(buf, sizeof(buf), fp) != NULL) { | ||
| 98 | count++; | ||
| 99 | fputs(buf, outfp); | ||
| 100 | if (buf[0] == '\r' || buf[0] == '\n') break; | ||
| 101 | } | ||
| 102 | debug_print("wrote header: %d lines\n", count); | ||
| 103 | |||
| 104 | /* write until first boundary */ | ||
| 105 | count = 0; | ||
| 106 | if (partinfo->children && partinfo->boundary) { | ||
| 107 | boundary = partinfo->boundary; | ||
| 108 | boundary_len = strlen(boundary); | ||
| 109 | debug_print("write until %s\n", boundary); | ||
| 110 | while (fgets(buf, sizeof(buf), fp) != NULL) { | ||
| 111 | count++; | ||
| 112 | if (IS_BOUNDARY(buf, boundary, boundary_len)) { | ||
| 113 | fputs(buf, outfp); | ||
| 114 | debug_print("start boundary: %s", buf); | ||
| 115 | break; | ||
| 116 | } else { | ||
| 117 | fputs(buf, outfp); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | debug_print("wrote %d lines\n", count); | ||
| 121 | } | ||
| 122 | |||
| 123 | if (partinfo->sub) { | ||
| 124 | debug_print("enter rfc822 -----------------------------\n"); | ||
| 125 | err = !remove_attachment_rec(partinfo->sub, fp, outfp); | ||
| 126 | debug_print("leave rfc822 -----------------------------\n"); | ||
| 127 | if (err) | ||
| 128 | break; | ||
| 129 | } else if (partinfo->children) { | ||
| 130 | debug_print("enter child -----------------------------\n"); | ||
| 131 | err = !remove_attachment_rec | ||
| 132 | (partinfo->children, fp, outfp); | ||
| 133 | debug_print("leave child -----------------------------\n"); | ||
| 134 | if (err) | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (partinfo->parent && partinfo->parent->boundary) { | ||
| 139 | boundary = partinfo->parent->boundary; | ||
| 140 | boundary_len = strlen(boundary); | ||
| 141 | debug_print("boundary = %s\n", boundary); | ||
| 142 | } else { | ||
| 143 | boundary = NULL; | ||
| 144 | boundary_len = 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | /* write (or skip) part body and end boundary */ | ||
| 148 | if (boundary && !partinfo->main) { | ||
| 149 | count = 0; | ||
| 150 | debug_print("write until %s\n", boundary); | ||
| 151 | while (fgets(buf, sizeof(buf), fp) != NULL) { | ||
| 152 | if (IS_BOUNDARY(buf, boundary, boundary_len)) { | ||
| 153 | count++; | ||
| 154 | fputs(buf, outfp); | ||
| 155 | debug_print("end boundary: %s", buf); | ||
| 156 | break; | ||
| 157 | } else { | ||
| 158 | if (!is_attach_part) | ||
| 159 | count++; | ||
| 160 | if (!is_attach_part) | ||
| 161 | fputs(buf, outfp); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | debug_print("wrote body: %d lines\n", count); | ||
| 165 | } | ||
| 166 | |||
| 167 | debug_print("------------------------------------------------- end %s\n", partinfo->content_type); | ||
| 168 | |||
| 169 | partinfo = partinfo->next; | ||
| 170 | } | ||
| 171 | |||
| 172 | return !err; | ||
| 173 | } | ||
| 174 | |||
| 175 | static gboolean has_attach_part(MimeInfo *mimeinfo) | ||
| 176 | { | ||
| 177 | for (; mimeinfo != NULL; mimeinfo = procmime_mimeinfo_next(mimeinfo)) { | ||
| 178 | if (mimeinfo->filename || mimeinfo->name) | ||
| 179 | return TRUE; | ||
| 180 | } | ||
| 181 | |||
| 182 | return FALSE; | ||
| 183 | } | ||
| 184 | |||
| 185 | static gboolean remove_attachment(MsgInfo *msginfo) | ||
| 186 | { | ||
| 187 | MimeInfo *mimeinfo; | ||
| 188 | FILE *fp, *outfp; | ||
| 189 | gchar *infile, *outfile; | ||
| 190 | gboolean err = FALSE; | ||
| 191 | |||
| 192 | mimeinfo = procmime_scan_message(msginfo); | ||
| 193 | g_return_val_if_fail(mimeinfo != NULL, FALSE); | ||
| 194 | |||
| 195 | if (!has_attach_part(mimeinfo)) { | ||
| 196 | debug_print("remove_attachment: this message doesn't have attachments\n"); | ||
| 197 | procmime_mimeinfo_free_all(mimeinfo); | ||
| 198 | return TRUE; | ||
| 199 | } | ||
| 200 | |||
| 201 | if ((fp = procmsg_open_message(msginfo)) == NULL) { | ||
| 202 | procmime_mimeinfo_free_all(mimeinfo); | ||
| 203 | return FALSE; | ||
| 204 | } | ||
| 205 | |||
| 206 | infile = procmsg_get_message_file(msginfo); | ||
| 207 | outfile = g_strconcat(infile, ".tmp", NULL); | ||
| 208 | debug_print("infile: %s\n", infile); | ||
| 209 | debug_print("outfile: %s\n", outfile); | ||
| 210 | |||
| 211 | if ((outfp = g_fopen(outfile, "wb")) == NULL) { | ||
| 212 | g_free(outfile); | ||
| 213 | g_free(infile); | ||
| 214 | fclose(fp); | ||
| 215 | procmime_mimeinfo_free_all(mimeinfo); | ||
| 216 | return FALSE; | ||
| 217 | } | ||
| 218 | |||
| 219 | err = !remove_attachment_rec(mimeinfo, fp, outfp); | ||
| 220 | |||
| 221 | if (fclose(outfp) == EOF) { | ||
| 222 | FILE_OP_ERROR(outfile, "fclose"); | ||
| 223 | err = TRUE; | ||
| 224 | } | ||
| 225 | |||
| 226 | fclose(fp); | ||
| 227 | |||
| 228 | if (!err) { | ||
| 229 | debug_print("overwriting original message file: %s\n", infile); | ||
| 230 | if (copy_file(outfile, infile, FALSE) == 0) { | ||
| 231 | GStatBuf s; | ||
| 232 | if (g_stat(infile, &s) == 0) { | ||
| 233 | msginfo->size = s.st_size; | ||
| 234 | msginfo->mtime = s.st_mtime; | ||
| 235 | } | ||
| 236 | if (msginfo->folder) | ||
| 237 | msginfo->folder->cache_dirty = TRUE; | ||
| 238 | } else | ||
| 239 | err = TRUE; | ||
| 240 | } | ||
| 241 | |||
| 242 | g_unlink(outfile); | ||
| 243 | g_free(outfile); | ||
| 244 | g_free(infile); | ||
| 245 | procmime_mimeinfo_free_all(mimeinfo); | ||
| 246 | |||
| 247 | return !err; | ||
| 248 | } | ||
| 249 | |||
| 250 | static void remove_attachment_cb(void) | ||
| 251 | { | ||
| 252 | FolderItem *item; | ||
| 253 | GSList *mlist, *cur; | ||
| 254 | gint val; | ||
| 255 | |||
| 256 | debug_print("remove_attachment_cb\n"); | ||
| 257 | |||
| 258 | if (syl_plugin_summary_is_locked()) | ||
| 259 | return; | ||
| 260 | |||
| 261 | item = syl_plugin_summary_get_current_folder(); | ||
| 262 | if (!item || !item->folder || FOLDER_TYPE(item->folder) != F_MH || | ||
| 263 | item->stype == F_VIRTUAL) { | ||
| 264 | syl_plugin_alertpanel_message(_("Error"), _("This tool is available on local folders only."), 3); | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | mlist = syl_plugin_summary_get_selected_msg_list(); | ||
| 269 | if (!mlist) | ||
| 270 | return; | ||
| 271 | |||
| 272 | val = syl_plugin_alertpanel(_("Remove attachments"), | ||
| 273 | _("Do you really remove attached files from the selected messages?"), | ||
| 274 | GTK_STOCK_YES, GTK_STOCK_NO, NULL); | ||
| 275 | if (val != 0) { | ||
| 276 | g_slist_free(mlist); | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | for (cur = mlist; cur != NULL; cur = cur->next) { | ||
| 281 | MsgInfo *msginfo = (MsgInfo *)cur->data; | ||
| 282 | |||
| 283 | if (!msginfo) | ||
| 284 | continue; | ||
| 285 | if (!MSG_IS_MIME(msginfo->flags)) { | ||
| 286 | debug_print("message %u is not multi-part. skipping.\n", msginfo->msgnum); | ||
| 287 | continue; | ||
| 288 | } | ||
| 289 | debug_print("Removing attachments of message: %u: %s\n", msginfo->msgnum, msginfo->subject ? msginfo->subject : "(No Subject)"); | ||
| 290 | |||
| 291 | if (!remove_attachment(msginfo)) { | ||
| 292 | g_warning("Cannot remove attachments from %u: %s\n", msginfo->msgnum, msginfo->subject ? msginfo->subject : "(No Subject)"); | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | |||
| 296 | syl_plugin_summary_update_by_msgnum(msginfo->msgnum); | ||
| 297 | } | ||
| 298 | |||
| 299 | g_slist_free(mlist); | ||
| 300 | |||
| 301 | syl_plugin_summary_redisplay_msg(); | ||
| 302 | } | ||
