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-pi-mailbox.gob (10242B) - 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 %h{
     25 #define MN_PI_MAILBOX_N_CONNECTION_TYPES	3
     26 %}
     27 
     28 %privateheader{
     29 #include <gtk/gtk.h>
     30 #include "mn-client-session.h"
     31 
     32 #define MN_PI_MAILBOX_SESSION_PRIVATE \
     33   MNMailbox			*mailbox;	\
     34   MNAuthenticatedMailbox	*auth_mailbox;	\
     35   MNPIMailbox			*pi_mailbox;	\
     36   MNClientSession		*session
     37 %}
     38 
     39 %{
     40 #include <glib/gi18n.h>
     41 #include "mn-authenticated-mailbox-private.h"
     42 #include "mn-mailbox-private.h"
     43 #include "mn-util.h"
     44 #include "mn-stock.h"
     45 #include "mn-conf.h"
     46 
     47 struct _MNClientSessionPrivate
     48 {
     49   MN_PI_MAILBOX_SESSION_PRIVATE;
     50 };
     51 %}
     52 
     53 enum MN_PI_MAILBOX_CONNECTION_TYPE
     54 {
     55   NORMAL,
     56   INBAND_SSL,
     57   SSL,
     58 } MN:PI:Mailbox:Connection:Type;
     59 
     60 class MN:PI:Mailbox from MN:Authenticated:Mailbox (abstract)
     61 {
     62   classwide int *default_ports;
     63 
     64   public MNPIMailboxConnectionType connection_type;
     65   property ENUM connection_type (link,
     66 				 enum_type = MN:PI:Mailbox:Connection:Type,
     67 				 flags = CONSTRUCT | MN_MAILBOX_PARAM_LOAD_SAVE,
     68 				 default_value = MN_PI_MAILBOX_CONNECTION_TYPE_NORMAL);
     69 
     70   public char *authmech destroywith g_free;
     71   property STRING authmech (link, flags = MN_MAILBOX_PARAM_LOAD_SAVE);
     72 
     73   /* named hostname and not server for historical reasons */
     74   public char *hostname destroywith g_free;
     75   property STRING hostname (link, flags = MN_MAILBOX_PARAM_LOAD_SAVE | MN_MAILBOX_PARAM_REQUIRED);
     76 
     77   public int port;
     78   property INT port (link,
     79 		     flags = MN_MAILBOX_PARAM_LOAD_SAVE,
     80 		     minimum = 0,
     81 		     maximum = 65535);
     82 
     83   public int runtime_port;
     84 
     85   private GtkWidget *untrusted_dialog;
     86 
     87   class_init (class)
     88   {
     89     /*
     90      * 5 minutes is a good default check delay for remote POP3/IMAP
     91      * mailboxes.
     92      */
     93     MN_MAILBOX_CLASS(class)->default_check_delay = 60 * 5;
     94   }
     95 
     96   init (self)
     97   {
     98     mn_mailbox_set_stock_id(MN_MAILBOX(self), MN_STOCK_REMOTE);
     99   }
    100 
    101   override (MN:Mailbox) void
    102     seal (MNMailbox *mailbox)
    103   {
    104     MNAuthenticatedMailbox *auth_mailbox = MN_AUTHENTICATED_MAILBOX(mailbox);
    105     Self *self = SELF(mailbox);
    106 
    107     PARENT_HANDLER(mailbox);
    108 
    109     /* do not save default port to mailboxes.xml */
    110     if (self->port == SELF_GET_CLASS(self)->default_ports[self->connection_type])
    111       self->port = 0;
    112 
    113     self->runtime_port = self->port == 0
    114       ? SELF_GET_CLASS(self)->default_ports[self->connection_type]
    115       : self->port;
    116 
    117     auth_mailbox->keyring_server = g_strdup(self->hostname);
    118     auth_mailbox->keyring_port = self->runtime_port;
    119   }
    120 
    121   override (MN:Mailbox) void
    122     removed (MNMailbox *mailbox)
    123   {
    124     Self *self = SELF(mailbox);
    125 
    126     PARENT_HANDLER(mailbox);
    127 
    128     if (selfp->untrusted_dialog)
    129       gtk_dialog_response(GTK_DIALOG(selfp->untrusted_dialog), GTK_RESPONSE_CANCEL);
    130   }
    131 
    132   override (MN:Authenticated:Mailbox) void
    133     authenticated_check (MNAuthenticatedMailbox *mailbox)
    134   {
    135 #if ! WITH_SSL
    136     Self *self = SELF(mailbox);
    137 #endif
    138 
    139     PARENT_HANDLER(mailbox);
    140 
    141 #if ! WITH_SSL
    142     if (self->connection_type == MN_PI_MAILBOX_CONNECTION_TYPE_INBAND_SSL
    143 	|| self->connection_type == MN_PI_MAILBOX_CONNECTION_TYPE_SSL)
    144       {
    145 	GDK_THREADS_ENTER();
    146 
    147 	mn_mailbox_set_error(MN_MAILBOX(mailbox), _("SSL/TLS support has not been compiled in"));
    148 	mn_mailbox_set_poll(MN_MAILBOX(mailbox), FALSE); /* disable the mailbox */
    149 
    150 	gdk_flush();
    151 	GDK_THREADS_LEAVE();
    152       }
    153 #endif
    154   }
    155 
    156   protected gboolean
    157     split_uri (const char *uri (check null),
    158 	       int maxlen,
    159 	       char *scheme (check null),
    160 	       char *auth (check null),
    161 	       char *location (check null))
    162   {
    163     char *pat;
    164     int n;
    165 
    166     pat = g_strdup_printf("%%%i[^:]://%%%i[^@]@%%%is", maxlen, maxlen, maxlen);
    167     n = sscanf(uri, pat, scheme, auth, location);
    168     g_free(pat);
    169 
    170     return n == 3;	/* MN requires an username, hence the auth part */
    171   }
    172 
    173   protected gboolean
    174     split_uri_auth (const char *auth (check null),
    175 		    int maxlen,
    176 		    char *username (check null),
    177 		    char *authmech (check null),
    178 		    gboolean *has_authmech (check null))
    179   {
    180     char *pat;
    181     int n;
    182 
    183     pat = g_strdup_printf("%%%i[^;];AUTH=%%%is", maxlen, maxlen);
    184     n = sscanf(auth, pat, username, authmech);
    185     g_free(pat);
    186 
    187     if (n < 1)
    188       return FALSE;		/* MN requires an username */
    189 
    190     *has_authmech = n == 2;
    191 
    192     return TRUE;
    193   }
    194 
    195   protected void
    196     split_uri_hostport (const char *hostport (check null),
    197 			int maxlen,
    198 			char *hostname (check null),
    199 			int *port (check null))
    200   {
    201     char *pat;
    202     int n;
    203 
    204     /* split host:port part in 2 subparts: host and port */
    205 
    206     pat = g_strdup_printf("[%%%i[^]]]:%%u", maxlen);
    207     n = sscanf(hostport, pat, hostname, port);
    208     g_free(pat);
    209 
    210     if (n < 1)
    211       {
    212 	pat = g_strdup_printf("%%%i[^:]:%%u", maxlen);
    213 	n = sscanf(hostport, pat, hostname, port);
    214 	g_free(pat);
    215       }
    216 
    217     g_assert(n >= 1);
    218 
    219     if (n < 2)
    220       *port = 0;
    221   }
    222 
    223   protected void
    224     session_private_init (self, MNClientSessionPrivate *priv (check null))
    225   {
    226     priv->mailbox = MN_MAILBOX(self);
    227     priv->auth_mailbox = MN_AUTHENTICATED_MAILBOX(self);
    228     priv->pi_mailbox = MN_PI_MAILBOX(self);
    229   }
    230 
    231   protected gboolean
    232     sasl_get_credentials_cb (MNClientSession *session,
    233 			     MNClientSessionPrivate *priv,
    234 			     const char **username,
    235 			     const char **password)
    236   {
    237 #if WITH_SASL
    238     g_return_val_if_fail(username != NULL || password != NULL, FALSE);
    239 
    240     if (username)
    241       *username = priv->auth_mailbox->username;
    242 
    243     if (password)
    244       {
    245 	if (mn_authenticated_mailbox_fill_password(priv->auth_mailbox, TRUE))
    246 	  *password = priv->auth_mailbox->runtime_password;
    247 	else
    248 	  return FALSE;
    249       }
    250     else
    251       /*
    252        * Reset auth_cancelled ourselves since we did not call
    253        * mn_authenticated_mailbox_fill_password().
    254        */
    255       priv->auth_mailbox->auth_cancelled = FALSE;
    256 
    257     return TRUE;
    258 #else
    259     g_assert_not_reached();
    260     return FALSE;
    261 #endif /* WITH_SASL */
    262   }
    263 
    264   protected gboolean
    265     ssl_trust_server_cb (MNClientSession *session,
    266 			 const char *server,
    267 			 int port,
    268 			 const char *fingerprint,
    269 			 const char *verify_error,
    270 			 MNClientSessionPrivate *priv)
    271   {
    272 #if WITH_SSL
    273     gboolean status = FALSE;
    274 
    275     if (fingerprint)
    276       {
    277 	GSList *gconf_fingerprints;
    278 
    279 	gconf_fingerprints = mn_conf_get_string_list(MN_CONF_TRUSTED_X509_CERTIFICATES);
    280 
    281 	if (mn_g_str_slist_find(gconf_fingerprints, fingerprint))
    282 	  status = TRUE;
    283 	else
    284 	  if (self_run_untrusted_dialog(priv->pi_mailbox, server, verify_error, fingerprint))
    285 	    {
    286 	      status = TRUE;
    287 	      gconf_fingerprints = g_slist_append(gconf_fingerprints, g_strdup(fingerprint));
    288 	      mn_conf_set_string_list(MN_CONF_TRUSTED_X509_CERTIFICATES, gconf_fingerprints);
    289 	    }
    290 
    291 	mn_g_slist_free_deep(gconf_fingerprints);
    292       }
    293     else
    294       {
    295 	char *key;
    296 	GSList *gconf_servers = NULL;
    297 
    298 	key = g_strdup_printf("%s:%i", server, port);
    299 	gconf_servers = mn_conf_get_string_list(MN_CONF_TRUSTED_SERVERS);
    300 
    301 	if (mn_g_str_slist_find(gconf_servers, key))
    302 	  status = TRUE;
    303 	else
    304 	  {
    305 	    if (self_run_untrusted_dialog(priv->pi_mailbox, server, _("missing certificate"), NULL))
    306 	      {
    307 		status = TRUE;
    308 		gconf_servers = g_slist_append(gconf_servers, g_strdup(key));
    309 		mn_conf_set_string_list(MN_CONF_TRUSTED_SERVERS, gconf_servers);
    310 	      }
    311 	  }
    312 
    313 	g_free(key);
    314 	mn_g_slist_free_deep(gconf_servers);
    315       }
    316 
    317     return status;
    318 #else
    319     g_assert_not_reached();
    320     return FALSE;
    321 #endif /* WITH_SSL */
    322   }
    323 
    324   private gboolean
    325     run_untrusted_dialog (self,
    326 			  const char *server (check null),
    327 			  const char *reason (check null),
    328 			  const char *cert_fingerprint)
    329   {
    330 #if WITH_SSL
    331     GString *secondary;
    332     gboolean status;
    333 
    334     g_return_val_if_fail(server != NULL, FALSE);
    335     g_return_val_if_fail(reason != NULL, FALSE);
    336 
    337     secondary = g_string_new(NULL);
    338     g_string_printf(secondary,
    339 		    _("Mail Notification was unable to trust \"%s\" "
    340 		      "(%s). It is possible that someone is "
    341 		      "intercepting your communication to obtain "
    342 		      "your confidential information.\n"
    343 		      "\n"
    344 		      "You should only connect to the server if you "
    345 		      "are certain you are connected to \"%s\". "
    346 		      "If you choose to connect to the server, this "
    347 		      "message will not be shown again."),
    348 		    server, reason, server);
    349 
    350     if (cert_fingerprint)
    351       {
    352 	g_string_append(secondary, "\n\n");
    353 	g_string_append_printf(secondary, _("Certificate fingerprint: %s."), cert_fingerprint);
    354       }
    355 
    356     GDK_THREADS_ENTER();
    357 
    358     selfp->untrusted_dialog = mn_alert_dialog_new(NULL,
    359 						  GTK_MESSAGE_WARNING, 0,
    360 						  _("Connect to untrusted server?"),
    361 						  secondary->str);
    362     g_string_free(secondary, TRUE);
    363 
    364     mn_add_weak_pointer(&selfp->untrusted_dialog);
    365 
    366     gtk_dialog_add_buttons(GTK_DIALOG(selfp->untrusted_dialog),
    367 			   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    368 			   GTK_STOCK_CONNECT, GTK_RESPONSE_OK,
    369 			   NULL);
    370 
    371     status = mn_dialog_run_nonmodal(GTK_DIALOG(selfp->untrusted_dialog)) == GTK_RESPONSE_OK;
    372     gtk_widget_destroy(selfp->untrusted_dialog);
    373 
    374     gdk_flush();
    375     GDK_THREADS_LEAVE();
    376 
    377     return status;
    378 #else
    379     g_assert_not_reached();
    380     return FALSE;
    381 #endif /* WITH_SSL */
    382   }
    383 
    384   protected void
    385     notice_cb (MNClientSession *session,
    386 	       const char *message,
    387 	       MNClientSessionPrivate *priv)
    388   {
    389     mn_mailbox_notice(priv->mailbox, "%s", message);
    390   }
    391 
    392   protected void
    393     warning_cb (MNClientSession *session,
    394 		const char *message,
    395 		MNClientSessionPrivate *priv)
    396   {
    397     mn_mailbox_warning(priv->mailbox, "%s", message);
    398   }
    399 }