talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit 22249a5bdbc5930c0a3069804ba9cdf35ec07dec
parent c03433163c1b3d0d9aaefc82c7c5a5fa2c413a58
Author: Michael Rasmussen <mir@datanom.net>
Date:   Sat, 23 Sep 2017 22:55:25 +0200

Merge branch 'master' of ssh+git://git.claws-mail.org/home/git/claws

Diffstat:
MAUTHORS | 2++
Mconfigure.ac | 2+-
Mdoc/man/claws-mail.1 | 5+++++
Msrc/account.c | 2++
Msrc/compose.c | 13+++++++++----
Msrc/compose.h | 1+
Msrc/gtk/authors.h | 2++
Msrc/gtk/gtkaspell.c | 2+-
Msrc/imap.c | 35++---------------------------------
Msrc/main.c | 42++++++++++++++++++++++++++++++------------
Msrc/plugins/pgpcore/prefs_gpg.c | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/plugins/pgpcore/prefs_gpg.h | 2++
Msrc/plugins/pgpcore/select-keys.c | 12++++++++++--
Msrc/plugins/pgpcore/sgpgme.c | 28++++++++++++++++++++++------
Msrc/prefs_account.c | 3+++
Msrc/prefs_account.h | 2++
Msrc/prefs_common.c | 1+
Msrc/prefs_gtk.c | 2++
Msrc/prefs_migration.c | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/prefs_migration.h | 3++-
Msrc/quote_fmt.c | 2+-
Msrc/summaryview.c | 52+++++++++++++++++++++++++++++++++++++++++-----------
22 files changed, 377 insertions(+), 167 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -314,3 +314,5 @@ contributors (in addition to the above; based on Changelog) Olivier Brunel Michael Vilain Orbea + Flavio Leitner + Thomas Orgis diff --git a/configure.ac b/configure.ac @@ -585,7 +585,7 @@ dnl enchant is used for spell checking AC_MSG_CHECKING([whether to use enchant]) AC_MSG_RESULT($enable_enchant) if test $enable_enchant = yes; then - PKG_CHECK_MODULES(ENCHANT, enchant >= 1.0.0, + PKG_CHECK_MODULES(ENCHANT, enchant >= 1.4.0, [ AC_DEFINE(USE_ENCHANT, 1, enchant) echo "Building with enchant" diff --git a/doc/man/claws-mail.1 b/doc/man/claws-mail.1 @@ -101,6 +101,8 @@ This list is not complete. .br \fB \-\-attach file1 [file2]...\fR .br +\fB \-\-insert file1 [file2]...\fR +.br \fB \-\-receive\fR .br \fB \-\-receive\-all\fR @@ -283,6 +285,9 @@ Subscribe to the given URI if possible. \fB\-\-attach file1 [file2]...\fR Open composition window with specified files attached. .TP +\fB\-\-insert file1 [file2]...\fR +Open composition window with specified files inserted. +.TP \fB\-\-compose\fR "mailto:\fI%t\fR?subject=\fI%s\fR&cc=\fI%c\fR&body=\fI%b\fR" This syntax can be used in web\-browsers and CLI to open a pre\-populated Compose window. Possible fields after the destination recipient are: subject, diff --git a/src/account.c b/src/account.c @@ -1052,6 +1052,8 @@ static void account_clone(GtkWidget *widget, gpointer data) ac_clon->is_default = FALSE; ACP_FASSIGN(folder); + ACP_FASSIGN(config_version); + account_list = g_list_append(account_list, ac_clon); account_list_view_set(); } diff --git a/src/compose.c b/src/compose.c @@ -1226,7 +1226,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); } } @@ -5193,9 +5196,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); @@ -11708,6 +11711,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; } diff --git a/src/compose.h b/src/compose.h @@ -262,6 +262,7 @@ struct _AttachInfo gchar *name; goffset size; gchar *charset; + gboolean insert; }; typedef enum diff --git a/src/gtk/authors.h b/src/gtk/authors.h @@ -195,6 +195,7 @@ static char *CONTRIBS_LIST[] = { "Abhay S. Kushwaha", "Joshua M. Kwan", "Jean-Yves Lefort", +"Flavio Leitner", "Jérôme Lelong", "Eric Limpens", "Thomas Link", @@ -241,6 +242,7 @@ static char *CONTRIBS_LIST[] = { "Paul Ollis", "Fredrik Olofssen", "Orbea", +"Thomas Orgis", "Reza Pakdel", "Richard Palo", "Marcel Pol", diff --git a/src/gtk/gtkaspell.c b/src/gtk/gtkaspell.c @@ -1348,7 +1348,7 @@ static void add_word_to_personal_cb(GtkWidget *w, gpointer data) { GtkAspell *gtkaspell = (GtkAspell *) data; - enchant_dict_add_to_pwl(gtkaspell->gtkaspeller->speller, gtkaspell->theword, strlen(gtkaspell->theword)); + enchant_dict_add(gtkaspell->gtkaspeller->speller, gtkaspell->theword, strlen(gtkaspell->theword)); gtkaspell->ctx.check_word(gtkaspell->ctx.data); gtkaspell_dict_changed(gtkaspell); diff --git a/src/imap.c b/src/imap.c @@ -77,8 +77,6 @@ typedef struct _IMAPSession IMAPSession; typedef struct _IMAPNameSpace IMAPNameSpace; typedef struct _IMAPFolderItem IMAPFolderItem; -#include "prefs_account.h" - #define IMAP_FOLDER(obj) ((IMAPFolder *)obj) #define IMAP_FOLDER_ITEM(obj) ((IMAPFolderItem *)obj) #define IMAP_SESSION(obj) ((IMAPSession *)obj) @@ -427,7 +425,6 @@ static gint imap_get_flags (Folder *folder, FolderItem *item, MsgInfoList *msglist, GHashTable *msgflags); -static gchar *imap_folder_get_path (Folder *folder); static gchar *imap_item_get_path (Folder *folder, FolderItem *item); static MsgInfo *imap_parse_msg(const gchar *file, FolderItem *item); @@ -3045,35 +3042,6 @@ static FolderItem *imap_create_special_folder(Folder *folder, return new_item; } -static gchar *imap_folder_get_path(Folder *folder) -{ - gchar *folder_path; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - -#ifdef G_OS_WIN32 - gchar *sanitized_dirname = g_strdup(folder->account->recv_server); - g_strdelimit(sanitized_dirname, ":", ','); -#endif - - folder_path = g_strconcat(get_imap_cache_dir(), - G_DIR_SEPARATOR_S, -#ifdef G_OS_WIN32 - sanitized_dirname, -#else - folder->account->recv_server, -#endif - G_DIR_SEPARATOR_S, - folder->account->userid, - NULL); - -#ifdef G_OS_WIN32 - g_free(sanitized_dirname); -#endif - return folder_path; -} - #ifdef G_OS_WIN32 static gchar *imap_encode_unsafe_chars(const gchar *str) { @@ -3110,8 +3078,9 @@ static gchar *imap_item_get_path(Folder *folder, FolderItem *item) gchar *item_path = NULL; g_return_val_if_fail(folder != NULL, NULL); + g_return_val_if_fail(folder->account != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); - folder_path = imap_folder_get_path(folder); + folder_path = prefs_account_cache_dir(folder->account, FALSE); g_return_val_if_fail(folder_path != NULL, NULL); diff --git a/src/main.c b/src/main.c @@ -1250,6 +1250,14 @@ int main(int argc, char *argv[]) folder_system_init(); prefs_common_read_config(); + if (prefs_update_config_version_common() < 0) { + debug_print("Main configuration file version upgrade failed, exiting\n"); +#ifdef G_OS_WIN32 + win32_close_log(); +#endif + exit(200); + } + prefs_themes_init(); prefs_fonts_init(); prefs_ext_prog_init(); @@ -1326,6 +1334,14 @@ int main(int argc, char *argv[]) prefs_account_init(); account_read_config_all(); + if (prefs_update_config_version_accounts() < 0) { + debug_print("Accounts configuration file version upgrade failed, exiting\n"); +#ifdef G_OS_WIN32 + win32_close_log(); +#endif + exit(201); + } + #ifdef HAVE_LIBETPAN imap_main_init(prefs_common.skip_ssl_cert_check); imap_main_set_timeout(prefs_common.io_timeout_secs); @@ -1478,17 +1494,8 @@ int main(int argc, char *argv[]) } if (never_ran) { - prefs_common_get_prefs()->config_version = CLAWS_CONFIG_VERSION; prefs_common_write_config(); plugin_load_standard_plugins (); - } else { - if (prefs_update_config_version() < 0) { - exit_claws(mainwin); -#ifdef G_OS_WIN32 - win32_close_log(); -#endif - exit(0); - } } /* if not crashed, show window now */ @@ -1861,9 +1868,10 @@ static void parse_cmd_opt(int argc, char *argv[]) cmd.subscribe = TRUE; cmd.subscribe_uri = p; } - } else if (!strncmp(argv[i], "--attach", 8)) { + } else if (!strncmp(argv[i], "--attach", 8) || !strncmp(argv[i], "--insert", 8)) { const gchar *p = (i+1 < argc)?argv[i+1]:NULL; gchar *file = NULL; + gboolean insert = !strncmp(argv[i], "--insert", 8); while (p && *p != '\0' && *p != '-') { if ((file = g_filename_from_uri(p, NULL, NULL)) != NULL) { @@ -1879,8 +1887,10 @@ static void parse_cmd_opt(int argc, char *argv[]) } else if (file == NULL) { file = g_strdup(p); } + ainfo = g_new0(AttachInfo, 1); ainfo->file = file; + ainfo->insert = insert; cmd.attach_files = g_list_append(cmd.attach_files, ainfo); i++; p = (i+1 < argc)?argv[i+1]:NULL; @@ -1957,6 +1967,9 @@ static void parse_cmd_opt(int argc, char *argv[]) g_print("%s\n", _(" --attach file1 [file2]...\n" " open composition window with specified files\n" " attached")); + g_print("%s\n", _(" --insert file1 [file2]...\n" + " open composition window with specified files\n" + " inserted")); g_print("%s\n", _(" --receive receive new messages")); g_print("%s\n", _(" --receive-all receive new messages of all accounts")); g_print("%s\n", _(" --cancel-receiving cancel receiving of messages")); @@ -2339,6 +2352,10 @@ static gint prohibit_duplicate_launch(void) for (curr = cmd.attach_files; curr != NULL ; curr = curr->next) { str = (gchar *) ((AttachInfo *)curr->data)->file; + if (((AttachInfo *)curr->data)->insert) + fd_write_all(uxsock, "insert ", strlen("insert ")); + else + fd_write_all(uxsock, "attach ", strlen("attach ")); fd_write_all(uxsock, str, strlen(str)); fd_write_all(uxsock, "\n", 1); } @@ -2539,9 +2556,10 @@ static void lock_socket_input_cb(gpointer data, strretchomp(buf); if (!strcmp2(buf, ".")) break; - + ainfo = g_new0(AttachInfo, 1); - ainfo->file = g_strdup(buf); + ainfo->file = g_strdup(strstr(buf, " ") + 1); + ainfo->insert = !strncmp(buf, "insert ", 7); files = g_list_append(files, ainfo); } open_compose_new(mailto, files); diff --git a/src/plugins/pgpcore/prefs_gpg.c b/src/plugins/pgpcore/prefs_gpg.c @@ -87,6 +87,26 @@ struct GPGPage GtkWidget *gpg_path; }; +struct GPGAccountPage +{ + PrefsPage page; + + GtkWidget *key_default; + GtkWidget *key_by_from; + GtkWidget *key_custom; + GtkWidget *keyid; + GtkWidget *keyid_label; + GtkWidget *new_key_label; + GtkWidget *new_key_btn; + GtkWidget *new_key_box; + + PrefsAccount *account; +}; + +static struct GPGPage gpg_page; +static struct GPGAccountPage gpg_account_page; +static struct GPGAccountPage smime_account_page; + static void prefs_gpg_create_widget_func(PrefsPage *_page, GtkWindow *window, gpointer data) @@ -270,22 +290,6 @@ static void prefs_gpg_save_func(PrefsPage *_page) prefs_gpg_save_config(); } -struct GPGAccountPage -{ - PrefsPage page; - - GtkWidget *key_default; - GtkWidget *key_by_from; - GtkWidget *key_custom; - GtkWidget *keyid; - GtkWidget *keyid_label; - GtkWidget *new_key_label; - GtkWidget *new_key_btn; - GtkWidget *new_key_box; - - PrefsAccount *account; -}; - void key_custom_toggled(GtkToggleButton *togglebutton, gpointer user_data) { struct GPGAccountPage *page = (struct GPGAccountPage *) user_data; @@ -333,6 +337,7 @@ static void prefs_gpg_account_create_widget_func(PrefsPage *_page, struct GPGAccountPage *page = (struct GPGAccountPage *) _page; PrefsAccount *account = (PrefsAccount *) data; GPGAccountConfig *config; + SignKeyType sign_key; GtkWidget *vbox; GtkWidget *frame1; @@ -403,7 +408,10 @@ static void prefs_gpg_account_create_widget_func(PrefsPage *_page, gtk_box_pack_start(GTK_BOX(hbox), keyid, FALSE, FALSE, 0); config = prefs_gpg_account_get_config(account); - switch (config->sign_key) { + + sign_key = + (page == &smime_account_page ? config->smime_sign_key : config->sign_key); + switch (sign_key) { case SIGN_KEY_DEFAULT: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(key_default), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(keyid_label), FALSE); @@ -441,9 +449,13 @@ static void prefs_gpg_account_create_widget_func(PrefsPage *_page, gtk_widget_show(new_key_btn); gtk_box_pack_start(GTK_BOX(hbox), new_key_btn, FALSE, FALSE, 0); - if (config->sign_key_id != NULL) - gtk_entry_set_text(GTK_ENTRY(keyid), config->sign_key_id); - + if (page == &smime_account_page) { + if (config->smime_sign_key_id != NULL) + gtk_entry_set_text(GTK_ENTRY(keyid), config->smime_sign_key_id); + } else { + if (config->sign_key_id != NULL) + gtk_entry_set_text(GTK_ENTRY(keyid), config->sign_key_id); + } g_signal_connect(G_OBJECT(key_custom), "toggled", G_CALLBACK(key_custom_toggled), page); g_signal_connect(G_OBJECT(new_key_btn), "clicked", G_CALLBACK(new_key_clicked), page); @@ -473,14 +485,26 @@ static void prefs_gpg_account_save_func(PrefsPage *_page) config = prefs_gpg_account_get_config(page->account); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_default))) - config->sign_key = SIGN_KEY_DEFAULT; - else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_by_from))) - config->sign_key = SIGN_KEY_BY_FROM; - else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_custom))) { - config->sign_key = SIGN_KEY_CUSTOM; - g_free(config->sign_key_id); - config->sign_key_id = gtk_editable_get_chars(GTK_EDITABLE(page->keyid), 0, -1); + if (page == &smime_account_page) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_default))) + config->smime_sign_key = SIGN_KEY_DEFAULT; + else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_by_from))) + config->smime_sign_key = SIGN_KEY_BY_FROM; + else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_custom))) { + config->smime_sign_key = SIGN_KEY_CUSTOM; + g_free(config->smime_sign_key_id); + config->smime_sign_key_id = gtk_editable_get_chars(GTK_EDITABLE(page->keyid), 0, -1); + } + } else { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_default))) + config->sign_key = SIGN_KEY_DEFAULT; + else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_by_from))) + config->sign_key = SIGN_KEY_BY_FROM; + else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->key_custom))) { + config->sign_key = SIGN_KEY_CUSTOM; + g_free(config->sign_key_id); + config->sign_key_id = gtk_editable_get_chars(GTK_EDITABLE(page->keyid), 0, -1); + } } prefs_gpg_account_set_config(page->account, config); @@ -526,26 +550,51 @@ struct GPGAccountConfig *prefs_gpg_account_get_config(PrefsAccount *account) config = g_new0(GPGAccountConfig, 1); config->sign_key = SIGN_KEY_DEFAULT; config->sign_key_id = NULL; + config->smime_sign_key = SIGN_KEY_DEFAULT; + config->smime_sign_key_id = NULL; confstr = prefs_account_get_privacy_prefs(account, "gpg"); - if (confstr == NULL) - return config; - - strv = g_strsplit(confstr, ";", 0); - if (strv[0] != NULL) { - if (!strcmp(strv[0], "DEFAULT")) - config->sign_key = SIGN_KEY_DEFAULT; - if (!strcmp(strv[0], "BY_FROM")) - config->sign_key = SIGN_KEY_BY_FROM; - if (!strcmp(strv[0], "CUSTOM")) { - if (strv[1] != NULL) { - config->sign_key = SIGN_KEY_CUSTOM; - config->sign_key_id = g_strdup(strv[1]); - } else + if (confstr != NULL) { + strv = g_strsplit(confstr, ";", 0); + if (strv[0] != NULL) { + if (!strcmp(strv[0], "DEFAULT")) config->sign_key = SIGN_KEY_DEFAULT; + if (!strcmp(strv[0], "BY_FROM")) + config->sign_key = SIGN_KEY_BY_FROM; + if (!strcmp(strv[0], "CUSTOM")) { + if (strv[1] != NULL) { + config->sign_key = SIGN_KEY_CUSTOM; + config->sign_key_id = g_strdup(strv[1]); + } else + config->sign_key = SIGN_KEY_DEFAULT; + } } + g_strfreev(strv); + } + + confstr = prefs_account_get_privacy_prefs(account, "smime"); + /* If the "smime" section does not yet exist, fall back to + * "gpg" section even for smime_ values. This will generally + * only happen on first run. */ + if (confstr == NULL) + confstr = prefs_account_get_privacy_prefs(account, "gpg"); + if (confstr != NULL) { + strv = g_strsplit(confstr, ";", 0); + if (strv[0] != NULL) { + if (!strcmp(strv[0], "DEFAULT")) + config->smime_sign_key = SIGN_KEY_DEFAULT; + if (!strcmp(strv[0], "BY_FROM")) + config->smime_sign_key = SIGN_KEY_BY_FROM; + if (!strcmp(strv[0], "CUSTOM")) { + if (strv[1] != NULL) { + config->smime_sign_key = SIGN_KEY_CUSTOM; + config->smime_sign_key_id = g_strdup(strv[1]); + } else + config->smime_sign_key = SIGN_KEY_DEFAULT; + } + } + g_strfreev(strv); } - g_strfreev(strv); return config; } @@ -572,17 +621,35 @@ void prefs_gpg_account_set_config(PrefsAccount *account, GPGAccountConfig *confi prefs_account_set_privacy_prefs(account, "gpg", confstr); g_free(confstr); + confstr = NULL; + + switch (config->smime_sign_key) { + case SIGN_KEY_DEFAULT: + confstr = g_strdup("DEFAULT"); + break; + case SIGN_KEY_BY_FROM: + confstr = g_strdup("BY_FROM"); + break; + case SIGN_KEY_CUSTOM: + confstr = g_strdup_printf("CUSTOM;%s", config->smime_sign_key_id); + break; + default: + confstr = g_strdup(""); + g_warning("prefs_gpg_account_set_config: bad sign_key val"); + } + + prefs_account_set_privacy_prefs(account, "smime", confstr); + + g_free(confstr); } void prefs_gpg_account_free_config(GPGAccountConfig *config) { + g_free(config->smime_sign_key_id); g_free(config->sign_key_id); g_free(config); } -static struct GPGPage gpg_page; -static struct GPGAccountPage gpg_account_page; - void prefs_gpg_enable_agent(gboolean enable) { if (enable) { @@ -607,7 +674,7 @@ void prefs_gpg_enable_agent(gboolean enable) void prefs_gpg_init() { - static gchar *path[3]; + static gchar *path[3], *spath[3]; gchar *rcpath; const gchar *tmp = NULL; @@ -635,6 +702,17 @@ void prefs_gpg_init() gpg_account_page.page.weight = 30.0; prefs_account_register_page((PrefsPage *) &gpg_account_page); + + spath[0] = _("Plugins"); + spath[1] = _("S/MIME"); + spath[2] = NULL; + smime_account_page.page.path = spath; + smime_account_page.page.create_widget = prefs_gpg_account_create_widget_func; + smime_account_page.page.destroy_widget = prefs_gpg_account_destroy_widget_func; + smime_account_page.page.save_page = prefs_gpg_account_save_func; + smime_account_page.page.weight = 30.0; + + prefs_account_register_page((PrefsPage *) &smime_account_page); tmp = g_getenv("GPG_AGENT_INFO"); if (tmp) diff --git a/src/plugins/pgpcore/prefs_gpg.h b/src/plugins/pgpcore/prefs_gpg.h @@ -50,6 +50,8 @@ struct GPGAccountConfig { SignKeyType sign_key; gchar *sign_key_id; + SignKeyType smime_sign_key; + gchar *smime_sign_key_id; }; void prefs_gpg_init(void); diff --git a/src/plugins/pgpcore/select-keys.c b/src/plugins/pgpcore/select-keys.c @@ -167,6 +167,9 @@ static void destroy_key (gpointer data) { gpgme_key_t key = data; + + debug_print("unref key %p\n", key); + gpgme_key_unref (key); } @@ -255,6 +258,7 @@ set_row (GtkCMCList *clist, gpgme_key_t key, gpgme_protocol_t proto) row = gtk_cmclist_append (clist, (gchar**)text); g_free (algo_buf); + gpgme_key_ref(key); gtk_cmclist_set_row_data_full (clist, row, key, destroy_key); } @@ -298,8 +302,10 @@ fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t prot update_progress (sk, ++running, pattern); while ( !(err = gpgme_op_keylist_next ( ctx, &key )) ) { gpgme_user_id_t uid = key->uids; - if (!key->can_encrypt || key->revoked || key->expired || key->disabled) + if (!key->can_encrypt || key->revoked || key->expired || key->disabled) { + gpgme_key_unref(key); continue; + } debug_print ("%% %s:%d: insert\n", __FILE__ ,__LINE__ ); set_row (clist, key, proto ); for (; uid; uid = uid->next) { @@ -349,7 +355,9 @@ fill_clist (struct select_keys_s *sk, const char *pattern, gpgme_protocol_t prot if (exact_match && num_results == 1) return last_key; - gpgme_key_unref(last_key); + if (last_key != NULL) + gpgme_key_unref(last_key); + return NULL; } diff --git a/src/plugins/pgpcore/sgpgme.c b/src/plugins/pgpcore/sgpgme.c @@ -572,14 +572,30 @@ gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account, { GPGAccountConfig *config; const gchar *signer_addr = account->address; + SignKeyType sk; + gchar *skid; + gboolean smime = FALSE; gpgme_signers_clear(ctx); + if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_CMS) + smime = TRUE; + if (from_addr) signer_addr = from_addr; config = prefs_gpg_account_get_config(account); - switch(config->sign_key) { + if(smime) { + debug_print("sgpgme_setup_signers: S/MIME protocol\n"); + sk = config->smime_sign_key; + skid = config->smime_sign_key_id; + } else { + debug_print("sgpgme_setup_signers: OpenPGP protocol\n"); + sk = config->sign_key; + skid = config->sign_key_id; + } + + switch(sk) { case SIGN_KEY_DEFAULT: debug_print("using default gnupg key\n"); break; @@ -587,19 +603,19 @@ gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account, debug_print("using key for %s\n", signer_addr); break; case SIGN_KEY_CUSTOM: - debug_print("using key for %s\n", config->sign_key_id); + debug_print("using key for %s\n", skid); break; } - if (config->sign_key != SIGN_KEY_DEFAULT) { + if (sk != SIGN_KEY_DEFAULT) { const gchar *keyid; gpgme_key_t key, found_key; gpgme_error_t err; - if (config->sign_key == SIGN_KEY_BY_FROM) + if (sk == SIGN_KEY_BY_FROM) keyid = signer_addr; - else if (config->sign_key == SIGN_KEY_CUSTOM) - keyid = config->sign_key_id; + else if (sk == SIGN_KEY_CUSTOM) + keyid = skid; else goto bail; diff --git a/src/prefs_account.c b/src/prefs_account.c @@ -435,6 +435,9 @@ static PrefParam basic_param[] = { {"password", NULL, &tmp_ac_prefs.passwd, P_PASSWORD, NULL, NULL, NULL}, + {"config_version", "-1", &tmp_ac_prefs.config_version, P_INT, + NULL, NULL, NULL}, + {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL} }; diff --git a/src/prefs_account.h b/src/prefs_account.h @@ -207,6 +207,8 @@ struct _PrefsAccount struct _Folder *folder; GHashTable *privacy_prefs; SMTPSession *session; + + gint config_version; }; void prefs_account_init (void); diff --git a/src/prefs_common.c b/src/prefs_common.c @@ -41,6 +41,7 @@ #include "prefs_display_header.h" #include "prefs_summary_column.h" #include "prefs_folder_column.h" +#include "prefs_migration.h" #include "mainwindow.h" #include "summaryview.h" #include "folderview.h" diff --git a/src/prefs_gtk.c b/src/prefs_gtk.c @@ -440,6 +440,8 @@ void prefs_set_default(PrefParam *param) if (param[i].defval != NULL) *((gint *)param[i].data) = (gint)atoi(param[i].defval); + else if (!strcmp(param[i].name, "config_version")) + *((gint *)param[i].data) = CLAWS_CONFIG_VERSION; else *((gint *)param[i].data) = 0; break; diff --git a/src/prefs_migration.c b/src/prefs_migration.c @@ -34,14 +34,70 @@ #include "prefs_common.h" #include "alertpanel.h" -static void _update_config(gint version) +static gint starting_config_version = 0; + +gboolean _version_check(gint ver) { - GList *cur; - PrefsAccount *ac_prefs; + if (ver > CLAWS_CONFIG_VERSION) { + gchar *msg; + gchar *markup; + AlertValue av; + + markup = g_strdup_printf( + "<a href=\"%s\"><span underline=\"none\">", + CONFIG_VERSIONS_URI); + msg = g_strdup_printf( + _("Your Claws Mail configuration is from a newer " + "version than the version which you are currently " + "using.\n\n" + "This is not recommended.\n\n" + "For further information see the %sClaws Mail " + "website%s.\n\n" + "Do you want to exit now?"), + markup, "</span></a>"); + g_free(markup); + av = alertpanel_full(_("Configuration warning"), msg, + GTK_STOCK_NO, GTK_STOCK_YES, NULL, + FALSE, NULL, + ALERT_ERROR, G_ALERTALTERNATE); + g_free(msg); + + if (av != G_ALERTDEFAULT) + return FALSE; /* abort startup */ + + return TRUE; /* hic sunt dracones */ + } + + return TRUE; +} +static void _update_config_common(gint version) +{ debug_print("Updating config version %d to %d.\n", version, version + 1); switch (version) { + case 1: + + /* The autochk_interval preference is now + * interpreted as seconds instead of minutes */ + prefs_common.autochk_itv *= 60; + + break; + + default: + + /* NOOP */ + + break; + } +} + +static void _update_config_account(PrefsAccount *ac_prefs, gint version) +{ + debug_print("Account '%s': Updating config version from %d to %d.\n", + ac_prefs->account_name, version, version + 1); + + switch (version) { case 0: /* Removing A_APOP and A_RPOP from RecvProtocol enum, @@ -54,64 +110,35 @@ static void _update_config(gint version) * A_IMAP and the rest are from 3 up. * We can't use the macros, since they may change in the * future. Numbers do not change. :) */ - for (cur = account_get_list(); cur != NULL; cur = cur->next) { - ac_prefs = (PrefsAccount *)cur->data; - if (ac_prefs->protocol == 1) { - ac_prefs->protocol = 0; - } else if (ac_prefs->protocol > 2) { - /* A_IMAP and above gets bumped down by 2. */ - ac_prefs->protocol -= 2; - } + if (ac_prefs->protocol == 1) { + ac_prefs->protocol = 0; + } else if (ac_prefs->protocol > 2) { + /* A_IMAP and above gets bumped down by 2. */ + ac_prefs->protocol -= 2; } break; - case 1: + default: - /* The autochk_interval preference is now - * interpreted as seconds instead of minutes */ - prefs_common.autochk_itv *= 60; + /* NOOP */ break; - - default: - break; } + + ac_prefs->config_version = version + 1; } -int prefs_update_config_version() +int prefs_update_config_version_common() { gint ver = prefs_common_get_prefs()->config_version; - if (ver > CLAWS_CONFIG_VERSION) { - gchar *msg; - gchar *markup; - AlertValue av; - - markup = g_strdup_printf( - "<a href=\"%s\"><span underline=\"none\">", - CONFIG_VERSIONS_URI); - msg = g_strdup_printf( - _("Your Claws Mail configuration is from a newer " - "version than the version which you are currently " - "using.\n\n" - "This is not recommended.\n\n" - "For further information see the %sClaws Mail " - "website%s.\n\n" - "Do you want to exit now?"), - markup, "</span></a>"); - g_free(markup); - av = alertpanel_full(_("Configuration warning"), msg, - GTK_STOCK_NO, GTK_STOCK_YES, NULL, - FALSE, NULL, - ALERT_ERROR, G_ALERTALTERNATE); - g_free(msg); - - if (av != G_ALERTDEFAULT) - return -1; /* abort startup */ + /* Store the starting version number for other components' + * migration functions. */ + starting_config_version = ver; - return 0; /* hic sunt dracones */ - } + if (!_version_check(ver)) + return -1; debug_print("Starting config update at config_version %d.\n", ver); if (ver == CLAWS_CONFIG_VERSION) { @@ -120,10 +147,46 @@ int prefs_update_config_version() } while (ver < CLAWS_CONFIG_VERSION) { - _update_config(ver++); + _update_config_common(ver++); prefs_common_get_prefs()->config_version = ver; } debug_print("Config update done.\n"); return 1; /* update done */ } + +int prefs_update_config_version_accounts() +{ + GList *cur; + PrefsAccount *ac_prefs; + + for (cur = account_get_list(); cur != NULL; cur = cur->next) { + ac_prefs = (PrefsAccount *)cur->data; + + if (ac_prefs->config_version == -1) { + /* There was no config_version stored in accountrc, let's assume + * config_version same as clawsrc started at, to avoid breaking + * this account by "upgrading" it unnecessarily. */ + debug_print("Account '%s': config_version not saved, using one from clawsrc: %d\n", ac_prefs->account_name, starting_config_version); + ac_prefs->config_version = starting_config_version; + } + + gint ver = ac_prefs->config_version; + + debug_print("Account '%s': Starting config update at config_version %d.\n", ac_prefs->account_name, ver); + + if (!_version_check(ver)) + return -1; + + if (ver == CLAWS_CONFIG_VERSION) { + debug_print("Account '%s': No update necessary, already at latest config_version.\n", ac_prefs->account_name); + continue; + } + + while (ver < CLAWS_CONFIG_VERSION) { + _update_config_account(ac_prefs, ver++); + } + } + + return 1; +} diff --git a/src/prefs_migration.h b/src/prefs_migration.h @@ -19,6 +19,7 @@ #ifndef __PREFS_MIGRATION_H__ #define __PREFS_MIGRATION_H__ -int prefs_update_config_version(); +int prefs_update_config_version_common(); +int prefs_update_config_version_accounts(); #endif /* __PREFS_MIGRATION_H__ */ diff --git a/src/quote_fmt.c b/src/quote_fmt.c @@ -93,7 +93,7 @@ static gchar *quote_desc_strings[] = { "|program{<span style=\"oblique\">sub_expr</span>}\n(|p{<span style=\"oblique\">sub_expr</span>})\n", N_("insert program output:\n<span style=\"oblique\">sub_expr</span> is evaluated as a command-line to get\nthe output from"), /* insert program output */ "|input{<span style=\"oblique\">sub_expr</span>}\n(|i{<span style=\"oblique\">sub_expr</span>})\n", N_("insert user input:\n<span style=\"oblique\">sub_expr</span> is a variable to be replaced by\nuser-entered text"), /* insert user input */ "|attach{<span style=\"oblique\">sub_expr</span>}\n(|a{<span style=\"oblique\">sub_expr</span>})", N_("attach file:\n<span style=\"oblique\">sub_expr</span> is evaluated as the path of the file to attach"), /* attach file */ - "|attach_output{<span style=\"oblique\">sub_expr</span>}\n(|A{<span style=\"oblique\">sub_expr</span>})", N_("attach file:\n<span style=\"oblique\">sub_expr</span> is evaluated as a command-line to get\nthe filename from"), /* attach file whose name's got from program output */ + "|attach_program{<span style=\"oblique\">sub_expr</span>}\n(|A{<span style=\"oblique\">sub_expr</span>})", N_("attach file:\n<span style=\"oblique\">sub_expr</span> is evaluated as a command-line to get\nthe filename from"), /* attach file whose name's got from program output */ "", NULL, N_("<span weight=\"bold\">definition of terms:</span>"), NULL, "<span style=\"oblique\">expr</span>\n", N_("text that can contain any of the symbols or\ncommands above"), diff --git a/src/summaryview.c b/src/summaryview.c @@ -163,7 +163,8 @@ static void summary_update_status (SummaryView *summaryview); static void summary_status_show (SummaryView *summaryview); static void summary_set_column_titles (SummaryView *summaryview); static void summary_set_ctree_from_list (SummaryView *summaryview, - GSList *mlist); + GSList *mlist, + guint selected_msgnum); static inline void summary_set_header (SummaryView *summaryview, gchar *text[], MsgInfo *msginfo); @@ -1447,7 +1448,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item) /* set ctree and hash table from the msginfo list, and create the thread */ - summary_set_ctree_from_list(summaryview, mlist); + summary_set_ctree_from_list(summaryview, mlist, selected_msgnum); g_slist_free(mlist); @@ -3090,6 +3091,35 @@ static gboolean summary_thread_is_read(GNode *gnode) return all_read; } +typedef struct _ThreadSelectedData { + guint msgnum; + gboolean is_selected; +} ThreadSelectedData; + +static gboolean summary_update_is_selected(GNode *gnode, gpointer data) +{ + ThreadSelectedData *selected = (ThreadSelectedData *)data; + MsgInfo *msginfo = (MsgInfo *)gnode->data; + + if (msginfo->msgnum == selected->msgnum) { + selected->is_selected = TRUE; + return TRUE; + } + + return FALSE; +} + +static gboolean summary_thread_is_selected(GNode *gnode, guint selected_msgnum) +{ + ThreadSelectedData selected; + + selected.msgnum = selected_msgnum; + selected.is_selected = FALSE; + g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, + summary_update_is_selected, &selected); + return selected.is_selected; +} + static gboolean summary_insert_gnode_func(GtkCMCTree *ctree, guint depth, GNode *gnode, GtkCMCTreeNode *cnode, gpointer data) { @@ -3141,7 +3171,7 @@ static gboolean summary_insert_gnode_func(GtkCMCTree *ctree, guint depth, GNode } static void summary_set_ctree_from_list(SummaryView *summaryview, - GSList *mlist) + GSList *mlist, guint selected_msgnum) { GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); MsgInfo *msginfo; @@ -3184,14 +3214,14 @@ static void summary_set_ctree_from_list(SummaryView *summaryview, for (gnode = root->children; gnode != NULL; gnode = gnode->next) { - if (!summaryview->folder_item->hide_read_threads || - !summary_thread_is_read(gnode)) - { - summary_find_thread_age(gnode); - node = gtk_sctree_insert_gnode - (ctree, NULL, node, gnode, - summary_insert_gnode_func, summaryview); - } + if (!summaryview->folder_item->hide_read_threads || + !summary_thread_is_read(gnode) || + summary_thread_is_selected(gnode, selected_msgnum)) { + summary_find_thread_age(gnode); + node = gtk_sctree_insert_gnode + (ctree, NULL, node, gnode, + summary_insert_gnode_func, summaryview); + } } g_node_destroy(root);