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 }