Statistics
| Revision:

root / plugin / attachment_tool / attachment_tool.c @ 3300

History | View | Annotate | Download (7.5 KB)

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
                        struct stat 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
}