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-webmail-mailbox.gob (9324B) - 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-authenticated-mailbox.h"
     22 %}
     23 
     24 %{
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <sys/wait.h>
     28 #include <fcntl.h>
     29 #include <unistd.h>
     30 #include <errno.h>
     31 #include <glib/gi18n.h>
     32 #include <gmime/gmime.h>
     33 #include "mn-mailbox-private.h"
     34 #include "mn-authenticated-mailbox-private.h"
     35 #include "mn-message-mime.h"
     36 #include "mn-util.h"
     37 %}
     38 
     39 class MN:Webmail:Mailbox from MN:Authenticated:Mailbox (abstract)
     40 {
     41   classwide const char *default_domain;
     42 
     43   public char *folder destroywith g_free;
     44   property STRING folder (link,
     45 			  flags = CONSTRUCT
     46 			  | MN_MAILBOX_PARAM_LOAD_SAVE
     47 			  | MN_MAILBOX_PARAM_REQUIRED,
     48 			  default_value = "Inbox");
     49 
     50   override (MN:Mailbox) void
     51     seal (MNMailbox *mailbox)
     52   {
     53     MNAuthenticatedMailbox *auth_mailbox = MN_AUTHENTICATED_MAILBOX(mailbox);
     54     Self *self = SELF(mailbox);
     55 
     56     PARENT_HANDLER(mailbox);
     57 
     58     if (! mailbox->runtime_name)
     59       mailbox->runtime_name = self_build_name(SELF_GET_CLASS(self), MN_AUTHENTICATED_MAILBOX(mailbox)->username, self->folder);
     60 
     61     if (! auth_mailbox->keyring_domain)
     62       auth_mailbox->keyring_domain = g_strdup(MN_WEBMAIL_MAILBOX_CLASS(SELF_GET_CLASS(self))->default_domain);
     63   }
     64 
     65   protected void
     66     parse_username (self, char **username (check null), char **domain (check null))
     67   {
     68     mn_authenticated_mailbox_parse_username(MN_AUTHENTICATED_MAILBOX(self), username, domain);
     69     if (! *domain)
     70       *domain = g_strdup(MN_WEBMAIL_MAILBOX_CLASS(SELF_GET_CLASS(self))->default_domain);
     71   }
     72 
     73   private int
     74     create_temporary_file (char **filename (check null), GError **err)
     75   {
     76     int fd;
     77     char *_filename;
     78     GError *tmp_err = NULL;
     79 
     80     /* GetLive chokes on the hyphen in "mail-notification", so use "mn" */
     81     fd = g_file_open_tmp("mn.XXXXXX", &_filename, &tmp_err);
     82     if (fd == -1)
     83       {
     84 	g_set_error(err, 0, 0, _("unable to create a temporary file: %s"), tmp_err->message);
     85 	g_error_free(tmp_err);
     86 	return -1;
     87       }
     88 
     89     if (fchmod(fd, S_IRUSR | S_IWUSR) < 0)
     90       {
     91 	g_set_error(err, 0, 0, _("unable to change the permissions of the temporary file: %s"), g_strerror(errno));
     92 	g_free(_filename);
     93 	close(fd);
     94 	return -1;
     95       }
     96 
     97     *filename = _filename;
     98     return fd;
     99   }
    100 
    101   protected char *
    102     create_spool_file (GError **err)
    103   {
    104     int fd;
    105     char *filename;
    106 
    107     fd = self_create_temporary_file(&filename, err);
    108     if (fd == -1)
    109       return NULL;
    110 
    111     close(fd);
    112 
    113     return filename;
    114   }
    115 
    116   protected char *
    117     write_temporary_file (const char *contents (check null),
    118 			  const char *encoding (check null),
    119 			  GError **err)
    120   {
    121     int fd;
    122     GError *tmp_err = NULL;
    123     char *filename;
    124     GIOChannel *channel;
    125     gsize bytes_written;
    126 
    127     fd = self_create_temporary_file(&filename, err);
    128     if (fd == -1)
    129       return NULL;
    130 
    131     channel = g_io_channel_unix_new(fd);
    132 
    133     if (g_io_channel_set_encoding(channel, encoding, &tmp_err) != G_IO_STATUS_NORMAL)
    134       {
    135 	g_set_error(err, 0, 0, _("unable to set encoding of %s: %s"), filename, tmp_err->message);
    136 	goto error;
    137       }
    138 
    139     if (g_io_channel_write_chars(channel, contents, -1, &bytes_written, &tmp_err) != G_IO_STATUS_NORMAL)
    140       {
    141 	g_set_error(err, 0, 0, _("unable to write to %s: %s"), filename, tmp_err->message);
    142 	goto error;
    143       }
    144 
    145     if (g_io_channel_shutdown(channel, TRUE, &tmp_err) != G_IO_STATUS_NORMAL)
    146       {
    147 	g_set_error(err, 0, 0, _("unable to close %s: %s"), filename, tmp_err->message);
    148 	goto error_noshutdown;
    149       }
    150 
    151     g_io_channel_unref(channel);
    152 
    153     return filename;
    154 
    155   error:
    156     g_io_channel_shutdown(channel, FALSE, NULL);
    157   error_noshutdown:
    158     g_io_channel_unref(channel);
    159     g_free(filename);
    160     return NULL;
    161   }
    162 
    163   virtual private char *
    164     get_error_message (self,
    165 		       const char *helper_stdout,
    166 		       const char *helper_stderr,
    167 		       gboolean *is_auth_failure (check null));
    168 
    169   private void
    170     print_multiline_text (self,
    171 			  const char *text (check null),
    172 			  const char *line_prefix (check null))
    173   {
    174     char **lines;
    175     int i;
    176 
    177     lines = g_strsplit(text, "\n", 0);
    178     for (i = 0; lines[i]; i++)
    179       {
    180 	// do not print the empty last line
    181 	if (! lines[i + 1] && ! lines[i][0])
    182 	  break;
    183 
    184 	mn_mailbox_notice(MN_MAILBOX(self), "%s%s", line_prefix, lines[i]);
    185       }
    186     g_strfreev(lines);
    187   }
    188 
    189   protected void
    190     print_config (self, const char *config (check null))
    191   {
    192     mn_mailbox_notice(MN_MAILBOX(self), _("configuration:"));
    193     self_print_multiline_text(self, config, "> ");
    194   }
    195 
    196   private void
    197     print_output (self,
    198 		  const char *header (check null),
    199 		  const char *contents)
    200   {
    201     if (! contents || ! *contents)
    202       return;
    203 
    204     mn_mailbox_notice(MN_MAILBOX(self), "%s", header);
    205     self_print_multiline_text(self, contents, "< ");
    206   }
    207 
    208   protected gboolean
    209     run_helper (self,
    210 		const char *name (check null),
    211 		const char *command (check null),
    212 		GError **err)
    213   {
    214     GError *tmp_err = NULL;
    215     char *helper_stdout;
    216     char *helper_stderr;
    217     int exit_status;
    218     gboolean status = FALSE;
    219 
    220     mn_mailbox_notice(MN_MAILBOX(self), _("running %s"), command);
    221 
    222     if (! g_spawn_command_line_sync(command, &helper_stdout, &helper_stderr, &exit_status, &tmp_err))
    223       {
    224 	g_set_error(err, 0, 0, _("cannot execute \"%s\": %s"), name, tmp_err->message);
    225 	g_error_free(tmp_err);
    226 	return FALSE;
    227       }
    228 
    229     self_print_output(self, _("standard output:"), helper_stdout);
    230     self_print_output(self, _("standard error output:"), helper_stderr);
    231 
    232     if (WEXITSTATUS(exit_status) != 0)
    233       {
    234 	char *message;
    235 	gboolean is_auth_failure = FALSE;
    236 
    237 	message = self_get_error_message(self,
    238 					 helper_stdout,
    239 					 helper_stderr,
    240 					 &is_auth_failure);
    241 	if (message)
    242 	  {
    243 	    g_set_error(err, 0, 0, "%s", message);
    244 	    g_free(message);
    245 	  }
    246 	else
    247 	  /* translators: %s is a program name, as in "unknown fetchyahoo failure" */
    248 	  g_set_error(err, 0, 0, _("unknown %s failure"), name);
    249 
    250 	if (is_auth_failure && MN_AUTHENTICATED_MAILBOX(self)->auth_prompted)
    251 	  mn_authenticated_mailbox_auth_failed(MN_AUTHENTICATED_MAILBOX(self));
    252 
    253 	goto end;
    254       }
    255 
    256     status = TRUE;
    257 
    258   end:
    259     g_free(helper_stdout);
    260     g_free(helper_stderr);
    261 
    262     return status;
    263   }
    264 
    265   protected gboolean
    266     read_spool_file (self, const char *spool_file (check null), GError **err)
    267   {
    268     int fd;
    269     GMimeStream *stream;
    270     GMimeParser *parser;
    271     GSList *messages = NULL;
    272 
    273     fd = open(spool_file, O_RDONLY);
    274     if (fd < 0)
    275       {
    276 	g_set_error(err, 0, 0, _("unable to open %s: %s"), spool_file, strerror(errno));
    277 	return FALSE;
    278       }
    279 
    280     stream = g_mime_stream_fs_new(fd);
    281 
    282     parser = g_mime_parser_new_with_stream(stream);
    283     g_object_unref(stream);
    284     g_mime_parser_set_scan_from(parser, TRUE);
    285 
    286     while (! g_mime_parser_eos(parser))
    287       {
    288 	GMimeMessage *mime_message;
    289 
    290 	mime_message = g_mime_parser_construct_message(parser);
    291 	if (mime_message)
    292 	  {
    293 	    MNMessage *message;
    294 
    295 	    message = mn_message_new_from_mime_message(MN_MAILBOX(self), mime_message, NULL, 0, TRUE);
    296 	    g_object_unref(mime_message);
    297 
    298 	    if (message)
    299 	      messages = g_slist_prepend(messages, message);
    300 	  }
    301       }
    302 
    303     g_object_unref(parser);
    304 
    305     /* the fd is owned by the stream and closed by it */
    306 
    307     GDK_THREADS_ENTER();
    308 
    309     mn_mailbox_set_messages(MN_MAILBOX(self), messages);
    310     mn_g_object_slist_free(messages);
    311 
    312     gdk_flush();
    313     GDK_THREADS_LEAVE();
    314 
    315     return TRUE;
    316   }
    317 
    318   virtual private gboolean
    319     webmail_check (self, GError **err);
    320 
    321   override (MN:Authenticated:Mailbox) void
    322     authenticated_check (MNAuthenticatedMailbox *mailbox)
    323   {
    324     Self *self = SELF(mailbox);
    325     GError *err = NULL;
    326 
    327     PARENT_HANDLER(mailbox);
    328 
    329   again:
    330     if (! mn_authenticated_mailbox_fill_password(mailbox, TRUE))
    331       return;
    332 
    333     if (! self_webmail_check(self, &err))
    334       {
    335 	if (mailbox->auth_prompted && mailbox->auth_failed)
    336 	  {
    337 	    g_clear_error(&err);
    338 	    goto again;
    339 	  }
    340 
    341 	GDK_THREADS_ENTER();
    342 
    343 	mn_mailbox_set_error(MN_MAILBOX(self), "%s", err->message);
    344 	g_error_free(err);
    345 
    346 	gdk_flush();
    347 	GDK_THREADS_LEAVE();
    348       }
    349   }
    350 
    351   public char *
    352     build_name (MNWebmailMailboxClass *class (check null),
    353 		const char *username (check null),
    354 		const char *folder)
    355   {
    356     GString *name;
    357 
    358     name = g_string_new(NULL);
    359 
    360     if (strchr(username, '@'))
    361       g_string_append(name, username);
    362     else
    363       g_string_append_printf(name, "%s@%s", username, class->default_domain);
    364 
    365     if (folder && strcmp(folder, "Inbox"))
    366       g_string_append_printf(name, "/%s", folder);
    367 
    368     return g_string_free(name, FALSE);
    369   }
    370 }