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-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 }