Fixes a crash when saving attachments fails
[modest] / src / widgets / modest-msg-view-window.c
index 7afcfff..2271e1e 100644 (file)
 
 #ifdef MODEST_TOOLKIT_HILDON2
 #include <hildon/hildon.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#include <X11/XKBlib.h>
+#include <X11/Xdmcp.h>
 #endif
+
 #include <tny-camel-bs-mime-part.h>
 #include <tny-camel-bs-msg.h>
 
@@ -133,6 +138,7 @@ struct _ModestMsgViewWindowPrivate {
 
        gchar *msg_uid;
        TnyMimePart *other_body;
+       TnyMsg * top_msg;
 
        GSList *sighandlers;
 };
@@ -244,6 +250,11 @@ static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
                                                   gpointer userdata);
 static void update_branding (ModestMsgViewWindow *self);
 static void sync_flags      (ModestMsgViewWindow *self);
+static gboolean on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, 
+                                   GtkContainer *container, ModestMsgViewWindow *self);
+
+static gboolean on_realize (GtkWidget *widget,
+                           gpointer userdata);
 
 /* list my signals */
 enum {
@@ -502,12 +513,19 @@ modest_msg_view_window_init (ModestMsgViewWindow *obj)
        priv->remove_attachment_banner = NULL;
        priv->msg_uid = NULL;
        priv->other_body = NULL;
-       
+
        priv->sighandlers = NULL;
-       
+
        /* Init window */
        init_window (MODEST_MSG_VIEW_WINDOW(obj));
 
+#ifdef MODEST_TOOLKIT_HILDON2
+       /* Grab the zoom keys, it will be used for Zoom and not for
+          changing volume */
+       g_signal_connect (G_OBJECT (obj), "realize",
+                         G_CALLBACK (on_realize),
+                         NULL);
+#endif
 }
 
 static void
@@ -651,6 +669,11 @@ modest_msg_view_window_finalize (GObject *obj)
                priv->other_body = NULL;
        }
 
+       if (priv->top_msg != NULL) {
+               g_object_unref (priv->top_msg);
+               priv->top_msg = NULL;
+       }
+
        if (priv->header_model != NULL) {
                g_object_unref (priv->header_model);
                priv->header_model = NULL;
@@ -820,6 +843,8 @@ modest_msg_view_window_construct (ModestMsgViewWindow *self,
                          G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
        g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
                          G_CALLBACK (modest_ui_actions_on_limit_error), obj);
+       g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
+                         G_CALLBACK (on_handle_calendar), obj);
        g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
                          G_CALLBACK (on_fetch_image), obj);
 
@@ -900,6 +925,7 @@ modest_msg_view_window_new_with_header_model (TnyMsg *msg,
        modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
+       priv->top_msg = NULL;
 
        /* Remember the message list's TreeModel so we can detect changes
         * and change the list selection when necessary: */
@@ -978,6 +1004,7 @@ modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
        modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
+       priv->top_msg = NULL;
 
        is_merge = g_str_has_prefix (msg_uid, "merge:");
 
@@ -1058,6 +1085,7 @@ modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
        modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
+       priv->top_msg = NULL;
 
        /* Remember the message list's TreeModel so we can detect changes 
         * and change the list selection when necessary: */
@@ -1151,6 +1179,7 @@ modest_msg_view_window_new_for_search_result (TnyMsg *msg,
        modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
 
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
+       priv->top_msg = NULL;
 
        /* Remember that this is a search result, 
         * so we can disable some UI appropriately: */
@@ -1185,6 +1214,7 @@ modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
 ModestWindow *
 modest_msg_view_window_new_with_other_body (TnyMsg *msg, 
                                            TnyMimePart *other_body,
+                                           TnyMsg *top_msg,
                                            const gchar *modest_account_name,
                                            const gchar *mailbox,
                                            const gchar *msg_uid)
@@ -1206,6 +1236,11 @@ modest_msg_view_window_new_with_other_body (TnyMsg *msg,
        } else {
                tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
        }
+       if (top_msg) {
+               priv->top_msg = g_object_ref (top_msg);
+       } else {
+               priv->top_msg = NULL;
+       }
        update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
        update_branding (MODEST_MSG_VIEW_WINDOW (obj));
 
@@ -1220,12 +1255,13 @@ modest_msg_view_window_new_with_other_body (TnyMsg *msg,
 }
 
 ModestWindow *
-modest_msg_view_window_new_for_attachment (TnyMsg *msg, 
+modest_msg_view_window_new_for_attachment (TnyMsg *msg,
+                                          TnyMsg *top_msg,
                                           const gchar *modest_account_name,
                                           const gchar *mailbox,
                                           const gchar *msg_uid)
 {
-       return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
+       return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
 }
 
 static void
@@ -1532,6 +1568,21 @@ modest_msg_view_window_get_message (ModestMsgViewWindow *self)
        return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
 }
 
+TnyMsg*
+modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
+{
+       ModestMsgViewWindowPrivate *priv;
+       
+       g_return_val_if_fail (self, NULL);
+       
+       priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
+
+       if (priv->top_msg)
+               return g_object_ref (priv->top_msg);
+       else
+               return NULL;
+}
+
 const gchar*
 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
 {
@@ -2668,6 +2719,9 @@ on_decode_to_stream_async_handler (TnyMimePart *mime_part,
 {
        DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
        const gchar *content_type;
+       ModestMsgViewWindowPrivate *priv;
+
+       priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
 
        if (cancelled || err) {
                if (err) {
@@ -2705,6 +2759,7 @@ on_decode_to_stream_async_handler (TnyMimePart *mime_part,
 
                fd = g_open (helper->file_path, O_RDONLY, 0644);
                if (fd != -1) {
+                       TnyMsg *top_msg;
                        file_stream = tny_fs_stream_new (fd);
 
                        mgr = modest_runtime_get_window_mgr ();
@@ -2716,8 +2771,16 @@ on_decode_to_stream_async_handler (TnyMimePart *mime_part,
                                account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
 
                        msg = tny_camel_msg_new ();
-                       tny_camel_msg_parse ((TnyCamelMsg *) msg, file_stream);
-                       msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), account, mailbox, helper->attachment_uid);
+                       tny_camel_msg_parse (TNY_CAMEL_MSG (msg), file_stream);
+
+                       if (priv->top_msg)
+                               top_msg = g_object_ref (priv->top_msg);
+                       else
+                               top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
+
+                       msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg, 
+                                                                            account, mailbox, helper->attachment_uid);
+                       if (top_msg) g_object_unref (top_msg);
                        modest_window_set_zoom (MODEST_WINDOW (msg_win),
                                                modest_window_get_zoom (MODEST_WINDOW (helper->self)));
                        if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
@@ -2920,6 +2983,7 @@ modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
                if (found) {
                        g_debug ("window for this body is already being created");
                } else {
+                       TnyMsg *top_msg;
 
                        /* it's not found, so create a new window for it */
                        modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
@@ -2927,9 +2991,16 @@ modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
                        const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
                        if (!account)
                                account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
+
+                       if (priv->top_msg)
+                               top_msg = g_object_ref (priv->top_msg);
+                       else
+                               top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
                        
-                       msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
+                       msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
                                                                              account, mailbox, attachment_uid);
+
+                       if (top_msg) g_object_unref (top_msg);
                        
                        modest_window_set_zoom (MODEST_WINDOW (msg_win),
                                                modest_window_get_zoom (MODEST_WINDOW (window)));
@@ -2955,14 +3026,20 @@ modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
                         * thus, we don't do anything */
                        g_debug ("window for is already being created");
                } else {
+                       TnyMsg *top_msg;
                        /* it's not found, so create a new window for it */
                        modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
                        gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
                        const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
                        if (!account)
                                account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
-                       msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, 
-                                                                            mailbox, attachment_uid);
+                       if (priv->top_msg)
+                               top_msg = g_object_ref (priv->top_msg);
+                       else
+                               top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
+                       msg_win = modest_msg_view_window_new_for_attachment (
+                               TNY_MSG (mime_part), top_msg, account, 
+                               mailbox, attachment_uid);
                        modest_window_set_zoom (MODEST_WINDOW (msg_win),
                                                modest_window_get_zoom (MODEST_WINDOW (window)));
                        if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
@@ -3166,7 +3243,7 @@ save_mime_part_to_file (SaveMimePartInfo *info)
                if (written < 0) {
                        g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
 
-                       if ((error->domain == TNY_ERROR_DOMAIN) && 
+                       if (error && (error->domain == TNY_ERROR_DOMAIN) &&
                            (error->code == TNY_IO_ERROR_WRITE) &&
                            (errno == ENOSPC)) {
                                info->result = GNOME_VFS_ERROR_NO_SPACE;
@@ -3337,6 +3414,28 @@ save_attachments_response (GtkDialog *dialog,
        gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
+static gboolean
+msg_is_attachment (TnyList *mime_parts)
+{
+       TnyIterator *iter;
+       gboolean retval = FALSE;
+
+       if (tny_list_get_length (mime_parts) > 1)
+               return FALSE;
+
+       iter = tny_list_create_iterator (mime_parts);
+       if (iter) {
+               TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
+               if (part) {
+                       if (TNY_IS_MSG (part))
+                               retval = TRUE;
+                       g_object_unref (part);
+               }
+               g_object_unref (iter);
+       }
+       return retval;
+}
+
 void
 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, 
                                         TnyList *mime_parts)
@@ -3352,13 +3451,34 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
        priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
 
        if (mime_parts == NULL) {
+               gboolean allow_msgs = FALSE;
+
                /* In Hildon 2.2 save and delete operate over all the attachments as there's no
                 * selection available */
                mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
-               if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, FALSE)) {
+
+               /* Check if the message is composed by an unique MIME
+                  part whose content disposition is attachment. There
+                  could be messages like this:
+
+                  Date: Tue, 12 Jan 2010 20:40:59 +0000
+                  From: <sender@example.org>
+                  To: <recipient@example.org>
+                  Subject: no body
+                  Content-Type: image/jpeg
+                  Content-Disposition: attachment; filename="bug7718.jpeg"
+
+                  whose unique MIME part is the message itself whose
+                  content disposition is attachment
+               */
+               if (mime_parts && msg_is_attachment (mime_parts))
+                       allow_msgs = TRUE;
+
+               if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
                        g_object_unref (mime_parts);
                        return;
                }
+
                if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
                        if (mime_parts) {
                                g_object_unref (mime_parts);
@@ -4037,3 +4157,47 @@ sync_flags (ModestMsgViewWindow *self)
                g_object_unref (header);
        }
 }
+
+#ifdef MODEST_TOOLKIT_HILDON2
+static gboolean
+on_realize (GtkWidget *widget,
+           gpointer userdata)
+{
+       GdkDisplay *display;
+       Atom atom;
+       unsigned long val = 1;
+
+       display = gdk_drawable_get_display (widget->window);
+       atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
+       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+                        GDK_WINDOW_XID (widget->window), atom,
+                        XA_INTEGER, 32, PropModeReplace,
+                        (unsigned char *) &val, 1);
+
+       return FALSE;
+}
+#endif
+
+static gboolean
+on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
+{
+       const gchar *account_name;
+       ModestProtocolType proto_type;
+       ModestProtocol *protocol;
+       gboolean retval = FALSE;
+
+       account_name = modest_window_get_active_account (MODEST_WINDOW (self));
+       
+       /* Get proto */
+       proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (), 
+                                                           account_name);
+       protocol = 
+               modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (), 
+                                                              proto_type);
+
+       if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
+               retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
+                                                                 calendar_part, container);
+       }
+       return retval;
+}