src/mn-maildir-mailbox-backend.gob (7738B) - 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 "mn-vfs-mailbox-backend.h"
22 %}
23
24 %{
25 #include <string.h>
26 #include <stdlib.h>
27 #include <glib/gi18n.h>
28 #include "mn-mailbox-private.h"
29 #include "mn-reentrant-mailbox-private.h"
30 #include "mn-vfs-mailbox-backend-private.h"
31 #include "mn-vfs.h"
32 #include "mn-util.h"
33 #include "mn-message-mime.h"
34 #include "mn-maildir-message.h"
35 %}
36
37 class MN:Maildir:Mailbox:Backend from MN:VFS:Mailbox:Backend
38 {
39 class_init (class)
40 {
41 MN_VFS_MAILBOX_BACKEND_CLASS(class)->format = "Maildir";
42 }
43
44 override (MN:VFS:Mailbox:Backend) void
45 monitor_cb (MNVFSMailboxBackend *backend,
46 const char *info_uri,
47 GnomeVFSMonitorEventType event_type)
48 {
49 if (event_type == GNOME_VFS_MONITOR_EVENT_CHANGED
50 || event_type == GNOME_VFS_MONITOR_EVENT_DELETED
51 || event_type == GNOME_VFS_MONITOR_EVENT_CREATED)
52 {
53 char *filename;
54
55 filename = mn_vfs_uri_extract_short_name(info_uri);
56 if (filename)
57 {
58 if (filename[0] != '.')
59 mn_reentrant_mailbox_queue_check(MN_REENTRANT_MAILBOX(backend->mailbox));
60
61 g_free(filename);
62 }
63 }
64 }
65
66 private gboolean
67 dir_exists (MN:VFS:Mailbox *mailbox (check null type),
68 const char *name (check null))
69 {
70 GnomeVFSURI *dir_uri;
71 gboolean exists;
72
73 dir_uri = gnome_vfs_uri_append_path(mailbox->vfs_uri, name);
74 exists = mn_vfs_test(dir_uri, G_FILE_TEST_IS_DIR);
75 gnome_vfs_uri_unref(dir_uri);
76
77 return exists;
78 }
79
80 override (MN:VFS:Mailbox:Backend) gboolean
81 is (MNVFSMailboxBackend *dummy,
82 MNVFSMailboxBackendClass *class,
83 MNVFSMailbox *mailbox)
84 {
85 return self_dir_exists(mailbox, "cur")
86 && self_dir_exists(mailbox, "new")
87 && self_dir_exists(mailbox, "tmp");
88 }
89
90 private void
91 monitor_directory (self, int check_id, const char *dir (check null))
92 {
93 MNVFSMailboxBackend *backend = MN_VFS_MAILBOX_BACKEND(self);
94 GnomeVFSURI *uri;
95 char *text_uri;
96
97 uri = gnome_vfs_uri_append_path(backend->mailbox->vfs_uri, dir);
98 text_uri = gnome_vfs_uri_to_string(uri, GNOME_VFS_URI_HIDE_NONE);
99 gnome_vfs_uri_unref(uri);
100
101 mn_vfs_mailbox_backend_monitor(backend, check_id, text_uri, GNOME_VFS_MONITOR_DIRECTORY);
102 g_free(text_uri);
103 }
104
105 private gboolean
106 scan_directory (self,
107 int check_id,
108 const char *dir (check null),
109 gboolean new,
110 GSList **messages (check null),
111 int *num_errors (check null),
112 GError **err)
113 {
114 MNVFSMailboxBackend *backend = MN_VFS_MAILBOX_BACKEND(self);
115 GnomeVFSURI *uri;
116 GnomeVFSResult result;
117 GnomeVFSResult close_result;
118 GnomeVFSDirectoryHandle *handle;
119 GnomeVFSFileInfo *file_info;
120 gboolean aborted = FALSE;
121
122 uri = gnome_vfs_uri_append_path(backend->mailbox->vfs_uri, dir);
123
124 result = gnome_vfs_directory_open_from_uri(&handle, uri, GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
125 if (result != GNOME_VFS_OK)
126 {
127 g_set_error(err, 0, 0, _("unable to open folder \"%s\": %s"), dir, gnome_vfs_result_to_string(result));
128 gnome_vfs_uri_unref(uri);
129 return FALSE;
130 }
131
132 file_info = gnome_vfs_file_info_new();
133 while ((result = gnome_vfs_directory_read_next(handle, file_info)) == GNOME_VFS_OK)
134 if (file_info->name[0] != '.')
135 {
136 char *mid;
137 MNMessageFlags flags = 0;
138 MNVFSMessage *message = NULL;
139
140 if (mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
141 {
142 aborted = TRUE;
143 break;
144 }
145
146 if (new)
147 {
148 mid = g_strdup(file_info->name);
149 flags |= MN_MESSAGE_NEW;
150 }
151 else
152 {
153 char *info;
154
155 /* http://cr.yp.to/proto/maildir.html */
156
157 info = strrchr(file_info->name, ':');
158 if (! info
159 || ! g_str_has_prefix(info + 1, "2,")
160 || strpbrk(info + 3, "ST"))
161 continue; /* no info, or message seen/trashed: ignore it */
162
163 mid = g_strndup(file_info->name, info - file_info->name);
164 }
165
166 /*
167 * Hold the GDK lock while using
168 * mn_mailbox_get_message_from_mid(), since for
169 * MNReentrantMailbox, mail checks can run concurrently, so
170 * another check could be modifying the MID hash table.
171 */
172 GDK_THREADS_ENTER();
173
174 message = MN_VFS_MESSAGE(mn_mailbox_get_message_from_mid(MN_MAILBOX(backend->mailbox), mid));
175 if (message)
176 message = mn_vfs_message_new_from_message(message,
177 uri,
178 file_info->name,
179 flags);
180
181 gdk_flush();
182 GDK_THREADS_LEAVE();
183
184 if (! message)
185 {
186 GError *tmp_err = NULL;
187
188 message = mn_vfs_message_new(MN_TYPE_MAILDIR_MESSAGE,
189 backend,
190 mid,
191 uri,
192 file_info->name,
193 flags,
194 FALSE,
195 &tmp_err);
196
197 if (tmp_err)
198 {
199 GnomeVFSURI *message_uri;
200 char *message_text_uri;
201
202 message_uri = gnome_vfs_uri_append_file_name(uri, file_info->name);
203 message_text_uri = gnome_vfs_uri_to_string(message_uri, GNOME_VFS_URI_HIDE_PASSWORD);
204 gnome_vfs_uri_unref(message_uri);
205
206 mn_mailbox_warning(MN_MAILBOX(backend->mailbox), "cannot read message \"%s\": %s",
207 message_text_uri, tmp_err->message);
208 g_free(message_text_uri);
209 g_error_free(tmp_err);
210
211 (*num_errors)++;
212 }
213 }
214
215 g_free(mid);
216
217 if (message)
218 *messages = g_slist_prepend(*messages, message);
219 }
220 gnome_vfs_uri_unref(uri);
221 gnome_vfs_file_info_unref(file_info);
222 close_result = gnome_vfs_directory_close(handle);
223
224 if (! aborted)
225 {
226 if (result == GNOME_VFS_ERROR_EOF || result == GNOME_VFS_OK)
227 {
228 if (close_result == GNOME_VFS_OK)
229 return TRUE;
230 else
231 g_set_error(err, 0, 0, _("unable to close folder \"%s\": %s"), dir, gnome_vfs_result_to_string(close_result));
232 }
233 else
234 g_set_error(err, 0, 0, _("error while reading folder \"%s\": %s"), dir, gnome_vfs_result_to_string(result));
235 }
236
237 return FALSE;
238 }
239
240 override (MN:VFS:Mailbox:Backend) void
241 check (MNVFSMailboxBackend *backend, int check_id)
242 {
243 Self *self = SELF(backend);
244 GSList *messages = NULL;
245 GError *err = NULL;
246 int num_errors = 0;
247 gboolean status;
248
249 self_monitor_directory(self, check_id, "cur");
250 self_monitor_directory(self, check_id, "new");
251
252 status = self_scan_directory(self, check_id, "cur", FALSE, &messages, &num_errors, &err)
253 && self_scan_directory(self, check_id, "new", TRUE, &messages, &num_errors, &err);
254
255 GDK_THREADS_ENTER();
256
257 if (! mn_reentrant_mailbox_check_aborted(MN_REENTRANT_MAILBOX(backend->mailbox), check_id))
258 {
259 if (status)
260 {
261 mn_mailbox_set_messages(MN_MAILBOX(backend->mailbox), messages);
262
263 if (num_errors != 0)
264 mn_mailbox_set_error(MN_MAILBOX(backend->mailbox),
265 ngettext("cannot read %i message",
266 "cannot read %i messages",
267 num_errors),
268 num_errors);
269 }
270 else
271 mn_mailbox_set_error(MN_MAILBOX(backend->mailbox), "%s", err->message);
272 }
273
274 mn_g_object_slist_free(messages);
275
276 gdk_flush();
277 GDK_THREADS_LEAVE();
278
279 if (err)
280 g_error_free(err);
281 }
282 }