/*
- * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2011 Hiroyuki Yamamoto and the Claws Mail team
+ * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2015 Hiroyuki Yamamoto and the Claws Mail team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ *
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
+#include "claws-features.h"
#endif
#include "defs.h"
#include "main.h"
#include "mainwindow.h"
#include "compose.h"
-#include "addressbook.h"
+#ifndef USE_NEW_ADDRBOOK
+ #include "addressbook.h"
+#else
+ #include "addressbook-dbus.h"
+ #include "addressadd.h"
+#endif
#include "folderview.h"
#include "procmsg.h"
#include "menu.h"
#include "procmime.h"
#include "statusbar.h"
#include "about.h"
-#include "base64.h"
#include "quoted-printable.h"
#include "codeconv.h"
#include "utils.h"
#include "alertpanel.h"
#include "manage_window.h"
#include "folder.h"
+#include "folder_item_prefs.h"
#include "addr_compl.h"
#include "quote_fmt.h"
#include "undo.h"
#define MAX_REFERENCES_LEN 999
+#define COMPOSE_DRAFT_TIMEOUT_UNSET -1
+#define COMPOSE_DRAFT_TIMEOUT_FORBIDDEN -2
+
static GList *compose_list = NULL;
+static GSList *extra_headers = NULL;
static Compose *compose_generic_new (PrefsAccount *account,
const gchar *to,
FolderItem *item,
- GPtrArray *attach_files,
+ GList *attach_files,
GList *listAddress );
static Compose *compose_create (PrefsAccount *account,
static void compose_notebook_size_alloc (GtkNotebook *notebook,
GtkAllocation *allocation,
- Compose *compose);
+ GtkPaned *paned);
static gboolean compose_edit_size_alloc (GtkEditable *widget,
GtkAllocation *allocation,
GtkSHRuler *shruler);
gpointer data);
static void compose_insert_sig_cb (GtkAction *action,
gpointer data);
+static void compose_replace_sig_cb (GtkAction *action,
+ gpointer data);
static void compose_close_cb (GtkAction *action,
gpointer data);
GdkDragContext *drag_context,
gint x, gint y,
guint time, gpointer user_data);
+static gboolean completion_set_focus_to_subject
+ (GtkWidget *widget,
+ GdkEventKey *event,
+ Compose *user_data);
static void text_inserted (GtkTextBuffer *buffer,
GtkTextIter *iter,
static void compose_attach_update_label(Compose *compose);
static void compose_set_folder_prefs(Compose *compose, FolderItem *folder,
gboolean respect_default_to);
+static void compose_subject_entry_activated(GtkWidget *widget, gpointer data);
+static void from_name_activate_cb(GtkWidget *widget, gpointer data);
static GtkActionEntry compose_popup_entries[] =
{
{"Message/AttachFile", NULL, N_("_Attach file"), "<control>M", NULL, G_CALLBACK(compose_attach_cb) },
{"Message/InsertFile", NULL, N_("_Insert file"), "<control>I", NULL, G_CALLBACK(compose_insert_file_cb) },
{"Message/InsertSig", NULL, N_("Insert si_gnature"), "<control>G", NULL, G_CALLBACK(compose_insert_sig_cb) },
+ {"Message/ReplaceSig", NULL, N_("_Replace signature"), NULL, NULL, G_CALLBACK(compose_replace_sig_cb) },
/* {"Message/---", NULL, "---" }, */
{"Message/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(compose_save_cb) }, /*COMPOSE_KEEP_EDITING*/
/* {"Message/---", NULL, "---" }, */
{"Edit/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(compose_paste_cb) },
{"Edit/SpecialPaste", NULL, N_("_Special paste") },
- {"Edit/SpecialPaste/AsQuotation", NULL, N_("as _quotation"), NULL, NULL, G_CALLBACK(compose_paste_as_quote_cb) },
- {"Edit/SpecialPaste/Wrapped", NULL, N_("_wrapped"), NULL, NULL, G_CALLBACK(compose_paste_wrap_cb) },
- {"Edit/SpecialPaste/Unwrapped", NULL, N_("_unwrapped"), NULL, NULL, G_CALLBACK(compose_paste_no_wrap_cb) },
+ {"Edit/SpecialPaste/AsQuotation", NULL, N_("As _quotation"), NULL, NULL, G_CALLBACK(compose_paste_as_quote_cb) },
+ {"Edit/SpecialPaste/Wrapped", NULL, N_("_Wrapped"), NULL, NULL, G_CALLBACK(compose_paste_wrap_cb) },
+ {"Edit/SpecialPaste/Unwrapped", NULL, N_("_Unwrapped"), NULL, NULL, G_CALLBACK(compose_paste_no_wrap_cb) },
{"Edit/SelectAll", NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(compose_allsel_cb) },
ENC_ACTION(CS_ISO_8859_9, C_ISO_8859_9, N_("Turkish (ISO-8859-_9)")), /* RADIO compose_set_encoding_cb */
ENC_ACTION("Cyrillic/"CS_ISO_8859_5, C_ISO_8859_5, "ISO-8859-_5"), /* RADIO compose_set_encoding_cb */
ENC_ACTION("Cyrillic/"CS_KOI8_R, C_KOI8_R, "KOI8-_R"), /* RADIO compose_set_encoding_cb */
+ ENC_ACTION("Cyrillic/"CS_MACCYR, C_MACCYR, "_Mac-Cyrillic"), /* RADIO compose_set_encoding_cb */
ENC_ACTION("Cyrillic/"CS_KOI8_U, C_KOI8_U, "KOI8-_U"), /* RADIO compose_set_encoding_cb */
ENC_ACTION("Cyrillic/"CS_WINDOWS_1251, C_WINDOWS_1251, "Windows-1251"), /* RADIO compose_set_encoding_cb */
ENC_ACTION("Japanese/"CS_ISO_2022_JP, C_ISO_2022_JP, "ISO-2022-_JP"), /* RADIO compose_set_encoding_cb */
static gboolean compose_put_existing_to_front(MsgInfo *info)
{
- GList *compose_list = compose_get_compose_list();
- GList *elem = NULL;
+ const GList *compose_list = compose_get_compose_list();
+ const GList *elem = NULL;
if (compose_list) {
for (elem = compose_list; elem != NULL && elem->data != NULL;
GdkColormap *cmap;
gboolean success[8];
int i;
-#endif
GdkColor color[8];
+#endif
buffer = gtk_text_view_get_buffer(text);
compose->no_wrap_tag = gtk_text_buffer_create_tag(buffer, "no_wrap", NULL);
compose->no_join_tag = gtk_text_buffer_create_tag(buffer, "no_join", NULL);
+#if !GTK_CHECK_VERSION(2, 24, 0)
color[0] = quote_color1;
color[1] = quote_color2;
color[2] = quote_color3;
color[5] = quote_bgcolor3;
color[6] = signature_color;
color[7] = uri_color;
-#if !GTK_CHECK_VERSION(2, 24, 0)
+
cmap = gdk_drawable_get_colormap(gtk_widget_get_window(compose->window));
gdk_colormap_alloc_colors(cmap, color, 8, FALSE, TRUE, success);
for (i = 0; i < 8; i++) {
if (success[i] == FALSE) {
- GtkStyle *style;
-
g_warning("Compose: color allocation failed.\n");
- style = gtk_widget_get_style(GTK_WIDGET(text));
quote_color1 = quote_color2 = quote_color3 =
quote_bgcolor1 = quote_bgcolor2 = quote_bgcolor3 =
signature_color = uri_color = black;
}
Compose *compose_new(PrefsAccount *account, const gchar *mailto,
- GPtrArray *attach_files)
+ GList *attach_files)
{
return compose_generic_new(account, mailto, NULL, attach_files, NULL);
}
{
GtkEditable *entry;
if (folderidentifier) {
+#if !GTK_CHECK_VERSION(2, 24, 0)
combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+#else
+ combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
+#endif
prefs_common.compose_save_to_history = add_history(
prefs_common.compose_save_to_history, folderidentifier);
+#if !GTK_CHECK_VERSION(2, 24, 0)
combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
prefs_common.compose_save_to_history);
+#else
+ combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
+ prefs_common.compose_save_to_history);
+#endif
}
entry = GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(compose->savemsg_combo)));
result = gtk_editable_get_chars(entry, 0, -1);
if (result) {
+#if !GTK_CHECK_VERSION(2, 24, 0)
combobox_unset_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo));
+#else
+ combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo));
+#endif
prefs_common.compose_save_to_history = add_history(
prefs_common.compose_save_to_history, result);
+#if !GTK_CHECK_VERSION(2, 24, 0)
combobox_set_popdown_strings(GTK_COMBO_BOX(compose->savemsg_combo),
prefs_common.compose_save_to_history);
+#else
+ combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(compose->savemsg_combo),
+ prefs_common.compose_save_to_history);
+#endif
}
return result;
}
Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
- GPtrArray *attach_files, GList *listAddress )
+ GList *attach_files, GList *listAddress )
{
Compose *compose;
GtkTextView *textview;
/* mailto defines a from, check if we can get account prefs from it,
if not, the account prefs will be guessed using other ways, but we'll keep
the from anyway */
- if (mailto_from)
+ if (mailto_from) {
mailto_account = account_find_from_address(mailto_from, TRUE);
+ if (mailto_account == NULL) {
+ gchar *tmp_from;
+ Xstrdup_a(tmp_from, mailto_from, return NULL);
+ extract_address(tmp_from);
+ mailto_account = account_find_from_address(tmp_from, TRUE);
+ }
+ }
if (mailto_account)
account = mailto_account;
}
procmsg_msginfo_free( dummyinfo );
if (attach_files) {
- gint i;
- gchar *file;
+ GList *curr;
+ AttachInfo *ainfo;
- for (i = 0; i < attach_files->len; i++) {
- file = g_ptr_array_index(attach_files, i);
- compose_attach_append(compose, file, file, NULL, NULL);
+ for (curr = attach_files ; curr != NULL ; curr = curr->next) {
+ ainfo = (AttachInfo *) curr->data;
+ compose_attach_append(compose, ainfo->file, ainfo->file,
+ ainfo->content_type, ainfo->charset);
}
}
if (prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
- compose->draft_timeout_tag = -1;
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET;
+
SCROLL_TO_CURSOR(compose);
compose->modified = FALSE;
if (override_pref == FALSE && account->default_encrypt_reply == FALSE)
return;
- if (system)
- privacy = system;
- else if (account->default_privacy_system
- && strlen(account->default_privacy_system)) {
+ if (account->default_privacy_system && strlen(account->default_privacy_system))
privacy = account->default_privacy_system;
- } else {
+ else if (system)
+ privacy = system;
+ else {
GSList *privacy_avail = privacy_get_system_ids();
if (privacy_avail && g_slist_length(privacy_avail)) {
privacy = (gchar *)(privacy_avail->data);
if (system) {
g_free(compose->privacy_system);
compose->privacy_system = NULL;
+ g_free(compose->encdata);
+ compose->encdata = NULL;
}
if (compose->privacy_system == NULL)
compose->privacy_system = g_strdup(privacy);
else if (*(compose->privacy_system) == '\0') {
g_free(compose->privacy_system);
+ g_free(compose->encdata);
+ compose->encdata = NULL;
compose->privacy_system = g_strdup(privacy);
}
compose_update_privacy_system_menu_item(compose, FALSE);
{
const gchar *privacy = NULL;
- if (system)
- privacy = system;
- else if (account->default_privacy_system
- && strlen(account->default_privacy_system)) {
+ if (account->default_privacy_system && strlen(account->default_privacy_system))
privacy = account->default_privacy_system;
- } else {
+ else if (system)
+ privacy = system;
+ else {
GSList *privacy_avail = privacy_get_system_ids();
if (privacy_avail && g_slist_length(privacy_avail)) {
privacy = (gchar *)(privacy_avail->data);
if (system) {
g_free(compose->privacy_system);
compose->privacy_system = NULL;
+ g_free(compose->encdata);
+ compose->encdata = NULL;
}
if (compose->privacy_system == NULL)
compose->privacy_system = g_strdup(privacy);
compose_set_title(compose);
compose->updating = FALSE;
- compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
SCROLL_TO_CURSOR(compose);
if (compose->deferred_destroy) {
const gchar *body_fmt = NULL;
MsgInfo *full_msginfo;
- if (prefs_common.fw_quotefmt && *prefs_common.fw_quotefmt)
- body_fmt = gettext(prefs_common.fw_quotefmt);
- else
- body_fmt = "";
-
full_msginfo = procmsg_msginfo_get_full_info(msginfo);
if (!full_msginfo)
full_msginfo = procmsg_msginfo_copy(msginfo);
compose_set_title(compose);
compose->updating = FALSE;
- compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
SCROLL_TO_CURSOR(compose);
if (compose->deferred_destroy) {
compose_set_title(compose);
compose->updating = FALSE;
- compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
SCROLL_TO_CURSOR(compose);
if (compose->deferred_destroy) {
return FALSE;
}
+static gboolean compose_update_folder_hook(gpointer source, gpointer data)
+{
+ FolderUpdateData *hookdata = (FolderUpdateData *)source;
+ Compose *compose = (Compose *)data;
+ FolderItem *old_item = NULL;
+ FolderItem *new_item = NULL;
+ gchar *old_id, *new_id;
+
+ if (!(hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
+ && !(hookdata->update_flags & FOLDER_MOVE_FOLDERITEM))
+ return FALSE;
+
+ old_item = hookdata->item;
+ new_item = hookdata->item2;
+
+ old_id = folder_item_get_identifier(old_item);
+ new_id = new_item ? folder_item_get_identifier(new_item) : g_strdup("NULL");
+
+ if (compose->targetinfo && compose->targetinfo->folder == old_item) {
+ debug_print("updating targetinfo folder: %s -> %s\n", old_id, new_id);
+ compose->targetinfo->folder = new_item;
+ }
+
+ if (compose->replyinfo && compose->replyinfo->folder == old_item) {
+ debug_print("updating replyinfo folder: %s -> %s\n", old_id, new_id);
+ compose->replyinfo->folder = new_item;
+ }
+
+ if (compose->fwdinfo && compose->fwdinfo->folder == old_item) {
+ debug_print("updating fwdinfo folder: %s -> %s\n", old_id, new_id);
+ compose->fwdinfo->folder = new_item;
+ }
+
+ g_free(old_id);
+ g_free(new_id);
+ return FALSE;
+}
+
static void compose_colorize_signature(Compose *compose)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text));
G_CALLBACK(text_inserted), \
compose); \
}
-#define UNBLOCK_WRAP() { \
- compose->autowrap = prev_autowrap; \
- if (compose->autowrap) { \
- gint old = compose->draft_timeout_tag; \
- compose->draft_timeout_tag = -2; \
- compose_wrap_all(compose); \
- compose->draft_timeout_tag = old; \
- } \
- \
- g_signal_handlers_unblock_by_func(G_OBJECT(buffer), \
- G_CALLBACK(compose_changed_cb), \
- compose); \
- g_signal_handlers_unblock_by_func(G_OBJECT(buffer), \
- G_CALLBACK(text_inserted), \
- compose); \
+#define UNBLOCK_WRAP() { \
+ compose->autowrap = prev_autowrap; \
+ if (compose->autowrap) { \
+ gint old = compose->draft_timeout_tag; \
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN; \
+ compose_wrap_all(compose); \
+ compose->draft_timeout_tag = old; \
+ } \
+ \
+ g_signal_handlers_unblock_by_func(G_OBJECT(buffer), \
+ G_CALLBACK(compose_changed_cb), \
+ compose); \
+ g_signal_handlers_unblock_by_func(G_OBJECT(buffer), \
+ G_CALLBACK(text_inserted), \
+ compose); \
}
Compose *compose_reedit(MsgInfo *msginfo, gboolean batch)
}
if (fp != NULL) {
- gboolean prev_autowrap = compose->autowrap;
- GtkTextBuffer *buffer = textbuf;
+ gboolean prev_autowrap;
+ GtkTextBuffer *buffer;
BLOCK_WRAP();
while (fgets(buf, sizeof(buf), fp) != NULL) {
strcrchomp(buf);
compose_set_title(compose);
compose->updating = FALSE;
- compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
SCROLL_TO_CURSOR(compose);
if (compose->deferred_destroy) {
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/AttachFile", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
+ cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
compose->modified = FALSE;
compose_set_title(compose);
compose->updating = FALSE;
- compose->draft_timeout_tag = -1; /* desinhibit auto-drafting after loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET; /* desinhibit auto-drafting after loading */
SCROLL_TO_CURSOR(compose);
if (compose->deferred_destroy) {
return compose;
}
-GList *compose_get_compose_list(void)
+const GList *compose_get_compose_list(void)
{
return compose_list;
}
gchar *tmp = g_strdup(begin);
gchar *o_tmp = tmp;
tmp[cur-begin]='\0';
- cur++;
- begin = cur;
while (*tmp == ' ' || *tmp == '\t')
tmp++;
compose_add_header_entry(compose, header, tmp, pref_type);
case A_SIG:
compose_insert_sig(compose, FALSE);
break;
+ case A_REP_SIG:
+ compose_insert_sig(compose, TRUE);
+ break;
case A_EXTEDITOR:
compose_ext_editor_cb(NULL, compose);
break;
ref_id_list = g_slist_remove
(ref_id_list, ref_id_list->next->data);
} else {
- slist_free_strings(ref_id_list);
- g_slist_free(ref_id_list);
+ slist_free_strings_full(ref_id_list);
return NULL;
}
} else
g_string_append_printf(new_ref, "<%s>", (gchar *)cur->data);
}
- slist_free_strings(ref_id_list);
- g_slist_free(ref_id_list);
+ slist_free_strings_full(ref_id_list);
new_ref_str = new_ref->str;
g_string_free(new_ref, FALSE);
*(strstr(left_from, "@")) = '\0';
}
- if (left_ml && left_from && right_ml && right_from
+ if (right_ml && right_from
&& !strncmp(left_from, left_ml, strlen(left_ml))
&& !strcmp(right_from, right_ml)) {
result = TRUE;
gchar *tmp1 = NULL;
if (!msginfo->from)
return;
- Xstrdup_a(tmp1, msginfo->from, return);
- extract_address(tmp1);
- if (to_all || to_sender ||
- !account_find_from_address(tmp1, FALSE))
+ if (to_sender)
+ compose_entry_append(compose, msginfo->from,
+ COMPOSE_TO, PREF_NONE);
+ else if (to_all) {
+ Xstrdup_a(tmp1, msginfo->from, return);
+ extract_address(tmp1);
compose_entry_append(compose,
- (compose->replyto && !to_sender)
- ? compose->replyto :
- msginfo->from ? msginfo->from : "",
+ (!account_find_from_address(tmp1, FALSE))
+ ? msginfo->from :
+ msginfo->to,
COMPOSE_TO, PREF_NONE);
- else if (!to_all && !to_sender) {
+ } else {
if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
!folder_has_parent_of_type(msginfo->folder, F_OUTBOX) &&
!folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
g_free(addr);
}
- slist_free_strings(cc_list);
- g_slist_free(cc_list);
+ slist_free_strings_full(cc_list);
}
g_free(ac_email);
gint len;
FILE *fp;
gboolean prev_autowrap;
- gboolean badtxt = FALSE;
- struct stat file_stat;
+ GStatBuf file_stat;
int ret;
+ GString *file_contents = NULL;
+ ComposeInsertResult result = COMPOSE_INSERT_SUCCESS;
cm_return_val_if_fail(file != NULL, COMPOSE_INSERT_NO_FILE);
cur_encoding = conv_get_locale_charset_str_no_utf8();
+ file_contents = g_string_new("");
while (fgets(buf, sizeof(buf), fp) != NULL) {
gchar *str;
if (g_utf8_validate(buf, -1, NULL) == TRUE)
str = g_strdup(buf);
- else
+ else {
+ codeconv_set_strict(TRUE);
str = conv_codeset_strdup
(buf, cur_encoding, CS_INTERNAL);
+ codeconv_set_strict(FALSE);
+
+ if (!str) {
+ result = COMPOSE_INSERT_INVALID_CHARACTER;
+ break;
+ }
+ }
if (!str) continue;
/* strip <CR> if DOS/Windows file,
if (str[len] == '\r') str[len] = '\n';
}
- gtk_text_buffer_insert(buffer, &iter, str, -1);
+ file_contents = g_string_append(file_contents, str);
g_free(str);
}
- g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
- G_CALLBACK(text_inserted),
- compose);
- compose->autowrap = prev_autowrap;
- if (compose->autowrap)
- compose_wrap_all(compose);
+ if (result == COMPOSE_INSERT_SUCCESS) {
+ gtk_text_buffer_insert(buffer, &iter, file_contents->str, -1);
+ compose_changed_cb(NULL, compose);
+ g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
+ G_CALLBACK(text_inserted),
+ compose);
+ compose->autowrap = prev_autowrap;
+ if (compose->autowrap)
+ compose_wrap_all(compose);
+ }
+
+ g_string_free(file_contents, TRUE);
fclose(fp);
- if (badtxt)
- return COMPOSE_INSERT_INVALID_CHARACTER;
- else
- return COMPOSE_INSERT_SUCCESS;
+ return result;
}
static gboolean compose_attach_append(Compose *compose, const gchar *file,
alertpanel_error("Can't get file size of %s\n", filename);
return FALSE;
}
- if (size == 0) {
- alertpanel_error(_("File %s is empty."), filename);
- return FALSE;
+
+ /* In batch mode, we allow 0-length files to be attached no questions asked */
+ if (size == 0 && !compose->batch) {
+ gchar * msg = g_strdup_printf(_("File %s is empty."), filename);
+ AlertValue aval = alertpanel_full(_("Empty file"), msg,
+ GTK_STOCK_CANCEL, _("+_Attach anyway"), NULL, FALSE,
+ NULL, ALERT_WARNING, G_ALERTDEFAULT);
+ g_free(msg);
+
+ if (aval != G_ALERTALTERNATE) {
+ return FALSE;
+ }
}
if ((fp = g_fopen(file, "rb")) == NULL) {
alertpanel_error(_("Can't read %s."), filename);
outfile = procmime_get_tmp_file_name(child);
if ((err = procmime_get_part(outfile, child)) < 0)
- g_warning("Can't get the part of multipart message. (%s)", strerror(-err));
+ g_warning("Can't get the part of multipart message. (%s)", g_strerror(-err));
else {
gchar *content_type;
GtkTextIter iter, break_pos, end_of_line;
gchar *quote_str = NULL;
gint quote_len;
- gboolean wrap_quote = prefs_common.linewrap_quote;
+ gboolean wrap_quote = force || prefs_common.linewrap_quote;
gboolean prev_autowrap = compose->autowrap;
gint startq_offset = -1, noq_offset = -1;
gint uri_start = -1, uri_stop = -1;
if (force) {
modified = TRUE;
}
- if (compose->draft_timeout_tag == -2) {
+ if (compose->draft_timeout_tag == COMPOSE_DRAFT_TIMEOUT_FORBIDDEN) {
modified = TRUE;
}
}
- if (compose->draft_timeout_tag == -2) {
+ if (compose->draft_timeout_tag == COMPOSE_DRAFT_TIMEOUT_FORBIDDEN) {
if (gtk_text_iter_ends_line(&iter)) {
while (gtk_text_iter_ends_line(&iter) &&
gtk_text_iter_forward_line(&iter))
buffer = gtk_text_view_get_buffer(text);
gtk_text_buffer_get_start_iter(buffer, &iter);
+
+ undo_wrapping(compose->undostruct, TRUE);
+
while (!gtk_text_iter_is_end(&iter) && modified)
modified = compose_beautify_paragraph(compose, &iter, force);
+ undo_wrapping(compose->undostruct, FALSE);
+
}
static void compose_set_title(Compose *compose)
#define QUOTE_IF_REQUIRED(out, str) \
{ \
- if (*str != '"' && strpbrk(str, ",.[]<>")) { \
+ if (*str != '"' && strpbrk(str, ",.:;[]<>()@\\\"")) { \
gchar *__tmp; \
gint len; \
\
#define QUOTE_IF_REQUIRED_NORMAL(out, str, errret) \
{ \
- if (*str != '"' && strpbrk(str, ",.[]<>")) { \
+ if (*str != '"' && strpbrk(str, ",.:;[]<>()@\\\"")) { \
gchar *__tmp; \
gint len; \
\
static void compose_select_account(Compose *compose, PrefsAccount *account,
gboolean init)
{
- gchar *from = NULL, *header;
+ gchar *from = NULL, *header = NULL;
ComposeHeaderEntry *header_entry;
+#if GTK_CHECK_VERSION(2, 24, 0)
+ GtkTreeIter iter;
+#endif
cm_return_if_fail(account != NULL);
compose->account = account;
if (account->name && *account->name) {
- gchar *buf;
+ gchar *buf, *qbuf;
QUOTE_IF_REQUIRED_NORMAL(buf, account->name, return);
+ qbuf = escape_internal_quotes(buf, '"');
from = g_strdup_printf("%s <%s>",
- buf, account->address);
+ qbuf, account->address);
+ if (qbuf != buf)
+ g_free(qbuf);
gtk_entry_set_text(GTK_ENTRY(compose->from_name), from);
} else {
from = g_strdup_printf("<%s>",
}
header_entry = (ComposeHeaderEntry *) compose->header_list->data;
+#if !GTK_CHECK_VERSION(2, 24, 0)
header = gtk_combo_box_get_active_text(GTK_COMBO_BOX(header_entry->combo));
+#else
+ if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(header_entry->combo), &iter))
+ gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(
+ header_entry->combo)), &iter, COMBOBOX_TEXT, &header, -1);
+#endif
if (header && !strlen(gtk_entry_get_text(GTK_ENTRY(header_entry->entry)))) {
if (account->protocol == A_NNTP) {
gchar **strptr;
/* free to and newsgroup list */
- slist_free_strings(compose->to_list);
- g_slist_free(compose->to_list);
+ slist_free_strings_full(compose->to_list);
compose->to_list = NULL;
- slist_free_strings(compose->newsgroup_list);
- g_slist_free(compose->newsgroup_list);
+ slist_free_strings_full(compose->newsgroup_list);
compose->newsgroup_list = NULL;
/* search header entries for to and newsgroup entries */
return FALSE;
}
- if (!compose->batch) {
+ if (!compose->batch && prefs_common.warn_empty_subj == TRUE) {
str = gtk_entry_get_text(GTK_ENTRY(compose->subject_entry));
- if (*str == '\0' && check_everything == TRUE &&
+ if (*str == '\0' && check_everything == TRUE &&
compose->mode != COMPOSE_REDIRECT) {
AlertValue aval;
gchar *button_label;
compose->sending?_("Send it anyway?"):
_("Queue it anyway?"));
- aval = alertpanel(compose->sending?_("Send"):_("Send later"), message,
- GTK_STOCK_CANCEL, button_label, NULL);
+ aval = alertpanel_full(compose->sending?_("Send"):_("Send later"), message,
+ GTK_STOCK_CANCEL, button_label, NULL, TRUE, NULL,
+ ALERT_QUESTION, G_ALERTDEFAULT);
g_free(message);
+ if (aval & G_ALERTDISABLE) {
+ aval &= ~G_ALERTDISABLE;
+ prefs_common.warn_empty_subj = FALSE;
+ }
if (aval != G_ALERTALTERNATE)
return FALSE;
}
alertpanel_error(_("Could not queue message for sending:\n\n"
"Signature failed: %s"), privacy_get_error());
} else if (val == -2 && errno != 0) {
- alertpanel_error(_("Could not queue message for sending:\n\n%s."), strerror(errno));
+ alertpanel_error(_("Could not queue message for sending:\n\n%s."), g_strerror(errno));
} else {
alertpanel_error(_("Could not queue message for sending."));
}
}
generate_msgid(buf, sizeof(buf), addr);
err |= (fprintf(fp, "Resent-Message-ID: <%s>\n", buf) < 0);
+ if (compose->msgid)
+ g_free(compose->msgid);
compose->msgid = g_strdup(buf);
} else {
compose->msgid = NULL;
{
GtkTextBuffer *buffer;
GtkTextIter start, end;
- gchar *chars;
- gchar *buf;
+ gchar *chars, *tmp_enc_file, *content;
+ gchar *buf, *msg;
const gchar *out_codeset;
EncodingType encoding = ENC_UNKNOWN;
MimeInfo *mimemsg, *mimetext;
const gchar *src_codeset = CS_INTERNAL;
gchar *from_addr = NULL;
gchar *from_name = NULL;
+ FolderItem *outbox;
if (action == COMPOSE_WRITE_FOR_SEND)
attach_parts = TRUE;
if (!buf) {
AlertValue aval;
- gchar *msg;
msg = g_strdup_printf(_("Can't convert the character encoding of the message \n"
"to the specified %s charset.\n"
encoding != ENC_QUOTED_PRINTABLE && encoding != ENC_BASE64 &&
check_line_length(buf, 1000, &line) < 0) {
AlertValue aval;
- gchar *msg;
msg = g_strdup_printf
(_("Line %d exceeds the line length limit (998 bytes).\n"
}
g_free(from_name);
g_free(from_addr);
+
+ if (compose->use_encryption) {
+ if (compose->encdata != NULL &&
+ strcmp(compose->encdata, "_DONT_ENCRYPT_")) {
+
+ /* First, write an unencrypted copy and save it to outbox, if
+ * user wants that. */
+ if (compose->account->save_encrypted_as_clear_text) {
+ debug_print("saving sent message unencrypted...\n");
+ FILE *tmpfp = get_tmpfile_in_dir(get_mime_tmp_dir(), &tmp_enc_file);
+ if (tmpfp) {
+ fclose(tmpfp);
+
+ /* fp now points to a file with headers written,
+ * let's make a copy. */
+ rewind(fp);
+ content = file_read_stream_to_str(fp);
+
+ str_write_to_file(content, tmp_enc_file);
+ g_free(content);
+
+ /* Now write the unencrypted body. */
+ if ((tmpfp = g_fopen(tmp_enc_file, "a")) != NULL) {
+ procmime_write_mimeinfo(mimemsg, tmpfp);
+ fclose(tmpfp);
+
+ outbox = folder_find_item_from_identifier(compose_get_save_to(compose));
+ if (!outbox)
+ outbox = folder_get_default_outbox();
+
+ procmsg_save_to_outbox(outbox, tmp_enc_file, TRUE);
+ claws_unlink(tmp_enc_file);
+ } else {
+ g_warning("Can't open file %s\n", tmp_enc_file);
+ }
+ } else {
+ g_warning("couldn't get tempfile\n");
+ }
+ }
+ if (!privacy_encrypt(compose->privacy_system, mimemsg, compose->encdata)) {
+ debug_print("Couldn't encrypt mime structure: %s.\n",
+ privacy_get_error());
+ alertpanel_error(_("Couldn't encrypt the email: %s"),
+ privacy_get_error());
+ }
+ }
+ }
+
procmime_write_mimeinfo(mimemsg, fp);
procmime_mimeinfo_free_all(mimemsg);
(tmp, CS_INTERNAL, conv_get_locale_charset_str());
g_free(tmp);
- if (!chars) return -1;
-
+ if (!chars) {
+ fclose(fp);
+ claws_unlink(file);
+ return -1;
+ }
/* write body */
len = strlen(chars);
if (fwrite(chars, sizeof(gchar), len, fp) != len) {
FILE *fp;
GSList *cur;
gint num;
- static gboolean lock = FALSE;
PrefsAccount *mailac = NULL, *newsac = NULL;
gboolean err = FALSE;
debug_print("queueing message...\n");
cm_return_val_if_fail(compose->account != NULL, -1);
- lock = TRUE;
-
if (compose_check_entries(compose, check_subject) == FALSE) {
- lock = FALSE;
if (compose->batch) {
gtk_widget_show_all(compose->window);
}
if (!compose->to_list && !compose->newsgroup_list) {
g_warning("can't get recipient list.");
- lock = FALSE;
return -1;
}
else if (cur_account && cur_account->protocol != A_NNTP)
mailac = cur_account;
else if (!(mailac = compose_current_mail_account())) {
- lock = FALSE;
alertpanel_error(_("No account for sending mails available!"));
return -1;
}
if (compose->account->protocol == A_NNTP)
newsac = compose->account;
else {
- lock = FALSE;
alertpanel_error(_("Selected account isn't NNTP: Posting is impossible."));
return -1;
}
tmp = g_strdup_printf("%s%cqueue.%p%08x", get_tmp_dir(),
G_DIR_SEPARATOR, compose, (guint) rand());
debug_print("queuing to %s\n", tmp);
- if ((fp = g_fopen(tmp, "wb")) == NULL) {
+ if ((fp = g_fopen(tmp, "w+b")) == NULL) {
FILE_OP_ERROR(tmp, "fopen");
g_free(tmp);
- lock = FALSE;
return -2;
}
err |= (fprintf(fp, "X-Claws-Privacy-System:%s\n", compose->privacy_system) < 0);
err |= (fprintf(fp, "X-Claws-Sign:%d\n", compose->use_signing) < 0);
if (compose->use_encryption) {
- gchar *encdata;
if (!compose_warn_encryption(compose)) {
- lock = FALSE;
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
if (mailac && mailac->encrypt_to_self) {
GSList *tmp_list = g_slist_copy(compose->to_list);
tmp_list = g_slist_append(tmp_list, compose->account->address);
- encdata = privacy_get_encrypt_data(compose->privacy_system, tmp_list);
+ compose->encdata = privacy_get_encrypt_data(compose->privacy_system, tmp_list);
g_slist_free(tmp_list);
} else {
- encdata = privacy_get_encrypt_data(compose->privacy_system, compose->to_list);
+ compose->encdata = privacy_get_encrypt_data(compose->privacy_system, compose->to_list);
}
- if (encdata != NULL) {
- if (strcmp(encdata, "_DONT_ENCRYPT_")) {
+ if (compose->encdata != NULL) {
+ if (strcmp(compose->encdata, "_DONT_ENCRYPT_")) {
err |= (fprintf(fp, "X-Claws-Encrypt:%d\n", compose->use_encryption) < 0);
err |= (fprintf(fp, "X-Claws-Encrypt-Data:%s\n",
- encdata) < 0);
+ compose->encdata) < 0);
} /* else we finally dont want to encrypt */
} else {
err |= (fprintf(fp, "X-Claws-Encrypt:%d\n", compose->use_encryption) < 0);
/* and if encdata was null, it means there's been a problem in
* key selection */
- lock = FALSE;
+ if (err == TRUE)
+ g_warning("failed to write queue message");
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
return -5;
}
- g_free(encdata);
}
}
}
/* Message-ID of message replying to */
if ((compose->replyinfo != NULL) && (compose->replyinfo->msgid != NULL)) {
- gchar *folderid;
-
- folderid = folder_item_get_identifier(compose->replyinfo->folder);
+ gchar *folderid = NULL;
+
+ if (compose->replyinfo->folder)
+ folderid = folder_item_get_identifier(compose->replyinfo->folder);
+ if (folderid == NULL)
+ folderid = g_strdup("NULL");
+
err |= (fprintf(fp, "RMID:%s\t%d\t%s\n", folderid, compose->replyinfo->msgnum, compose->replyinfo->msgid) < 0);
g_free(folderid);
}
/* Message-ID of message forwarding to */
if ((compose->fwdinfo != NULL) && (compose->fwdinfo->msgid != NULL)) {
- gchar *folderid;
+ gchar *folderid = NULL;
- folderid = folder_item_get_identifier(compose->fwdinfo->folder);
+ if (compose->fwdinfo->folder)
+ folderid = folder_item_get_identifier(compose->fwdinfo->folder);
+ if (folderid == NULL)
+ folderid = g_strdup("NULL");
+
err |= (fprintf(fp, "FMID:%s\t%d\t%s\n", folderid, compose->fwdinfo->msgnum, compose->fwdinfo->msgid) < 0);
g_free(folderid);
}
if (compose->redirect_filename != NULL) {
if (compose_redirect_write_to_file(compose, fp) < 0) {
- lock = FALSE;
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
} else {
gint result = 0;
if ((result = compose_write_to_file(compose, fp, COMPOSE_WRITE_FOR_SEND, TRUE)) < 0) {
- lock = FALSE;
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
- lock = FALSE;
return -2;
}
if (fclose(fp) == EOF) {
FILE_OP_ERROR(tmp, "fclose");
claws_unlink(tmp);
g_free(tmp);
- lock = FALSE;
return -2;
}
g_warning("can't find queue folder\n");
claws_unlink(tmp);
g_free(tmp);
- lock = FALSE;
return -1;
}
folder_item_scan(queue);
g_warning("can't queue the message\n");
claws_unlink(tmp);
g_free(tmp);
- lock = FALSE;
return -1;
}
AttachInfo *ainfo;
GtkTreeView *tree_view = GTK_TREE_VIEW(compose->attach_clist);
MimeInfo *mimepart;
- struct stat statbuf;
+ GStatBuf statbuf;
gchar *type, *subtype;
GtkTreeModel *model;
GtkTreeIter iter;
}
continue;
}
+ if (g_stat(ainfo->file, &statbuf) < 0)
+ return -1;
+
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;
-
- g_stat(ainfo->file, &statbuf);
mimepart->length = statbuf.st_size;
type = g_strdup(ainfo->content_type);
!g_ascii_strcasecmp(mimepart->subtype, "rfc822")) {
mimepart->disposition = DISPOSITIONTYPE_INLINE;
} else if (mimepart->type == MIMETYPE_TEXT) {
- if (!ainfo->name && compose->mode == COMPOSE_FORWARD_INLINE) {
+ if (!ainfo->name && g_ascii_strcasecmp(mimepart->subtype, "plain")) {
/* Text parts with no name come from multipart/alternative
* forwards. Make sure the recipient won't look at the
* original HTML part by mistake. */
return 0;
}
+static gchar *compose_quote_list_of_addresses(gchar *str)
+{
+ GSList *list = NULL, *item = NULL;
+ gchar *qname = NULL, *faddr = NULL, *result = NULL;
+
+ list = address_list_append_with_comments(list, str);
+ for (item = list; item != NULL; item = item->next) {
+ gchar *spec = item->data;
+ gchar *endofname = strstr(spec, " <");
+ if (endofname != NULL) {
+ gchar * qqname;
+ *endofname = '\0';
+ QUOTE_IF_REQUIRED_NORMAL(qname, spec, return NULL);
+ qqname = escape_internal_quotes(qname, '"');
+ *endofname = ' ';
+ if (*qname != *spec || qqname != qname) { /* has been quoted, compute new */
+ gchar *addr = g_strdup(endofname);
+ gchar *name = (qqname != qname)? qqname: g_strdup(qname);
+ faddr = g_strconcat(name, addr, NULL);
+ g_free(name);
+ g_free(addr);
+ debug_print("new auto-quoted address: '%s'", faddr);
+ }
+ }
+ if (result == NULL)
+ result = g_strdup((faddr != NULL)? faddr: spec);
+ else {
+ result = g_strconcat(result,
+ ", ",
+ (faddr != NULL)? faddr: spec,
+ NULL);
+ }
+ if (faddr != NULL) {
+ g_free(faddr);
+ faddr = NULL;
+ }
+ }
+ slist_free_strings_full(list);
+
+ return result;
+}
+
#define IS_IN_CUSTOM_HEADER(header) \
(compose->account->add_customhdr && \
custom_header_find(compose->account->customhdr_list, header) != NULL)
headerentryname = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((headerentry->combo)))));
if (!g_utf8_collate(trans_fieldname, headerentryname)) {
- str = gtk_editable_get_chars(GTK_EDITABLE(headerentry->entry), 0, -1);
- g_strstrip(str);
- if (str[0] != '\0') {
+ gchar * ustr = gtk_editable_get_chars(GTK_EDITABLE(headerentry->entry), 0, -1);
+ g_strstrip(ustr);
+ str = compose_quote_list_of_addresses(ustr);
+ g_free(ustr);
+ if (str != NULL && str[0] != '\0') {
if (add_field)
g_string_append(fieldstr, seperator);
g_string_append(fieldstr, str);
if (from_name && *from_name) {
+ gchar *qname;
compose_convert_header
(compose, buf, sizeof(buf), from_name,
strlen("From: "), TRUE);
QUOTE_IF_REQUIRED(name, buf);
+ qname = escape_internal_quotes(name, '"');
g_string_append_printf(header, "From: %s <%s>\n",
- name, from_address);
+ qname, from_address);
+ if (qname != name)
+ g_free(qname);
} else
g_string_append_printf(header, "From: %s\n", from_address);
}
generate_msgid(buf, sizeof(buf), addr);
g_string_append_printf(header, "Message-ID: <%s>\n", buf);
+ if (compose->msgid)
+ g_free(compose->msgid);
compose->msgid = g_strdup(buf);
} else {
compose->msgid = NULL;
gtk_major_version, gtk_minor_version, gtk_micro_version,
TARGET_ALIAS);
}
- if (g_slist_length(compose->newsgroup_list) && !IS_IN_CUSTOM_HEADER("X-Newsreader")) {
+ if (compose->account->gen_xmailer &&
+ g_slist_length(compose->newsgroup_list) && !IS_IN_CUSTOM_HEADER("X-Newsreader")) {
g_string_append_printf(header, "X-Newsreader: %s (GTK+ %d.%d.%d; %s)\n",
prog_version,
gtk_major_version, gtk_minor_version, gtk_micro_version,
if (*address != '\0') {
gchar *name = procheader_get_fromname(address);
extract_address(address);
+#ifndef USE_NEW_ADDRBOOK
addressbook_add_contact(name, address, NULL, NULL);
+#else
+ debug_print("%s: %s\n", name, address);
+ if (addressadd_selection(name, address, NULL, NULL)) {
+ debug_print( "addressbook_add_contact - added\n" );
+ }
+#endif
}
g_free(address);
}
gtk_widget_show(menuitem);
}
+void compose_add_extra_header(gchar *header, GtkListStore *model)
+{
+ GtkTreeIter iter;
+ if (strcmp(header, "")) {
+ COMBOBOX_ADD(model, header, COMPOSE_TO);
+ }
+}
+
+void compose_add_extra_header_entries(GtkListStore *model)
+{
+ FILE *exh;
+ gchar *exhrc;
+ gchar buf[BUFFSIZE];
+ gint lastc;
+
+ if (extra_headers == NULL) {
+ exhrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "extraheaderrc", NULL);
+ if ((exh = g_fopen(exhrc, "rb")) == NULL) {
+ debug_print("extra headers file not found\n");
+ goto extra_headers_done;
+ }
+ while (fgets(buf, BUFFSIZE, exh) != NULL) {
+ lastc = strlen(buf) - 1; /* remove trailing control chars */
+ while (lastc >= 0 && buf[lastc] != ':')
+ buf[lastc--] = '\0';
+ if (lastc > 0 && buf[0] != '#' && buf[lastc] == ':') {
+ buf[lastc] = '\0'; /* remove trailing : for comparison */
+ if (custom_header_is_allowed(buf)) {
+ buf[lastc] = ':';
+ extra_headers = g_slist_prepend(extra_headers, g_strdup(buf));
+ }
+ else
+ g_message("disallowed extra header line: %s\n", buf);
+ }
+ else {
+ if (buf[0] != '#')
+ g_message("invalid extra header line: %s\n", buf);
+ }
+ }
+ fclose(exh);
+extra_headers_done:
+ g_free(exhrc);
+ extra_headers = g_slist_prepend(extra_headers, g_strdup("")); /* end of list */
+ extra_headers = g_slist_reverse(extra_headers);
+ }
+ g_slist_foreach(extra_headers, (GFunc)compose_add_extra_header, (gpointer)model);
+}
+
static void compose_create_header_entry(Compose *compose)
{
gchar *headers[] = {"To:", "Cc:", "Bcc:", "Newsgroups:", "Reply-To:", "Followup-To:", NULL};
gboolean standard_header = FALSE;
GtkListStore *model;
GtkTreeIter iter;
-#if !(GTK_CHECK_VERSION(2,12,0))
- GtkTooltips *tips = compose->tooltips;
-#endif
headerentry = g_new0(ComposeHeaderEntry, 1);
- /* Combo box */
+ /* Combo box model */
model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
+#if !GTK_CHECK_VERSION(2, 24, 0)
combo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(model), 0);
+#endif
COMBOBOX_ADD(model, prefs_common_translated_header_name("To:"),
COMPOSE_TO);
COMBOBOX_ADD(model, prefs_common_translated_header_name("Cc:"),
COMPOSE_REPLYTO);
COMBOBOX_ADD(model, prefs_common_translated_header_name("Followup-To:"),
COMPOSE_FOLLOWUPTO);
+ compose_add_extra_header_entries(model);
+ /* Combo box */
+#if GTK_CHECK_VERSION(2, 24, 0)
+ combo = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(model));
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+ gtk_cell_renderer_set_alignment(cell, 0.0, 0.5);
+ gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
+ gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combo), 0);
+#endif
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
- g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN((combo)))), "grab_focus",
+ g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN(combo))), "grab_focus",
G_CALLBACK(compose_grab_focus_cb), compose);
gtk_widget_show(combo);
+
+ /* Putting only the combobox child into focus chain of its parent causes
+ * the parent to be skipped when changing focus via Tab or Shift+Tab.
+ * This eliminates need to pres Tab twice in order to really get from the
+ * combobox to next widget. */
+ GList *l = NULL;
+ l = g_list_prepend(l, gtk_bin_get_child(GTK_BIN(combo)));
+ gtk_container_set_focus_chain(GTK_CONTAINER(combo), l);
+ g_list_free(l);
+
gtk_table_attach(GTK_TABLE(compose->header_table), combo, 0, 1,
compose->header_nextrow, compose->header_nextrow+1,
GTK_SHRINK, GTK_FILL, 0, 0);
- if (compose->header_last && (compose->draft_timeout_tag != -2)) {
+ if (compose->header_last && (compose->draft_timeout_tag != COMPOSE_DRAFT_TIMEOUT_FORBIDDEN)) {
const gchar *last_header_entry = gtk_entry_get_text(
GTK_ENTRY(gtk_bin_get_child(GTK_BIN((compose->header_last->combo)))));
string = headers;
static GtkWidget *compose_create_header(Compose *compose)
{
GtkWidget *from_optmenu_hbox;
+ GtkWidget *header_scrolledwin_main;
+ GtkWidget *header_table_main;
GtkWidget *header_scrolledwin;
GtkWidget *header_table;
- gint count = 0;
+ /* parent with account selection and from header */
+ header_scrolledwin_main = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_show(header_scrolledwin_main);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(header_scrolledwin_main), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- /* header labels and entries */
+ header_table_main = gtk_table_new(2, 2, FALSE);
+ gtk_widget_show(header_table_main);
+ gtk_container_set_border_width(GTK_CONTAINER(header_table_main), BORDER_WIDTH);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(header_scrolledwin_main), header_table_main);
+ gtk_viewport_set_shadow_type(GTK_VIEWPORT(gtk_bin_get_child(GTK_BIN((header_scrolledwin_main)))), GTK_SHADOW_NONE);
+
+ from_optmenu_hbox = compose_account_option_menu_create(compose);
+ gtk_table_attach(GTK_TABLE(header_table_main), from_optmenu_hbox,
+ 0, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+
+ /* child with header labels and entries */
header_scrolledwin = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(header_scrolledwin);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(header_scrolledwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
header_table = gtk_table_new(2, 2, FALSE);
gtk_widget_show(header_table);
- gtk_container_set_border_width(GTK_CONTAINER(header_table), BORDER_WIDTH);
+ gtk_container_set_border_width(GTK_CONTAINER(header_table), 0);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(header_scrolledwin), header_table);
- gtk_viewport_set_shadow_type(GTK_VIEWPORT(gtk_bin_get_child(GTK_BIN((header_scrolledwin)))), GTK_SHADOW_NONE);
- count = 0;
+ gtk_container_set_focus_vadjustment(GTK_CONTAINER(header_table),
+ gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(header_scrolledwin)));
+ gtk_viewport_set_shadow_type(GTK_VIEWPORT(gtk_bin_get_child(GTK_BIN(header_scrolledwin))), GTK_SHADOW_NONE);
- /* option menu for selecting accounts */
- from_optmenu_hbox = compose_account_option_menu_create(compose);
- gtk_table_attach(GTK_TABLE(header_table), from_optmenu_hbox,
- 0, 2, count, count + 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
- count++;
+ gtk_table_attach(GTK_TABLE(header_table_main), header_scrolledwin,
+ 0, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 2);
compose->header_table = header_table;
compose->header_list = NULL;
- compose->header_nextrow = count;
+ compose->header_nextrow = 0;
compose_create_header_entry(compose);
- compose->table = NULL;
+ compose->table = NULL;
- return header_scrolledwin ;
+ return header_scrolledwin_main;
}
static gboolean popup_attach_button_pressed(GtkWidget *widget, gpointer data)
G_CALLBACK(attach_selected), compose);
g_signal_connect(G_OBJECT(attach_clist), "button_press_event",
G_CALLBACK(attach_button_pressed), compose);
-#ifndef MAEMO
g_signal_connect(G_OBJECT(attach_clist), "popup-menu",
G_CALLBACK(popup_attach_button_pressed), compose);
-#else
- gtk_widget_tap_and_hold_setup(GTK_WIDGET(attach_clist), NULL, NULL,
- GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
- g_signal_connect(G_OBJECT(attach_clist), "tap-and-hold",
- G_CALLBACK(popup_attach_button_pressed), compose);
-#endif
g_signal_connect(G_OBJECT(attach_clist), "key_press_event",
G_CALLBACK(attach_key_pressed), compose);
g_signal_connect(G_OBJECT(savemsg_checkbtn), "toggled",
G_CALLBACK(compose_savemsg_checkbtn_cb), compose);
+#if !GTK_CHECK_VERSION(2, 24, 0)
savemsg_combo = gtk_combo_box_entry_new_text();
+#else
+ savemsg_combo = gtk_combo_box_text_new_with_entry();
+#endif
compose->savemsg_checkbtn = savemsg_checkbtn;
compose->savemsg_combo = savemsg_combo;
gtk_widget_show(savemsg_combo);
if (prefs_common.compose_save_to_history)
+#if !GTK_CHECK_VERSION(2, 24, 0)
combobox_set_popdown_strings(GTK_COMBO_BOX(savemsg_combo),
prefs_common.compose_save_to_history);
-
+#else
+ combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(savemsg_combo),
+ prefs_common.compose_save_to_history);
+#endif
gtk_table_attach(GTK_TABLE(table), savemsg_combo, 1, 2, rowcount, rowcount + 1, GTK_FILL|GTK_EXPAND, GTK_SHRINK, 0, 0);
gtk_widget_set_sensitive(GTK_WIDGET(savemsg_combo), prefs_common.savemsg);
g_signal_connect_after(G_OBJECT(savemsg_combo), "grab_focus",
G_CALLBACK(compose_savemsg_select_cb),
compose);
- rowcount++;
-
return table;
}
{
Compose *compose = (Compose *) data;
- if(compose->gtkaspell &&
- compose->gtkaspell->recheck_when_changing_dict == FALSE)
+ if(!compose->gtkaspell)
+ return;
+ if(compose->gtkaspell->recheck_when_changing_dict == FALSE)
return;
gtkaspell_highlight_all(compose->gtkaspell);
UndoMain *undostruct;
- gchar *titles[N_ATTACH_COLS];
GtkWidget *popupmenu;
GtkWidget *tmpl_menu;
GtkActionGroup *action_group = NULL;
debug_print("Creating compose window...\n");
compose = g_new0(Compose, 1);
- titles[COL_MIMETYPE] = _("MIME type");
- titles[COL_SIZE] = _("Size");
- titles[COL_NAME] = _("Name");
- titles[COL_CHARSET] = _("Charset");
-
compose->batch = batch;
compose->account = account;
compose->folder = folder;
- compose->mutex = g_mutex_new();
+ compose->mutex = cm_mutex_new();
compose->set_cursor_pos = -1;
-#if !(GTK_CHECK_VERSION(2,12,0))
- compose->tooltips = tips;
-#endif
-
window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose");
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
gtk_action_group_add_radio_actions(action_group, compose_radio_enc_entries,
G_N_ELEMENTS(compose_radio_enc_entries), C_AUTO, G_CALLBACK(compose_set_encoding_cb), (gpointer)compose);
-#ifndef MAEMO
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
-#else
- MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_POPUP)
-#endif
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu", "Message", "Message", GTK_UI_MANAGER_MENU)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "AttachFile", "Message/AttachFile", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "InsertFile", "Message/InsertFile", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "InsertSig", "Message/InsertSig", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "ReplaceSig", "Message/ReplaceSig", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Separator2", "Message/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Save", "Message/Save", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Separator3", "Message/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding", "Cyrillic", "Options/Encoding/Cyrillic", GTK_UI_MANAGER_MENU)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding/Cyrillic", CS_ISO_8859_5, "Options/Encoding/Cyrillic/"CS_ISO_8859_5, GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding/Cyrillic", CS_KOI8_R, "Options/Encoding/Cyrillic/"CS_KOI8_R, GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding/Cyrillic", CS_MACCYR, "Options/Encoding/Cyrillic/"CS_MACCYR, GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding/Cyrillic", CS_KOI8_U, "Options/Encoding/Cyrillic/"CS_KOI8_U, GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Options/Encoding/Cyrillic", CS_WINDOWS_1251, "Options/Encoding/Cyrillic/"CS_WINDOWS_1251, GTK_UI_MANAGER_MENUITEM)
gtk_widget_show_all(menubar);
gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(compose->ui_manager));
-#ifndef MAEMO
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
-#else
- hildon_window_set_menu(HILDON_WINDOW(window), GTK_MENU(menubar));
-#endif
if (prefs_common.toolbar_detachable) {
handlebox = gtk_handle_box_new();
gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
gtk_widget_realize(handlebox);
-#ifdef MAEMO
- compose->toolbar = toolbar_create(TOOLBAR_COMPOSE, window,
- (gpointer)compose);
-#else
compose->toolbar = toolbar_create(TOOLBAR_COMPOSE, handlebox,
(gpointer)compose);
-#endif
vbox2 = gtk_vbox_new(FALSE, 2);
gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
/* Notebook */
notebook = gtk_notebook_new();
- gtk_widget_set_size_request(notebook, -1, prefs_common.compose_notebook_height);
gtk_widget_show(notebook);
/* header labels and entries */
gtk_container_set_border_width(GTK_CONTAINER(subject), 0);
gtk_widget_show(subject);
- label = gtk_label_new(_("Subject:"));
+ label = gtk_label_new_with_mnemonic(_("S_ubject:"));
gtk_box_pack_start(GTK_BOX(subject), label, FALSE, FALSE, 0);
gtk_widget_show(label);
gtk_box_pack_start(GTK_BOX(subject), subject_entry, TRUE, TRUE, 0);
g_signal_connect_after(G_OBJECT(subject_entry), "grab_focus",
G_CALLBACK(compose_grab_focus_cb), compose);
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), subject_entry);
gtk_widget_show(subject_entry);
compose->subject_entry = subject_entry;
gtk_container_add(GTK_CONTAINER(subject_frame), subject);
gtk_text_buffer_add_selection_clipboard(buffer, clipboard);
gtk_container_add(GTK_CONTAINER(scrolledwin), text);
- g_signal_connect(G_OBJECT(notebook), "size_allocate",
- G_CALLBACK(compose_notebook_size_alloc), compose);
g_signal_connect_after(G_OBJECT(text), "size_allocate",
G_CALLBACK(compose_edit_size_alloc),
ruler);
G_CALLBACK(text_inserted), compose);
g_signal_connect(G_OBJECT(text), "button_press_event",
G_CALLBACK(text_clicked), compose);
-#ifndef MAEMO
g_signal_connect(G_OBJECT(text), "popup-menu",
G_CALLBACK(compose_popup_menu), compose);
-#else
- gtk_widget_tap_and_hold_setup(GTK_WIDGET(text), NULL, NULL,
- GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
- g_signal_connect(G_OBJECT(text), "tap-and-hold",
- G_CALLBACK(compose_popup_menu), compose);
-#endif
g_signal_connect(G_OBJECT(subject_entry), "changed",
- G_CALLBACK(compose_changed_cb), compose);
+ G_CALLBACK(compose_changed_cb), compose);
+ g_signal_connect(G_OBJECT(subject_entry), "activate",
+ G_CALLBACK(compose_subject_entry_activated), compose);
/* drag and drop */
gtk_drag_dest_set(text, GTK_DEST_DEFAULT_ALL, compose_mime_types,
g_signal_connect(G_OBJECT(text), "drag-drop",
G_CALLBACK(compose_drag_drop),
compose);
+ g_signal_connect(G_OBJECT(text), "key-press-event",
+ G_CALLBACK(completion_set_focus_to_subject),
+ compose);
gtk_widget_show_all(vbox);
/* pane between attach clist and text */
paned = gtk_vpaned_new();
gtk_container_add(GTK_CONTAINER(vbox2), paned);
-#ifdef MAEMO
- if( maemo_mainwindow_is_fullscreen(mainwindow_get_mainwindow()->window) )
- gtk_widget_set_size_request(edit_vbox, -1, mode == COMPOSE_NEW ? 300 : 280);
- else
- gtk_widget_set_size_request(edit_vbox, -1, mode == COMPOSE_NEW ? 250 : 230);
-#endif
- gtk_paned_add1(GTK_PANED(paned), notebook);
- gtk_paned_add2(GTK_PANED(paned), edit_vbox);
+ gtk_paned_pack1(GTK_PANED(paned), notebook, FALSE, FALSE);
+ gtk_paned_pack2(GTK_PANED(paned), edit_vbox, TRUE, FALSE);
+ gtk_paned_set_position(GTK_PANED(paned), prefs_common.compose_notebook_height);
+ g_signal_connect(G_OBJECT(notebook), "size_allocate",
+ G_CALLBACK(compose_notebook_size_alloc), paned);
+
gtk_widget_show_all(paned);
compose->use_signing = FALSE;
compose->use_encryption = FALSE;
compose->privacy_system = NULL;
+ compose->encdata = NULL;
compose->modified = FALSE;
compose->exteditor_file = NULL;
compose->exteditor_pid = -1;
compose->exteditor_tag = -1;
- compose->draft_timeout_tag = -2; /* inhibit auto-drafting while loading */
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN; /* inhibit auto-drafting while loading */
+
+ compose->folder_update_callback_id =
+ hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
+ compose_update_folder_hook,
+ (gpointer) compose);
#if USE_ENCHANT
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Spelling", FALSE);
gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((compose->header_last->combo)))),
prefs_common_translated_header_name("Newsgroups:"));
+#ifndef USE_NEW_ADDRBOOK
addressbook_set_target_compose(compose);
-
+#endif
if (mode != COMPOSE_REDIRECT)
compose_set_template_menu(compose);
else {
gtk_widget_realize(window);
} else {
gtk_widget_show(window);
-#ifdef MAEMO
- maemo_window_full_screen_if_needed(GTK_WINDOW(window));
- maemo_connect_key_press_to_mainwindow(GTK_WINDOW(window));
-#endif
}
return compose;
GtkWidget *hbox;
GtkWidget *optmenu;
GtkWidget *optmenubox;
+ GtkWidget *fromlabel;
GtkListStore *menu;
GtkTreeIter iter;
GtkWidget *from_name = NULL;
-#if !(GTK_CHECK_VERSION(2,12,0))
- GtkTooltips *tips = compose->tooltips;
-#endif
gint num = 0, def_menu = 0;
optmenu = gtkut_sc_combobox_create(optmenubox, FALSE);
menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(optmenu)));
- hbox = gtk_hbox_new(FALSE, 6);
+ hbox = gtk_hbox_new(FALSE, 4);
from_name = gtk_entry_new();
g_signal_connect_after(G_OBJECT(from_name), "grab_focus",
G_CALLBACK(compose_grab_focus_cb), compose);
+ g_signal_connect_after(G_OBJECT(from_name), "activate",
+ G_CALLBACK(from_name_activate_cb), optmenu);
for (; accounts != NULL; accounts = accounts->next, num++) {
PrefsAccount *ac = (PrefsAccount *)accounts->data;
if (ac == compose->account) def_menu = num;
- name = g_markup_printf_escaped(_("From: <i>%s</i>"),
+ name = g_markup_printf_escaped(_("<i>%s</i>"),
ac->account_name);
if (ac == compose->account) {
G_CALLBACK(compose_entry_popup_extend),
NULL);
+ fromlabel = gtk_label_new_with_mnemonic(_("_From:"));
+ gtk_label_set_mnemonic_widget(GTK_LABEL(fromlabel), from_name);
+
+ gtk_box_pack_start(GTK_BOX(hbox), fromlabel, FALSE, FALSE, 4);
gtk_box_pack_start(GTK_BOX(hbox), optmenubox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), from_name, TRUE, TRUE, 0);
+
+ /* Putting only the GtkEntry into focus chain of parent hbox causes
+ * the account selector combobox next to it to be unreachable when
+ * navigating widgets in GtkTable with up/down arrow keys.
+ * Note: gtk_widget_set_can_focus() was not enough. */
+ GList *l = NULL;
+ l = g_list_prepend(l, from_name);
+ gtk_container_set_focus_chain(GTK_CONTAINER(hbox), l);
+ g_list_free(l);
CLAWS_SET_TIP(optmenubox,
_("Account to use for this email"));
systemid = g_object_get_data(G_OBJECT(widget), "privacy_system");
g_free(compose->privacy_system);
compose->privacy_system = NULL;
+ g_free(compose->encdata);
+ compose->encdata = NULL;
if (systemid != NULL) {
compose->privacy_system = g_strdup(systemid);
case C_WINDOWS_1256: branch = "Menu/Options/Encoding/Arabic/" CS_WINDOWS_1256; break;
case C_ISO_8859_5: branch = "Menu/Options/Encoding/Cyrillic/" CS_ISO_8859_5; break;
case C_KOI8_R: branch = "Menu/Options/Encoding/Cyrillic/" CS_KOI8_R; break;
+ case C_MACCYR: branch = "Menu/Options/Encoding/Cyrillic/" CS_MACCYR; break;
case C_KOI8_U: branch = "Menu/Options/Encoding/Cyrillic/" CS_KOI8_U; break;
case C_WINDOWS_1251: branch = "Menu/Options/Encoding/Cyrillic/" CS_WINDOWS_1251; break;
case C_ISO_2022_JP: branch = "Menu/Options/Encoding/Japanese/" CS_ISO_2022_JP; break;
}
}
+ if (tmpl->replyto && *tmpl->replyto != '\0') {
+#ifdef USE_ENCHANT
+ quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE,
+ compose->gtkaspell);
+#else
+ quote_fmt_init(msginfo, NULL, NULL, FALSE, compose->account, FALSE);
+#endif
+ quote_fmt_scan_string(tmpl->replyto);
+ quote_fmt_parse();
+
+ buf = quote_fmt_get_buffer();
+ if (buf == NULL) {
+ alertpanel_error(_("Template Reply-To format error."));
+ } else {
+ compose_entry_append(compose, buf, COMPOSE_REPLYTO, PREF_TEMPLATE);
+ }
+ }
+
/* process the subject */
if (tmpl->subject && *tmpl->subject != '\0') {
#ifdef USE_ENCHANT
compose->deferred_destroy = TRUE;
return;
}
+
/* NOTE: address_completion_end() does nothing with the window
* however this may change. */
address_completion_end(compose->window);
- slist_free_strings(compose->to_list);
- g_slist_free(compose->to_list);
- slist_free_strings(compose->newsgroup_list);
- g_slist_free(compose->newsgroup_list);
- slist_free_strings(compose->header_list);
- g_slist_free(compose->header_list);
+ slist_free_strings_full(compose->to_list);
+ slist_free_strings_full(compose->newsgroup_list);
+ slist_free_strings_full(compose->header_list);
+
+ slist_free_strings_full(extra_headers);
+ extra_headers = NULL;
compose->header_list = compose->newsgroup_list = compose->to_list = NULL;
g_hash_table_destroy(compose->email_hashtable);
+ hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST,
+ compose->folder_update_callback_id);
+
procmsg_msginfo_free(compose->targetinfo);
procmsg_msginfo_free(compose->replyinfo);
procmsg_msginfo_free(compose->fwdinfo);
g_free(compose->orig_charset);
g_free(compose->privacy_system);
+ g_free(compose->encdata);
+#ifndef USE_NEW_ADDRBOOK
if (addressbook_get_target_compose() == compose)
addressbook_set_target_compose(NULL);
-
+#endif
#if USE_ENCHANT
if (compose->gtkaspell) {
gtkaspell_delete(compose->gtkaspell);
gtk_widget_destroy(compose->window);
toolbar_destroy(compose->toolbar);
g_free(compose->toolbar);
- g_mutex_free(compose->mutex);
+ cm_mutex_free(compose->mutex);
g_free(compose);
}
gtk_window_set_modal(GTK_WINDOW(attach_prop.window), TRUE);
gtk_widget_grab_focus(attach_prop.ok_btn);
gtk_widget_show(attach_prop.window);
- manage_window_set_transient(GTK_WINDOW(attach_prop.window));
+ gtk_window_set_transient_for(GTK_WINDOW(attach_prop.window),
+ GTK_WINDOW(compose->window));
optmenu = GTK_COMBO_BOX(attach_prop.encoding_optmenu);
if (ainfo->encoding == ENC_UNKNOWN)
gtk_widget_hide(attach_prop.window);
gtk_window_set_modal(GTK_WINDOW(attach_prop.window), FALSE);
- if (cancelled)
+ if (cancelled)
break;
entry_text = gtk_entry_get_text(GTK_ENTRY(attach_prop.mimetype_entry));
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, (0 + 1),
GTK_FILL, 0, 0, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+#if !GTK_CHECK_VERSION(2, 24, 0)
mimetype_entry = gtk_combo_box_entry_new_text();
+#else
+ mimetype_entry = gtk_combo_box_text_new_with_entry();
+#endif
gtk_table_attach(GTK_TABLE(table), mimetype_entry, 1, 2, 0, (0 + 1),
GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
for (mime_type_list = strlist; mime_type_list != NULL;
mime_type_list = mime_type_list->next) {
+#if !GTK_CHECK_VERSION(2, 24, 0)
gtk_combo_box_append_text(GTK_COMBO_BOX(mimetype_entry), mime_type_list->data);
+#else
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(mimetype_entry), mime_type_list->data);
+#endif
g_free(mime_type_list->data);
}
g_list_free(strlist);
if (buf[0] == '0') { /* success */
GtkTextView *text = GTK_TEXT_VIEW(compose->text);
GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
+ GtkTextIter start, end;
+ gchar *chars;
gtk_text_buffer_set_text(buffer, "", -1);
compose_insert_file(compose, compose->exteditor_file);
if (claws_unlink(compose->exteditor_file) < 0)
FILE_OP_ERROR(compose->exteditor_file, "unlink");
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(compose->text));
+ gtk_text_buffer_get_start_iter(buffer, &start);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ chars = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
+ if (chars && strlen(chars) > 0)
+ compose->modified = TRUE;
+ g_free(chars);
} else if (buf[0] == '1') { /* failed */
g_warning("Couldn't exec external editor\n");
if (claws_unlink(compose->exteditor_file) < 0)
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/SendLater", sensitive);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertFile", sensitive);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", sensitive);
+ cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/ReplaceSig", sensitive);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapPara", sensitive);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/WrapAllLines", sensitive);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit/ExtEditor", sensitive);
static void compose_notebook_size_alloc(GtkNotebook *notebook,
GtkAllocation *allocation,
- Compose *compose)
+ GtkPaned *paned)
{
- prefs_common.compose_notebook_height = allocation->height;
+ prefs_common.compose_notebook_height = gtk_paned_get_position(paned);
}
/* compose_edit_size_alloc() - called when resized. don't know whether Gtk
GSList *list, *saved_list = NULL;
HeaderEntryState *state;
GtkRcStyle *style = NULL;
+#if !GTK_CHECK_VERSION(3, 0, 0)
static GdkColor yellow;
static gboolean color_set = FALSE;
+#else
+ static GdkColor yellow = { (guint32)0, (guint32)0xf5, (guint32)0xf6, (guint32)0xbe };
+#endif
/* Get ID of active account in the combo box */
menu = gtk_combo_box_get_model(optmenu);
- gtk_combo_box_get_active_iter(optmenu, &iter);
+ cm_return_if_fail(gtk_combo_box_get_active_iter(optmenu, &iter));
gtk_tree_model_get(menu, &iter, 1, &account_id, -1);
ac = account_find_from_id(account_id);
GTK_EDITABLE(hentry->entry), 0, -1);
state->type = hentry->type;
+#if !GTK_CHECK_VERSION(3, 0, 0)
if (!color_set) {
gdk_color_parse("#f5f6be", &yellow);
color_set = gdk_colormap_alloc_color(
gdk_colormap_get_system(),
&yellow, FALSE, TRUE);
}
+#endif
style = gtk_widget_get_modifier_style(hentry->entry);
state->entry_marked = gdk_color_equal(&yellow,
Compose *compose = (Compose *)data;
GtkTreeSelection *attach_selection;
gint attach_nr_selected;
+ GtkTreePath *path;
if (!event) return FALSE;
if (event->button == 3) {
attach_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
attach_nr_selected = gtk_tree_selection_count_selected_rows(attach_selection);
-
- if (attach_nr_selected > 0)
- {
- cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", TRUE);
- cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", TRUE);
- } else {
- cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", FALSE);
- cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", FALSE);
+
+ /* If no rows, or just one row is selected, right-click should
+ * open menu relevant to the row being right-clicked on. We
+ * achieve that by selecting the clicked row first. If more
+ * than one row is selected, we shouldn't modify the selection,
+ * as user may want to remove selected rows (attachments). */
+ if (attach_nr_selected < 2) {
+ gtk_tree_selection_unselect_all(attach_selection);
+ attach_nr_selected = 0;
+ gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
+ event->x, event->y, &path, NULL, NULL, NULL);
+ if (path != NULL) {
+ gtk_tree_selection_select_path(attach_selection, path);
+ gtk_tree_path_free(path);
+ attach_nr_selected++;
+ }
}
+
+ cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", (attach_nr_selected > 0));
+ /* Properties menu item makes no sense with more than one row
+ * selected, the properties dialog can only edit one attachment. */
+ cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", (attach_nr_selected == 1));
gtk_menu_popup(GTK_MENU(compose->popupmenu), NULL, NULL,
NULL, NULL, event->button, event->time);
if (compose->draft_timeout_tag >= 0) { /* CLAWS: disable draft timeout */
g_source_remove(compose->draft_timeout_tag);
- compose->draft_timeout_tag = -1;
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET;
}
compose_send(compose);
} else if (val == -1) {
alertpanel_error(_("Could not queue message."));
} else if (val == -2) {
- alertpanel_error(_("Could not queue message:\n\n%s."), strerror(errno));
+ alertpanel_error(_("Could not queue message:\n\n%s."), g_strerror(errno));
} else if (val == -3) {
if (privacy_peek_error())
alertpanel_error(_("Could not queue message for sending:\n\n"
debug_print("couldn't lock mutex, probably sending\n");
return FALSE;
}
-
+
lock = TRUE;
tmp = g_strdup_printf("%s%cdraft.%p", get_tmp_dir(),
/* Message-ID of message replying to */
if ((compose->replyinfo != NULL) && (compose->replyinfo->msgid != NULL)) {
- gchar *folderid;
-
- folderid = folder_item_get_identifier(compose->replyinfo->folder);
+ gchar *folderid = NULL;
+
+ if (compose->replyinfo->folder)
+ folderid = folder_item_get_identifier(compose->replyinfo->folder);
+ if (folderid == NULL)
+ folderid = g_strdup("NULL");
+
err |= (fprintf(fp, "RMID:%s\t%d\t%s\n", folderid, compose->replyinfo->msgnum, compose->replyinfo->msgid) < 0);
g_free(folderid);
}
/* Message-ID of message forwarding to */
if ((compose->fwdinfo != NULL) && (compose->fwdinfo->msgid != NULL)) {
- gchar *folderid;
-
- folderid = folder_item_get_identifier(compose->fwdinfo->folder);
+ gchar *folderid = NULL;
+
+ if (compose->fwdinfo->folder)
+ folderid = folder_item_get_identifier(compose->fwdinfo->folder);
+ if (folderid == NULL)
+ folderid = g_strdup("NULL");
+
err |= (fprintf(fp, "FMID:%s\t%d\t%s\n", folderid, compose->fwdinfo->msgnum, compose->fwdinfo->msgid) < 0);
g_free(folderid);
}
goto warn_err;
}
+ flag.perm_flags = MSG_NEW|MSG_UNREAD;
if (compose->targetinfo) {
target_locked = MSG_IS_LOCKED(compose->targetinfo->flags);
- flag.perm_flags = target_locked?MSG_LOCKED:0;
+ if (target_locked)
+ flag.perm_flags |= MSG_LOCKED;
}
flag.tmp_flags = MSG_DRAFT;
if (newmsginfo) {
procmsg_msginfo_unset_flags(newmsginfo, ~0, ~0);
if (target_locked)
- procmsg_msginfo_set_flags(newmsginfo, MSG_LOCKED, MSG_DRAFT);
+ procmsg_msginfo_set_flags(newmsginfo, MSG_NEW|MSG_UNREAD|MSG_LOCKED, MSG_DRAFT);
else
- procmsg_msginfo_set_flags(newmsginfo, 0, MSG_DRAFT);
+ procmsg_msginfo_set_flags(newmsginfo, MSG_NEW|MSG_UNREAD, MSG_DRAFT);
if (compose_use_attach(compose) && action != COMPOSE_AUTO_SAVE)
procmsg_msginfo_set_flags(newmsginfo, 0,
MSG_HAS_ATTACHMENT);
compose_close(compose);
return TRUE;
} else {
- struct stat s;
+ GStatBuf s;
gchar *path;
path = folder_item_fetch_msg(draft, msgnum);
if (compose->redirect_filename != NULL)
return;
+ /* Set focus_window properly, in case we were called via popup menu,
+ * which unsets it (via focus_out_event callback on compose window). */
+ manage_window_focus_in(compose->window, NULL, NULL);
+
file_list = filesel_select_multiple_files_open(_("Select file"));
if (file_list) {
compose_insert_sig(compose, FALSE);
}
+static void compose_replace_sig_cb(GtkAction *action, gpointer data)
+{
+ Compose *compose = (Compose *)data;
+
+ compose_insert_sig(compose, TRUE);
+}
+
static gint compose_delete_cb(GtkWidget *widget, GdkEventAny *event,
gpointer data)
{
compose_close_cb(NULL, compose);
}
+static gboolean compose_can_autosave(Compose *compose)
+{
+ if (compose->privacy_system && compose->use_encryption)
+ return prefs_common.autosave && prefs_common.autosave_encrypted;
+ else
+ return prefs_common.autosave;
+}
+
static void compose_close_cb(GtkAction *action, gpointer data)
{
Compose *compose = (Compose *)data;
g_mutex_unlock(compose->mutex);
switch (val) {
case G_ALERTDEFAULT:
- if (prefs_common.autosave && !reedit)
- compose_remove_draft(compose);
+ if (compose_can_autosave(compose) && !reedit)
+ compose_remove_draft(compose);
break;
case G_ALERTALTERNATE:
compose_draft(data, COMPOSE_QUIT_EDITING);
{
Compose *compose = (Compose *)data;
+#ifndef USE_NEW_ADDRBOOK
addressbook_open(compose);
+#else
+ GError* error = NULL;
+ addressbook_connect_signals(compose);
+ addressbook_dbus_open(TRUE, &error);
+ if (error) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+ }
+#endif
}
static void about_show_cb(GtkAction *action, gpointer data)
tmpl = g_object_get_data(G_OBJECT(widget), "template");
cm_return_if_fail(tmpl != NULL);
- msg = g_strdup_printf(_("Do you want to apply the template '%s' ?"),
+ msg = g_strdup_printf(_("Do you want to apply the template '%s'?"),
tmpl->name);
val = alertpanel(_("Apply template"), msg,
_("_Replace"), _("_Insert"), GTK_STOCK_CANCEL);
GtkTextBuffer *buffer;
BLOCK_WRAP();
if (compose->focused_editable &&
- gtk_widget_has_focus(compose->focused_editable))
+#ifndef GENERIC_UMPC
+ gtk_widget_has_focus(compose->focused_editable)
+#endif
+ )
entry_paste_clipboard(compose, compose->focused_editable,
prefs_common.linewrap_pastes,
GDK_SELECTION_CLIPBOARD, NULL);
UNBLOCK_WRAP();
#ifdef USE_ENCHANT
- if (gtk_widget_has_focus(compose->text) &&
+ if (
+#ifndef GENERIC_UMPC
+ gtk_widget_has_focus(compose->text) &&
+#endif
compose->gtkaspell &&
compose->gtkaspell->check_while_typing)
gtkaspell_highlight_all(compose->gtkaspell);
UNBLOCK_WRAP();
#ifdef USE_ENCHANT
- if (gtk_widget_has_focus(compose->text) &&
+ if (
+#ifndef GENERIC_UMPC
+ gtk_widget_has_focus(compose->text) &&
+#endif
compose->gtkaspell &&
compose->gtkaspell->check_while_typing)
gtkaspell_highlight_all(compose->gtkaspell);
UNBLOCK_WRAP();
#ifdef USE_ENCHANT
- if (gtk_widget_has_focus(compose->text) &&
+ if (
+#ifndef GENERIC_UMPC
+ gtk_widget_has_focus(compose->text) &&
+#endif
compose->gtkaspell &&
compose->gtkaspell->check_while_typing)
gtkaspell_highlight_all(compose->gtkaspell);
GtkTextBuffer *buffer;
GtkTextMark *mark;
GtkTextIter ins;
- gint count;
cm_return_if_fail(GTK_IS_TEXT_VIEW(text));
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &ins, mark);
- count = gtk_text_iter_inside_word (&ins) ? 2 : 1;
if (gtk_text_iter_backward_word_starts(&ins, 1))
gtk_text_buffer_place_cursor(buffer, &ins);
}
static void activate_privacy_system(Compose *compose, PrefsAccount *account, gboolean warn)
{
g_free(compose->privacy_system);
+ g_free(compose->encdata);
compose->privacy_system = g_strdup(account->default_privacy_system);
compose_update_privacy_system_menu_item(compose, warn);
return TRUE;
}
+static gboolean completion_set_focus_to_subject
+ (GtkWidget *widget,
+ GdkEventKey *event,
+ Compose *compose)
+{
+ cm_return_val_if_fail(compose != NULL, FALSE);
+
+ /* make backtab move to subject field */
+ if(event->keyval == GDK_KEY_ISO_Left_Tab) {
+ gtk_widget_grab_focus(compose->subject_entry);
+ return TRUE;
+ }
+ return FALSE;
+}
+
static void compose_insert_drag_received_cb (GtkWidget *widget,
GdkDragContext *drag_context,
gint x,
g_list_free(list);
gtk_drag_finish(drag_context, TRUE, FALSE, time);
return;
- } else {
- return;
}
- gtk_drag_finish(drag_context, TRUE, FALSE, time);
}
static void compose_header_drag_received_cb (GtkWidget *widget,
{
Compose *compose = (Compose *)data;
- cm_return_val_if_fail(!compose->batch, FALSE);
+ if (compose->batch)
+ return FALSE;
GTK_EVENTS_FLUSH();
compose_show_first_last_header(compose, FALSE);
static gboolean compose_defer_auto_save_draft(Compose *compose)
{
- compose->draft_timeout_tag = -1;
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_UNSET;
compose_draft((gpointer)compose, COMPOSE_AUTO_SAVE);
return FALSE;
}
GtkAdjustment *vadj;
cm_return_if_fail(compose);
- cm_return_if_fail(!compose->batch);
+
+ if(compose->batch)
+ return;
+
cm_return_if_fail(GTK_IS_WIDGET(compose->header_table));
cm_return_if_fail(GTK_IS_VIEWPORT(gtk_widget_get_parent(compose->header_table)));
vadj = gtk_viewport_get_vadjustment(GTK_VIEWPORT(
compose);
g_signal_stop_emission_by_name(G_OBJECT(buffer), "insert-text");
- if (prefs_common.autosave &&
+ if (compose_can_autosave(compose) &&
gtk_text_buffer_get_char_count(buffer) % prefs_common.autosave_length == 0 &&
- compose->draft_timeout_tag != -2 /* disabled while loading */)
+ compose->draft_timeout_tag != COMPOSE_DRAFT_TIMEOUT_FORBIDDEN /* disabled while loading */)
compose->draft_timeout_tag = g_timeout_add
(500, (GSourceFunc) compose_defer_auto_save_draft, compose);
}
{
gint x, y;
+ cm_return_val_if_fail(compose, FALSE);
+
if (!g_mutex_trylock(compose->mutex)) {
/* we have to wait for the (possibly deferred by auto-save)
* drafting to be done, before destroying the compose under
* it. */
debug_print("waiting for drafting to finish...\n");
compose_allow_user_actions(compose, FALSE);
- g_timeout_add (500, (GSourceFunc) compose_close, compose);
- return FALSE;
+ if (compose->close_timeout_tag == 0) {
+ compose->close_timeout_tag =
+ g_timeout_add (500, (GSourceFunc) compose_close,
+ compose);
+ }
+ return TRUE;
}
- cm_return_val_if_fail(compose, FALSE);
+
+ if (compose->draft_timeout_tag >= 0) {
+ g_source_remove(compose->draft_timeout_tag);
+ compose->draft_timeout_tag = COMPOSE_DRAFT_TIMEOUT_FORBIDDEN;
+ }
+
gtkut_widget_get_uposition(compose->window, &x, &y);
if (!compose->batch) {
prefs_common.compose_x = x;
}
#endif
+static void compose_subject_entry_activated(GtkWidget *widget, gpointer data)
+{
+ Compose *compose = (Compose *)data;
+
+ cm_return_if_fail(compose != NULL);
+
+ gtk_widget_grab_focus(compose->text);
+}
+
+static void from_name_activate_cb(GtkWidget *widget, gpointer data)
+{
+ gtk_combo_box_popup(GTK_COMBO_BOX(data));
+}
+
+
/*
* End of Source.
*/