src/mn-base-mbox-mailbox-backend.gob (10193B) - raw
1 /*
2 * Mail Notification
3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 %headertop{
21 #include <gmime/gmime.h>
22 #include "mn-vfs-mailbox-backend.h"
23 #include "mn-message.h"
24 %}
25
26 %{
27 #include <string.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtk.h>
30 #include "mn-mailbox-private.h"
31 #include "mn-reentrant-mailbox-private.h"
32 #include "mn-vfs-mailbox-backend-private.h"
33 #include "mn-message-mime.h"
34 #include "mn-gmime-stream-vfs.h"
35 #include "mn-util.h"
36 #include "mn-vfs.h"
37 #if WITH_MBOX
38 #include "mn-mbox-mailbox-backend.h"
39 #endif
40 #if WITH_MOZILLA
41 #include "mn-mozilla-mailbox-backend.h"
42 #endif
43 %}
44
45 class MN:Base:Mbox:Mailbox:Backend from MN:VFS:Mailbox:Backend (abstract)
46 {
47 private GnomeVFSURI *uri unrefwith gnome_vfs_uri_unref;
48 private GnomeVFSFileSize last_size;
49 private time_t last_mtime;
50 private time_t last_ctime;
51
52 private GMutex *mutex = {g_mutex_new()} destroywith g_mutex_free;
53
54 override (MN:VFS:Mailbox:Backend) gboolean
55 is (MNVFSMailboxBackend *dummy,
56 MNVFSMailboxBackendClass *class,
57 MNVFSMailbox *mailbox)
58 {
59 gboolean is = FALSE;
60 GnomeVFSURI *uri;
61 GnomeVFSFileInfo *file_info;
62
63 uri = gnome_vfs_uri_ref(mailbox->vfs_uri);
64 file_info = gnome_vfs_file_info_new();
65
66 if (gnome_vfs_get_file_info_uri(uri, file_info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS | GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
67 {
68 GnomeVFSURI *uncompressed_uri;
69
70 /* handle a compressed mailbox */
71 uncompressed_uri = self_get_uncompressed_uri(uri, file_info);
72 if (uncompressed_uri)
73 {
74 GnomeVFSFileInfo *uncompressed_file_info;
75
76 uncompressed_file_info = gnome_vfs_file_info_new();
77 if (gnome_vfs_get_file_info_uri(uncompressed_uri, uncompressed_file_info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS) == GNOME_VFS_OK)
78 {
79 gnome_vfs_file_info_unref(file_info);
80 file_info = uncompressed_file_info;
81
82 gnome_vfs_uri_unref(uri);
83 uri = uncompressed_uri;
84 }
85 else
86 {
87 gnome_vfs_file_info_unref(uncompressed_file_info);
88 gnome_vfs_uri_unref(uncompressed_uri);
89 }
90 }
91
92 if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) != 0
93 && file_info->type == GNOME_VFS_FILE_TYPE_REGULAR
94 && self_get_mailbox_type(uri) == G_TYPE_FROM_CLASS(class))
95 is = TRUE;
96 }
97
98 gnome_vfs_uri_unref(uri);
99 gnome_vfs_file_info_unref(file_info);
100
101 return is;
102 }
103
104 private GType
105 get_mailbox_type (GnomeVFSURI *uri (check null))
106 {
107 GMimeParser *parser;
108 GType type = 0;
109
110 parser = self_parser_new(uri, NULL);
111 if (parser)
112 {
113 if (g_mime_parser_eos(parser))
114 /*
115 * The file is empty. For now, treat it as a mbox mailbox
116 * or, if mbox support was not compiled in, as a Mozilla
117 * mailbox. Whenever the file grows, it will be checked
118 * again and at that point we will decide whether it is a
119 * mbox mailbox, a Mozilla mailbox or another type of file.
120 */
121 {
122 #if WITH_MBOX
123 type = MN_TYPE_MBOX_MAILBOX_BACKEND;
124 #elif WITH_MOZILLA
125 type = MN_TYPE_MOZILLA_MAILBOX_BACKEND;
126 #endif
127 }
128 else
129 {
130 /*
131 * The file is not empty. Decide whether it is a Mozilla
132 * mailbox or a mbox mailbox by checking if the first
133 * message has a X-Mozilla-Status header. If the first
134 * message cannot be parsed, then it is neither a Mozilla
135 * mailbox nor a mbox mailbox.
136 */
137
138 GMimeMessage *mime_message;
139
140 mime_message = g_mime_parser_construct_message(parser);
141 if (mime_message)
142 {
143 if (g_mime_message_get_header(mime_message, "X-Mozilla-Status"))
144 {
145 #if WITH_MOZILLA
146 type = MN_TYPE_MOZILLA_MAILBOX_BACKEND;
147 #endif
148 }
149 else
150 {
151 #if WITH_MBOX
152 type = MN_TYPE_MBOX_MAILBOX_BACKEND;
153 #endif
154 }
155 g_object_unref(mime_message);
156 }
157 }
158 g_object_unref(parser);
159 }
160
161 return type;
162 }
163
164 private GMimeParser *
165 parser_new (GnomeVFSURI *uri (check null), GnomeVFSResult *result)
166 {
167 GnomeVFSResult _result;
168 GnomeVFSHandle *handle;
169 GMimeParser *parser = NULL;
170
171 _result = gnome_vfs_open_uri(&handle, uri, GNOME_VFS_OPEN_READ);
172 if (_result == GNOME_VFS_OK)
173 {
174 GMimeStream *stream;
175
176 stream = mn_gmime_stream_vfs_new(handle, uri, &_result);
177 if (stream)
178 {
179 parser = g_mime_parser_new_with_stream(stream);
180 g_object_unref(stream);
181 g_mime_parser_set_scan_from(parser, TRUE);
182 }
183 }
184
185 if (result)
186 *result = _result;
187
188 return parser;
189 }
190
191 override (MN:VFS:Mailbox:Backend) void
192 check (MNVFSMailboxBackend *backend, int check_id)
193 {
194 Self *self = SELF(backend);
195 gboolean polled;
196 GMimeParser *parser;
197 GnomeVFSResult result;
198 gboolean uri_set;
199
200 mn_vfs_mailbox_backend_monitor(backend, check_id, backend->mailbox->uri, GNOME_VFS_MONITOR_FILE);
201
202 if (mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
203 return;
204
205 /* the poll property is protected by the GDK lock */
206 GDK_THREADS_ENTER();
207
208 polled = mn_mailbox_get_poll(MN_MAILBOX(backend->mailbox));
209
210 gdk_flush();
211 GDK_THREADS_LEAVE();
212
213 if (polled)
214 {
215 GnomeVFSFileInfo *file_info;
216 gboolean check;
217
218 /*
219 * We are here because the mailbox has to be polled; only
220 * check it if necessary.
221 */
222
223 file_info = gnome_vfs_file_info_new();
224 result = gnome_vfs_get_file_info_uri(backend->mailbox->vfs_uri, file_info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
225
226 g_mutex_lock(selfp->mutex);
227
228 if (result == GNOME_VFS_OK
229 && (file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0
230 && (file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME) != 0
231 && file_info->size == selfp->last_size
232 && file_info->mtime == selfp->last_mtime)
233 {
234 if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_CTIME) != 0)
235 check = file_info->ctime != selfp->last_ctime;
236 else
237 /*
238 * The ctime is often missing for remote mailboxes;
239 * since anyway the size and mtime do not have changed,
240 * we do not check the mailbox.
241 */
242 check = FALSE;
243 }
244 else
245 check = TRUE;
246
247 if (check)
248 {
249 selfp->last_size = file_info->size;
250 selfp->last_mtime = file_info->mtime;
251 selfp->last_ctime = file_info->ctime;
252
253 if (mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
254 check = FALSE;
255 }
256
257 g_mutex_unlock(selfp->mutex);
258
259 gnome_vfs_file_info_unref(file_info);
260
261 if (! check)
262 return;
263 }
264
265 g_mutex_lock(selfp->mutex);
266 uri_set = selfp->uri != NULL;
267 g_mutex_unlock(selfp->mutex);
268
269 if (! uri_set)
270 {
271 GnomeVFSFileInfo *file_info;
272 GnomeVFSURI *uri;
273 gboolean aborted;
274
275 file_info = gnome_vfs_file_info_new();
276 if (gnome_vfs_get_file_info_uri(backend->mailbox->vfs_uri, file_info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS | GNOME_VFS_FILE_INFO_GET_MIME_TYPE) == GNOME_VFS_OK)
277 uri = self_get_uncompressed_uri(backend->mailbox->vfs_uri, file_info);
278 gnome_vfs_file_info_unref(file_info);
279
280 if (! uri)
281 uri = gnome_vfs_uri_ref(backend->mailbox->vfs_uri);
282
283 g_mutex_lock(selfp->mutex);
284
285 if (! selfp->uri)
286 {
287 selfp->uri = uri;
288 uri = NULL;
289 }
290
291 aborted = mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id);
292
293 g_mutex_unlock(selfp->mutex);
294
295 if (uri)
296 gnome_vfs_uri_unref(uri);
297
298 if (aborted)
299 return;
300 }
301
302 parser = self_parser_new(selfp->uri, &result);
303 if (parser)
304 {
305 GSList *messages = NULL;
306
307 while (! g_mime_parser_eos(parser))
308 {
309 GMimeMessage *mime_message;
310
311 if (mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
312 break;
313
314 mime_message = g_mime_parser_construct_message(parser);
315 if (mime_message)
316 {
317 MNMessage *message;
318
319 message = self_get_new_message(self, mime_message);
320 g_object_unref(mime_message);
321
322 if (message)
323 messages = g_slist_prepend(messages, message);
324 }
325 }
326
327 g_object_unref(parser);
328
329 GDK_THREADS_ENTER();
330
331 if (! mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
332 mn_mailbox_set_messages(MN_MAILBOX(backend->mailbox), messages);
333
334 mn_g_object_slist_free(messages);
335
336 gdk_flush();
337 GDK_THREADS_LEAVE();
338
339 return; /* success */
340 }
341
342 if (! mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
343 {
344 GDK_THREADS_ENTER();
345
346 mn_mailbox_set_error(MN_MAILBOX(backend->mailbox), _("unable to open mailbox: %s"), gnome_vfs_result_to_string(result));
347
348 gdk_flush();
349 GDK_THREADS_LEAVE();
350 }
351 }
352
353 virtual private MNMessage *
354 get_new_message (self, GMime:Message *mime_message (check null type));
355
356 private GnomeVFSURI *
357 get_uncompressed_uri (GnomeVFSURI *uri (check null),
358 GnomeVFSFileInfo *file_info (check null))
359 {
360 if ((file_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) != 0 && file_info->mime_type)
361 {
362 /* compression methods supported by GnomeVFS */
363 static const struct
364 {
365 const char *mime_type;
366 const char *method;
367 } compressions[] = {
368 { "application/x-gzip", "gzip" },
369 { "application/x-bzip", "bzip2" }
370 };
371 int i;
372
373 for (i = 0; i < G_N_ELEMENTS(compressions); i++)
374 if (! strcmp(file_info->mime_type, compressions[i].mime_type))
375 {
376 char *str;
377 GnomeVFSURI *uncompressed_uri;
378
379 str = g_strdup_printf("%s%s:/", GNOME_VFS_URI_MAGIC_STR, compressions[i].method);
380 uncompressed_uri = gnome_vfs_uri_append_string(uri, str);
381 g_free(str);
382
383 return uncompressed_uri;
384 }
385 }
386
387 return NULL;
388 }
389 }