mail-notification

Fork of Jean-Yves Lefort's mail-notification, a tray icon to notify of new mail
git clone https://code.djc.id.au/git/mail-notification/

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 }