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 }