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-evolution-server.gob (10752B) - 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 <dbus/dbus-glib.h>
     22 %}
     23 
     24 %{
     25 #include <stdio.h>
     26 #include <libintl.h>
     27 #include <gobject/gvaluecollector.h>
     28 #include <libedataserver/eds-version.h>
     29 #include <camel/camel-folder.h>
     30 #if EDS_CHECK_VERSION(2,29,0)
     31 #include <shell/e-shell.h>
     32 #include <mail/e-mail-browser.h>
     33 #else
     34 #include <mail/em-folder-view.h>
     35 #include <mail/em-format.h>
     36 #include <mail/em-message-browser.h>
     37 #endif
     38 #include <mail/em-utils.h>
     39 #include <mail/mail-session.h>
     40 #include <mail/mail-tools.h>
     41 #include "mn-evolution.h"
     42 #include "mn-evolution-folder-tree-server.h"
     43 #include "mn-evolution-plugin.h"
     44 
     45 /* see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=208774 */
     46 static GHashTable *folders = NULL;
     47 
     48 typedef struct
     49 {
     50   char		*uri;
     51   CamelFolder	*folder;
     52 } FolderInfo;
     53 
     54 #define MN_EVOLUTION_SERVER_ERROR	(mn_evolution_server_error_quark())
     55 
     56 typedef enum
     57 {
     58   MN_EVOLUTION_SERVER_ERROR_FOLDER_NOT_FOUND,
     59   MN_EVOLUTION_SERVER_ERROR_MESSAGE_NOT_FOUND,
     60   MN_EVOLUTION_SERVER_ERROR_FOLDER_TREE_REGISTRATION_FAILED,
     61 } MNEvolutionServerError;
     62 %}
     63 
     64 %afterdecls{
     65 #include "mn-evolution-server-dbus.h"
     66 %}
     67 
     68 /*
     69  * We hold the GDK lock because Evolution is multi-threaded and D-Bus
     70  * interface methods are run from a main loop callback.
     71  */
     72 
     73 class MN:Evolution:Server from G:Object
     74 {
     75   signal NONE (STRING)
     76     void folder_changed (self, const char *uri (check null));
     77 
     78   signal NONE (STRING)
     79     void message_reading (self, const char *uri (check null));
     80 
     81   class_init (class)
     82   {
     83     dbus_g_object_type_install_info(TYPE_SELF, &dbus_glib_mn_evolution_server_object_info);
     84   }
     85 
     86   private GQuark
     87     error_quark (void)
     88   {
     89     return g_quark_from_static_string("mn-evolution-server-error");
     90   }
     91 
     92   private void
     93     cache_folder (const char *uri (check null),
     94 		  CamelFolder *folder (check null))
     95   {
     96     FolderInfo *info;
     97 
     98     info = g_new0(FolderInfo, 1);
     99     info->uri = g_strdup(uri);
    100     info->folder = folder;
    101 #if EDS_CHECK_VERSION(2,31,0)
    102     g_object_ref(folder);
    103 #else
    104     camel_object_ref(folder);
    105 #endif
    106 
    107     /* uncache the folder when it is deleted */
    108 #if EDS_CHECK_VERSION(2,31,0)
    109     g_signal_connect(folder, "deleted", G_CALLBACK(self_folder_deleted_cb), info);
    110 #else
    111     camel_object_hook_event(folder, "deleted", self_folder_deleted_cb, info);
    112 #endif
    113 
    114     g_hash_table_replace(folders, info->uri, info);
    115   }
    116 
    117   private void
    118     folder_info_free (FolderInfo *info (check null))
    119   {
    120 #if EDS_CHECK_VERSION(2,31,0)
    121     g_signal_handlers_disconnect_by_func(info->folder, self_folder_deleted_cb, info);
    122     g_object_unref(info->folder);
    123 #else
    124     camel_object_unhook_event(info->folder, "deleted", self_folder_deleted_cb, info);
    125     camel_object_unref(info->folder);
    126 #endif
    127     g_free(info->uri);
    128     g_free(info);
    129   }
    130 
    131   private void
    132     folder_deleted_cb (CamelObject *object,
    133 		       gpointer event_data,
    134 		       gpointer user_data)
    135   {
    136     FolderInfo *info = user_data;
    137     gboolean status;
    138 
    139     status = g_hash_table_remove(folders, info->uri);
    140     g_assert(status == TRUE);
    141   }
    142 
    143   private CamelFolder *
    144     lookup_folder (const char *uri (check null), GError **err)
    145   {
    146     CamelFolder *folder = NULL;
    147 
    148     if (folders)
    149       {
    150 	FolderInfo *info;
    151 
    152 	info = g_hash_table_lookup(folders, uri);
    153 	if (info)
    154 	  {
    155 	    folder = info->folder;
    156 #if EDS_CHECK_VERSION(2,31,0)
    157             g_object_ref(folder);
    158 #else
    159 	    camel_object_ref(folder);
    160 #endif
    161 	  }
    162       }
    163     else
    164       folders = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) self_folder_info_free);
    165 
    166     if (! folder)
    167       {
    168 	folder = mail_tool_uri_to_folder(uri, 0,
    169 #if EDS_CHECK_VERSION(2,91,0)
    170                 NULL,
    171 #endif
    172                 NULL);
    173 	if (folder)
    174 	  self_cache_folder(uri, folder);
    175 	else
    176 	  g_set_error(err,
    177 		      MN_EVOLUTION_SERVER_ERROR,
    178 		      MN_EVOLUTION_SERVER_ERROR_FOLDER_NOT_FOUND,
    179 		      dgettext(GETTEXT_PACKAGE, "folder not found"));
    180       }
    181 
    182     return folder;
    183   }
    184 
    185   private GValueArray *
    186     value_array_new (GType type, ...)
    187   {
    188     GValueArray *value_array;
    189     va_list args;
    190 
    191     value_array = g_value_array_new(0);
    192 
    193     va_start(args, type);
    194 
    195     while (type)
    196       {
    197 	GValue value = { 0, };
    198 	char *error = NULL;
    199 
    200 	g_value_init(&value, type);
    201 	G_VALUE_COLLECT(&value, args, 0, &error);
    202 	g_assert(error == NULL);
    203 
    204 	g_value_array_append(value_array, &value);
    205 	g_value_unset(&value);
    206 
    207 	type = va_arg(args, GType);
    208       }
    209 
    210     va_end(args);
    211 
    212     return value_array;
    213   }
    214 
    215   private GValueArray *
    216     camel_message_info_to_dbus_struct (CamelMessageInfo *info (check null))
    217   {
    218     const CamelSummaryMessageID *id;
    219     char hexhash[sizeof(CamelSummaryMessageID) * 2 + 1];
    220     int i;
    221 
    222     id = camel_message_info_message_id(info);
    223     for (i = 0; i < sizeof(id->id.hash); i++)
    224       sprintf(hexhash + i * 2, "%.2x", id->id.hash[i]);
    225 
    226     g_assert(camel_message_info_uid(info) != NULL);
    227 
    228     return self_value_array_new(/* char *uid */
    229 				G_TYPE_STRING, camel_message_info_uid(info),
    230 				/* unsigned int sent_time */
    231 				G_TYPE_UINT, (unsigned int) camel_message_info_date_sent(info),
    232 				/* unsigned int received_time */
    233 				G_TYPE_UINT, (unsigned int) camel_message_info_date_received(info),
    234 				/* char *id */
    235 				G_TYPE_STRING, hexhash,
    236 				/* char *from */
    237 				G_TYPE_STRING, camel_message_info_from(info),
    238 				/* char *subject */
    239 				G_TYPE_STRING, camel_message_info_subject(info),
    240 				(GType) 0);
    241   }
    242 
    243   private gboolean
    244     get_unseen_messages (self,
    245 			 const char *folder_uri (check null),
    246 			 GPtrArray **ret (check null),
    247 			 GError **err)
    248   {
    249     CamelFolder *folder;
    250 
    251     GDK_THREADS_ENTER();
    252 
    253     folder = self_lookup_folder(folder_uri, err);
    254     if (folder)
    255       {
    256 	GPtrArray *summary;
    257 	int i;
    258 
    259 	*ret = g_ptr_array_new();
    260 
    261 	summary = camel_folder_get_summary(folder);
    262 
    263 	for (i = 0; i < summary->len; i++)
    264 	  {
    265 #if EDS_CHECK_VERSION(2,23,5)
    266             char *uid = summary->pdata[i];
    267             CamelMessageInfo *info = camel_folder_get_message_info(folder, uid);
    268 #else
    269 	    CamelMessageInfo *info = summary->pdata[i];
    270 #endif
    271 
    272 	    if ((camel_message_info_flags(info) & CAMEL_MESSAGE_SEEN) == 0)
    273 	      g_ptr_array_add(*ret, self_camel_message_info_to_dbus_struct(info));
    274 	  }
    275 
    276 	camel_folder_free_summary(folder, summary);
    277 #if EDS_CHECK_VERSION(2,31,0)
    278         g_object_unref(folder);
    279 #else
    280 	camel_object_unref(folder);
    281 #endif
    282       }
    283 
    284     GDK_THREADS_LEAVE();
    285 
    286     return folder != NULL;
    287   }
    288 
    289   private gboolean
    290     get_folder_name (self,
    291 		     const char *folder_uri (check null),
    292 		     char **ret (check null),
    293 		     GError **err)
    294   {
    295     CamelFolder *folder;
    296 
    297     GDK_THREADS_ENTER();
    298 
    299     folder = self_lookup_folder(folder_uri, err);
    300     if (folder)
    301       {
    302 	*ret = g_strdup(camel_folder_get_name(folder));
    303 #if EDS_CHECK_VERSION(2,31,0)
    304         g_object_unref(folder);
    305 #else
    306 	camel_object_unref(folder);
    307 #endif
    308       }
    309 
    310     GDK_THREADS_LEAVE();
    311 
    312     return folder != NULL;
    313   }
    314 
    315   private gboolean
    316     open_message (self,
    317 		  const char *folder_uri (check null),
    318 		  const char *message_uid (check null),
    319 		  GError **err)
    320   {
    321     CamelFolder *folder;
    322 
    323     GDK_THREADS_ENTER();
    324 
    325     folder = self_lookup_folder(folder_uri, err);
    326     if (folder)
    327       {
    328 #if EDS_CHECK_VERSION(2,29,0)
    329         EShell *shell;
    330         EShellBackend *shell_backend;
    331         GtkWidget *browser;
    332 
    333         shell = e_shell_get_default ();
    334         shell_backend = e_shell_get_backend_by_name (shell, "mail");
    335 
    336         browser = e_mail_browser_new (shell_backend);
    337         e_mail_reader_set_folder (E_MAIL_READER (browser), folder, folder_uri);
    338         e_mail_reader_set_message (E_MAIL_READER (browser), message_uid);
    339         gtk_widget_show (browser);
    340 #else
    341 	GtkWidget *browser;
    342 
    343 	/* modelled after Evolution's handleuri_got_folder() */
    344 
    345 	browser = em_message_browser_window_new();
    346 
    347 	em_format_set_session((EMFormat *) ((EMFolderView *) browser)->preview, session);
    348 	em_folder_view_set_folder((EMFolderView *) browser, folder, folder_uri);
    349 	em_folder_view_set_message((EMFolderView *) browser, message_uid, FALSE);
    350 	gtk_widget_show(((EMMessageBrowser *) browser)->window);
    351 #endif
    352 
    353 #if EDS_CHECK_VERSION(2,31,0)
    354         g_object_unref(folder);
    355 #else
    356 	camel_object_unref(folder);
    357 #endif
    358       }
    359 
    360     GDK_THREADS_LEAVE();
    361 
    362     return folder != NULL;
    363   }
    364 
    365   private gboolean
    366     set_message_flags (self,
    367 		       const char *folder_uri (check null),
    368 		       const char *message_uid (check null),
    369 		       unsigned int flags,
    370 		       GError **err)
    371   {
    372     CamelFolder *folder;
    373     gboolean status = FALSE;
    374 
    375     GDK_THREADS_ENTER();
    376 
    377     folder = self_lookup_folder(folder_uri, err);
    378     if (folder)
    379       {
    380 	status = camel_folder_set_message_flags(folder, message_uid, flags, flags);
    381 #if EDS_CHECK_VERSION(2,31,0)
    382         g_object_unref(folder);
    383 #else
    384 	camel_object_unref(folder);
    385 #endif
    386 
    387 	if (! status)
    388 	  g_set_error(err,
    389 		      MN_EVOLUTION_SERVER_ERROR,
    390 		      MN_EVOLUTION_SERVER_ERROR_MESSAGE_NOT_FOUND,
    391 		      dgettext(GETTEXT_PACKAGE, "message not found"));
    392       }
    393 
    394     GDK_THREADS_LEAVE();
    395 
    396     return status;
    397   }
    398 
    399   private gboolean
    400     folder_tree_new (self, guint32 id, GError **err)
    401   {
    402     MNEvolutionFolderTreeServer *tree;
    403     char *service;
    404     char *path;
    405     GError *tmp_err = NULL;
    406     gboolean status;
    407 
    408     GDK_THREADS_ENTER();
    409 
    410     tree = mn_evolution_folder_tree_server_new(id);
    411 
    412     service = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_SERVICE, id);
    413     path = g_strdup_printf(MN_EVOLUTION_FOLDER_TREE_SERVER_PATH, id);
    414 
    415     status = mn_evolution_plugin_register_server(G_OBJECT(tree), service, path, &tmp_err);
    416 
    417     g_free(service);
    418     g_free(path);
    419 
    420     if (! status)
    421       {
    422 	/* unlikely to ever happen, not worth a translation */
    423 	g_set_error(err,
    424 		    MN_EVOLUTION_SERVER_ERROR,
    425 		    MN_EVOLUTION_SERVER_ERROR_FOLDER_TREE_REGISTRATION_FAILED,
    426 		    "cannot register folder tree server: %s", tmp_err->message);
    427 	g_error_free(tmp_err);
    428 	g_object_unref(tree);
    429       }
    430 
    431     GDK_THREADS_LEAVE();
    432 
    433     return status;
    434   }
    435 
    436   public MNEvolutionServer *
    437     new (void)
    438   {
    439     return GET_NEW;
    440   }
    441 }