summaryrefslogtreecommitdiff
path: root/plugin/attachment_tool/attachment_tool.c
diff options
context:
space:
mode:
authorSimeon Simeonov2018-02-26 11:23:00 +0100
committerSimeon Simeonov2018-02-26 11:23:00 +0100
commit0b3cbf57875fd692e4ba0b336fefa4bee1ed00dc (patch)
treeaf916a30553c78ce9d4f2d8658656a175c5b6921 /plugin/attachment_tool/attachment_tool.c
Initial commit for sylpheed 3.7.0
Diffstat (limited to 'plugin/attachment_tool/attachment_tool.c')
-rw-r--r--plugin/attachment_tool/attachment_tool.c302
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
36static SylPluginInfo info = {
37 "Attachment Tool Plug-in",
38 "0.1.0",
39 "Hiroyuki Yamamoto",
40 "Attachment processing plug-in for Sylpheed"
41};
42
43static void remove_attachment_cb(void);
44
45void 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
55void plugin_unload(void)
56{
57 debug_print("attachment_tool plug-in unloaded.\n");
58}
59
60SylPluginInfo *plugin_info(void)
61{
62 return &info;
63}
64
65gint plugin_interface_version(void)
66{
67 return SYL_PLUGIN_INTERFACE_VERSION;
68}
69
70static 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
175static 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
185static 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
250static 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}