#define MAX_REFERENCES_LEN 999
+#define COMPOSE_DRAFT_TIMEOUT_UNSET -1
+#define COMPOSE_DRAFT_TIMEOUT_FORBIDEN -2
+
static GList *compose_list = NULL;
static GSList *extra_headers = NULL;
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);
{"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, "---" }, */
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);
{
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);
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) {
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) {
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)
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) {
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;
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)) {
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);
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))
#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; \
\
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>",
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;
}
}
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;
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,
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;
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)
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 */
#if USE_ENCHANT
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Spelling", FALSE);
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);
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);
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_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;
- 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);
+ if (compose->close_timeout_tag == 0) {
+ compose->close_timeout_tag =
+ g_timeout_add (500, (GSourceFunc) compose_close,
+ compose);
+ }
return FALSE;
}
- cm_return_val_if_fail(compose, FALSE);
+
+ if (compose->close_timeout_tag) {
+ /* let the close be done by the deferred callback */
+ g_mutex_unlock(compose->mutex);
+ return FALSE;
+ }
+
gtkut_widget_get_uposition(compose->window, &x, &y);
if (!compose->batch) {
prefs_common.compose_x = x;