Fix bug 3793: segfault when autocompletion asks for master passphrase
[claws.git] / src / compose.c
index 4ff2363c962f2ad2aab16595afe5fb28f80d43f6..e52f46744423498e06f6f6be675147cf71003007 100644 (file)
 #include "autofaces.h"
 #include "spell_entry.h"
 #include "headers.h"
+#ifdef USE_LDAP
+#include "password.h"
+#include "ldapserver.h"
+#endif
 
 enum
 {
@@ -1084,6 +1088,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
                        else
                                gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
                        quote_fmt_reset_vartable();
+                       quote_fmtlex_destroy();
 
                        g_free(tmp);
                }
@@ -1177,6 +1182,7 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
                                gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
                        compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
                        quote_fmt_reset_vartable();
+                       quote_fmtlex_destroy();
 
                        g_free(subject);
                        g_free(tmp);
@@ -1224,7 +1230,10 @@ Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderI
 
                for (curr = attach_files ; curr != NULL ; curr = curr->next) {
                        ainfo = (AttachInfo *) curr->data;
-                       compose_attach_append(compose, ainfo->file, ainfo->file,
+                       if (ainfo->insert)
+                               compose_insert_file(compose, ainfo->file);
+                       else
+                               compose_attach_append(compose, ainfo->file, ainfo->file,
                                        ainfo->content_type, ainfo->charset);
                }
        }
@@ -1652,6 +1661,7 @@ static Compose *compose_generic_reply(MsgInfo *msginfo,
                else
                        gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
                quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
 
                g_free(tmp);
        }
@@ -1834,6 +1844,7 @@ Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
                else
                        gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
                quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
 
                g_free(tmp);
                procmsg_msginfo_free(&full_msginfo);
@@ -2025,6 +2036,7 @@ static Compose *compose_forward_multiple(PrefsAccount *account, GSList *msginfo_
                        else
                                gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
                        quote_fmt_reset_vartable();
+                       quote_fmtlex_destroy();
 
                        g_free(tmp);
                }
@@ -3125,6 +3137,7 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                quote_fmt_parse();
 
                buf = quote_fmt_get_buffer();
+
                if (buf == NULL)
                        alertpanel_error(_("The \"Quotation mark\" of the template is invalid."));
                else
@@ -3158,11 +3171,14 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
                }
 
                buf = quote_fmt_get_buffer();
+
                if (buf == NULL) {
                        gint line = quote_fmt_get_line();
                        alertpanel_error(err_msg, line);
+
                        goto error;
                }
+
        } else
                buf = "";
 
@@ -3621,31 +3637,58 @@ static ComposeInsertResult compose_insert_file(Compose *compose, const gchar *fi
        gint len;
        FILE *fp;
        gboolean prev_autowrap;
+#ifdef G_OS_WIN32
+       GFile *f;
+       GFileInfo *fi;
+       GError *error = NULL;
+#else
        GStatBuf file_stat;
+#endif
        int ret;
+       goffset size;
        GString *file_contents = NULL;
        ComposeInsertResult result = COMPOSE_INSERT_SUCCESS;
 
        cm_return_val_if_fail(file != NULL, COMPOSE_INSERT_NO_FILE);
 
        /* get the size of the file we are about to insert */
+#ifdef G_OS_WIN32
+       f = g_file_new_for_path(file);
+       fi = g_file_query_info(f, "standard::size",
+                       G_FILE_QUERY_INFO_NONE, NULL, &error);
+       ret = 0;
+       if (error != NULL) {
+               g_warning(error->message);
+               ret = 1;
+               g_error_free(error);
+               g_object_unref(f);
+       }
+#else
        ret = g_stat(file, &file_stat);
+#endif
        if (ret != 0) {
                gchar *shortfile = g_path_get_basename(file);
                alertpanel_error(_("Could not get size of file '%s'."), shortfile);
                g_free(shortfile);
                return COMPOSE_INSERT_NO_FILE;
        } else if (prefs_common.warn_large_insert == TRUE) {
+#ifdef G_OS_WIN32
+               size = g_file_info_get_size(fi);
+               g_object_unref(fi);
+               g_object_unref(f);
+#else
+               size = file_stat.st_size;
+#endif
 
                /* ask user for confirmation if the file is large */
                if (prefs_common.warn_large_insert_size < 0 ||
-                   file_stat.st_size > (prefs_common.warn_large_insert_size * 1024)) {
+                   size > ((goffset) prefs_common.warn_large_insert_size * 1024)) {
                        AlertValue aval;
                        gchar *msg;
 
                        msg = g_strdup_printf(_("You are about to insert a file of %s "
                                                "in the message body. Are you sure you want to do that?"),
-                                               to_human_readable(file_stat.st_size));
+                                               to_human_readable(size));
                        aval = alertpanel_full(_("Are you sure?"), msg, GTK_STOCK_CANCEL,
                                        g_strconcat("+", _("_Insert"), NULL), NULL, TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
                        g_free(msg);
@@ -5160,6 +5203,7 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_everythin
                                               GTK_STOCK_CANCEL, button_label, NULL, TRUE, NULL,
                                               ALERT_QUESTION, G_ALERTDEFAULT);
                        g_free(message);
+                       g_free(button_label);
                        if (aval & G_ALERTDISABLE) {
                                aval &= ~G_ALERTDISABLE;
                                prefs_common.warn_empty_subj = FALSE;
@@ -5183,9 +5227,9 @@ static gboolean compose_check_entries(Compose *compose, gboolean check_everythin
                        entry = gtk_editable_get_chars(GTK_EDITABLE(((ComposeHeaderEntry *)list->data)->entry), 0, -1);
                        g_strstrip(header);
                        g_strstrip(entry);
-                       if ((entry[0] != '\0')
-                       &&      (strcmp(header, prefs_common_translated_header_name("To:"))
-                       ||  strcmp(header, prefs_common_translated_header_name("Cc:")))) {
+                       if ((entry[0] != '\0') &&
+                           (!strcmp(header, prefs_common_translated_header_name("To:")) ||
+                            !strcmp(header, prefs_common_translated_header_name("Cc:")))) {
                                cnt++;
                        }
                        g_free(header);
@@ -5670,6 +5714,7 @@ static gint compose_write_to_file(Compose *compose, FILE *fp, gint action, gbool
                if (*chars != '\n') {
                        gtk_text_buffer_insert(buffer, &end, "\n", 1);
                }
+               g_free(chars);
        }
 
        /* get all composed text */
@@ -6311,7 +6356,14 @@ static int compose_add_attachments(Compose *compose, MimeInfo *parent)
        AttachInfo *ainfo;
        GtkTreeView *tree_view = GTK_TREE_VIEW(compose->attach_clist);
        MimeInfo *mimepart;
+#ifdef G_OS_WIN32
+       GFile *f;
+       GFileInfo *fi;
+       GError *error = NULL;
+#else
        GStatBuf statbuf;
+#endif
+       goffset size;
        gchar *type, *subtype;
        GtkTreeModel *model;
        GtkTreeIter iter;
@@ -6333,15 +6385,31 @@ static int compose_add_attachments(Compose *compose, MimeInfo *parent)
                        }
                        continue;
                }
+#ifdef G_OS_WIN32
+               f = g_file_new_for_path(ainfo->file);
+               fi = g_file_query_info(f, "standard::size",
+                               G_FILE_QUERY_INFO_NONE, NULL, &error);
+               if (error != NULL) {
+                       g_warning(error->message);
+                       g_error_free(error);
+                       g_object_unref(f);
+                       return -1;
+               }
+               size = g_file_info_get_size(fi);
+               g_object_unref(fi);
+               g_object_unref(f);
+#else
                if (g_stat(ainfo->file, &statbuf) < 0)
                        return -1;
+               size = statbuf.st_size;
+#endif
 
                mimepart = procmime_mimeinfo_new();
                mimepart->content = MIMECONTENT_FILE;
                mimepart->data.filename = g_strdup(ainfo->file);
                mimepart->tmp = FALSE; /* or we destroy our attachment */
                mimepart->offset = 0;
-               mimepart->length = statbuf.st_size;
+               mimepart->length = size;
 
                type = g_strdup(ainfo->content_type);
 
@@ -7027,6 +7095,15 @@ extra_headers_done:
        g_slist_foreach(extra_headers, (GFunc)compose_add_extra_header, (gpointer)model);
 }
 
+static void _ldap_srv_func(gpointer data, gpointer user_data)
+{
+       LdapServer *server = (LdapServer *)data;
+       gboolean *enable = (gboolean *)user_data;
+
+       debug_print("%s server '%s'\n", (*enable == TRUE ? "enabling" : "disabling"), server->control->hostName);
+       server->searchFlag = *enable;
+}
+
 static void compose_create_header_entry(Compose *compose) 
 {
        gchar *headers[] = {"To:", "Cc:", "Bcc:", "Newsgroups:", "Reply-To:", "Followup-To:", NULL};
@@ -7165,7 +7242,22 @@ static void compose_create_header_entry(Compose *compose)
        g_signal_connect(G_OBJECT(entry), "populate-popup",
                         G_CALLBACK(compose_entry_popup_extend),
                         NULL);
-       
+
+#ifdef USE_LDAP
+       GSList *pwd_servers = addrindex_get_password_protected_ldap_servers();
+       if (pwd_servers != NULL && master_passphrase() == NULL) {
+               gboolean enable = FALSE;
+               debug_print("Master passphrase not available, disabling password-protected LDAP servers for this compose window.\n");
+               /* Temporarily disable password-protected LDAP servers,
+                * because user did not provide a master passphrase.
+                * We can safely enable searchFlag on all servers in this list
+                * later, since addrindex_get_password_protected_ldap_servers()
+                * includes servers which have it enabled initially. */
+               g_slist_foreach(pwd_servers, _ldap_srv_func, &enable);
+               compose->passworded_ldap_servers = pwd_servers;
+       }
+#endif
+
        address_completion_register_entry(GTK_ENTRY(entry), TRUE);
 
         headerentry->compose = compose;
@@ -8472,10 +8564,22 @@ static void compose_set_privacy_system_cb(GtkWidget *widget, gpointer data)
 
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/Sign", can_sign);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/Encrypt", can_encrypt);
-       gtk_widget_set_sensitive(compose->toolbar->privacy_sign_btn, can_sign);
-       gtk_widget_set_sensitive(compose->toolbar->privacy_encrypt_btn, can_encrypt);
-       gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(compose->toolbar->privacy_sign_btn), can_sign ? compose->use_signing : FALSE);
-       gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(compose->toolbar->privacy_encrypt_btn), can_encrypt ? compose->use_encryption : FALSE);
+       if (compose->toolbar->privacy_sign_btn != NULL) {
+               gtk_widget_set_sensitive(
+                       GTK_WIDGET(compose->toolbar->privacy_sign_btn),
+                       can_sign);
+               gtk_toggle_tool_button_set_active(
+                       GTK_TOGGLE_TOOL_BUTTON(compose->toolbar->privacy_sign_btn),
+                       can_sign ? compose->use_signing : FALSE);
+       }
+       if (compose->toolbar->privacy_encrypt_btn != NULL) {
+               gtk_widget_set_sensitive(
+                       GTK_WIDGET(compose->toolbar->privacy_encrypt_btn),
+                       can_encrypt);
+               gtk_toggle_tool_button_set_active(
+                       GTK_TOGGLE_TOOL_BUTTON(compose->toolbar->privacy_encrypt_btn),
+                       can_encrypt ? compose->use_encryption : FALSE);
+       }
 }
 
 static void compose_update_privacy_system_menu_item(Compose * compose, gboolean warn)
@@ -8532,8 +8636,18 @@ static void compose_update_privacy_system_menu_item(Compose * compose, gboolean
 
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/Sign", can_sign);
        cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options/Encrypt", can_encrypt);
-}      
+       if (compose->toolbar->privacy_sign_btn != NULL) {
+               gtk_widget_set_sensitive(
+                       GTK_WIDGET(compose->toolbar->privacy_sign_btn),
+                       can_sign);
+       }
+       if (compose->toolbar->privacy_encrypt_btn != NULL) {
+               gtk_widget_set_sensitive(
+                       GTK_WIDGET(compose->toolbar->privacy_encrypt_btn),
+                       can_encrypt);
+       }
+}
+
 static void compose_set_out_encoding(Compose *compose)
 {
        CharSet out_encoding;
@@ -8807,6 +8921,8 @@ static void compose_template_apply(Compose *compose, Template *tmpl,
        compose_template_apply_fields(compose, tmpl);
        compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
        quote_fmt_reset_vartable();
+       quote_fmtlex_destroy();
+
        compose_changed_cb(NULL, compose);
 
 #ifdef USE_ENCHANT
@@ -8860,6 +8976,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        gtk_entry_set_text(GTK_ENTRY(compose->from_name), buf);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        if (tmpl->to && *tmpl->to != '\0') {
@@ -8878,6 +8997,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        compose_entry_append(compose, buf, COMPOSE_TO, PREF_TEMPLATE);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        if (tmpl->cc && *tmpl->cc != '\0') {
@@ -8896,6 +9018,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        compose_entry_append(compose, buf, COMPOSE_CC, PREF_TEMPLATE);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        if (tmpl->bcc && *tmpl->bcc != '\0') {
@@ -8914,6 +9039,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        compose_entry_append(compose, buf, COMPOSE_BCC, PREF_TEMPLATE);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        if (tmpl->replyto && *tmpl->replyto != '\0') {
@@ -8932,6 +9060,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        compose_entry_append(compose, buf, COMPOSE_REPLYTO, PREF_TEMPLATE);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        /* process the subject */
@@ -8951,6 +9082,9 @@ static void compose_template_apply_fields(Compose *compose, Template *tmpl)
                } else {
                        gtk_entry_set_text(GTK_ENTRY(compose->subject_entry), buf);
                }
+
+               quote_fmt_reset_vartable();
+               quote_fmtlex_destroy();
        }
 
        procmsg_msginfo_free( &dummyinfo );
@@ -8964,6 +9098,11 @@ static void compose_destroy(Compose *compose)
 
        compose_list = g_list_remove(compose_list, compose);
 
+       gboolean enable = TRUE;
+       g_slist_foreach(compose->passworded_ldap_servers,
+                       _ldap_srv_func, &enable);
+       g_slist_free(compose->passworded_ldap_servers);
+
        if (compose->updating) {
                debug_print("danger, not destroying anything now\n");
                compose->deferred_destroy = TRUE;
@@ -10377,26 +10516,56 @@ warn_err:
                compose_close(compose);
                return TRUE;
        } else {
+#ifdef G_OS_WIN32
+               GFile *f;
+               GFileInfo *fi;
+               GTimeVal tv;
+               GError *error;
+#else
                GStatBuf s;
+#endif
                gchar *path;
+               goffset size, mtime;
 
                path = folder_item_fetch_msg(draft, msgnum);
                if (path == NULL) {
                        debug_print("can't fetch %s:%d\n", draft->path, msgnum);
                        goto unlock;
                }
+#ifdef G_OS_WIN32
+               f = g_file_new_for_path(path);
+               fi = g_file_query_info(f, "standard::size,time::modified",
+                               G_FILE_QUERY_INFO_NONE, NULL, &error);
+               if (error != NULL) {
+                       debug_print("couldn't query file info for '%s': %s\n",
+                                       path, error->message);
+                       g_error_free(error);
+                       g_free(path);
+                       g_object_unref(f);
+                       goto unlock;
+               }
+               size = g_file_info_get_size(fi);
+               g_file_info_get_modification_time(fi, &tv);
+               mtime = tv.tv_sec;
+               g_object_unref(fi);
+               g_object_unref(f);
+               g_free(path);
+#else
                if (g_stat(path, &s) < 0) {
                        FILE_OP_ERROR(path, "stat");
                        g_free(path);
                        goto unlock;
                }
+               size = s.st_size;
+               mtime = s.st_mtime;
+#endif
                g_free(path);
 
                procmsg_msginfo_free(&(compose->targetinfo));
                compose->targetinfo = procmsg_msginfo_new();
                compose->targetinfo->msgnum = msgnum;
-               compose->targetinfo->size = (goffset)s.st_size;
-               compose->targetinfo->mtime = s.st_mtime;
+               compose->targetinfo->size = size;
+               compose->targetinfo->mtime = mtime;
                compose->targetinfo->folder = draft;
                if (target_locked)
                        procmsg_msginfo_set_flags(compose->targetinfo, MSG_LOCKED, 0);
@@ -11655,6 +11824,8 @@ static gboolean compose_headerentry_button_clicked_cb (GtkWidget *button,
                                         ComposeHeaderEntry *headerentry)
 {
        gtk_entry_set_text(GTK_ENTRY(headerentry->entry), "");
+       gtk_widget_modify_base(GTK_WIDGET(headerentry->entry), GTK_STATE_NORMAL, NULL);
+       gtk_widget_modify_text(GTK_WIDGET(headerentry->entry), GTK_STATE_NORMAL, NULL);
        return FALSE;
 }