/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2011 Hiroyuki Yamamoto and the Claws Mail team
+ * Copyright (C) 1999-2012 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
#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 "codeconv.h"
#include "utils.h"
#include "gtkutils.h"
+#include "gtkshruler.h"
#include "socket.h"
#include "alertpanel.h"
#include "manage_window.h"
-#if !GTK_CHECK_VERSION(2, 24, 0)
-#include "gtkshruler.h"
-#endif
#include "folder.h"
+#include "folder_item_prefs.h"
#include "addr_compl.h"
#include "quote_fmt.h"
#include "undo.h"
#define MAX_REFERENCES_LEN 999
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,
ComposeEntryType to_type);
static gint compose_parse_header (Compose *compose,
MsgInfo *msginfo);
+static gint compose_parse_manual_headers (Compose *compose,
+ MsgInfo *msginfo,
+ HeaderEntry *entries);
static gchar *compose_parse_references (const gchar *ref,
const gchar *msgid);
static int compose_add_attachments (Compose *compose,
MimeInfo *parent);
static gchar *compose_get_header (Compose *compose);
+static gchar *compose_get_manual_headers_info (Compose *compose);
static void compose_convert_header (Compose *compose,
gchar *dest,
/* callback functions */
-#if !GTK_CHECK_VERSION(2, 24, 0)
+static void compose_notebook_size_alloc (GtkNotebook *notebook,
+ GtkAllocation *allocation,
+ Compose *compose);
static gboolean compose_edit_size_alloc (GtkEditable *widget,
GtkAllocation *allocation,
GtkSHRuler *shruler);
-#endif
static void account_activated (GtkComboBox *optmenu,
gpointer data);
static void attach_selected (GtkTreeView *tree_view,
static void compose_close_cb (GtkAction *action,
gpointer data);
+static void compose_print_cb (GtkAction *action,
+ gpointer data);
static void compose_set_encoding_cb (GtkAction *action, GtkRadioAction *current, gpointer data);
static void compose_toggle_autoindent_cb(GtkToggleAction *action,
gpointer data);
-#if !GTK_CHECK_VERSION(2, 24, 0)
static void compose_toggle_ruler_cb (GtkToggleAction *action,
gpointer data);
-#endif
static void compose_toggle_sign_cb (GtkToggleAction *action,
gpointer data);
static void compose_toggle_encrypt_cb (GtkToggleAction *action,
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,
/* {"Message/---", NULL, "---" }, */
{"Message/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(compose_save_cb) }, /*COMPOSE_KEEP_EDITING*/
/* {"Message/---", NULL, "---" }, */
+ {"Message/Print", NULL, N_("_Print"), NULL, NULL, G_CALLBACK(compose_print_cb) },
+ /* {"Message/---", NULL, "---" }, */
{"Message/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(compose_close_cb) },
/* Edit menu */
{"Edit/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(compose_copy_cb) },
{"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", 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/SelectAll", NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(compose_allsel_cb) },
{"Options/Encrypt", NULL, N_("_Encrypt"), NULL, NULL, G_CALLBACK(compose_toggle_encrypt_cb) }, /* Toggle */
{"Options/RequestRetRcpt", NULL, N_("_Request Return Receipt"), NULL, NULL, G_CALLBACK(compose_toggle_return_receipt_cb) }, /* TOGGLE */
{"Options/RemoveReferences", NULL, N_("Remo_ve references"), NULL, NULL, G_CALLBACK(compose_toggle_remove_refs_cb) }, /* TOGGLE */
-#if !GTK_CHECK_VERSION(2, 24, 0)
{"Tools/ShowRuler", NULL, N_("Show _ruler"), NULL, NULL, G_CALLBACK(compose_toggle_ruler_cb) }, /* Toggle */
-#endif
};
static GtkRadioActionEntry compose_radio_rm_entries[] =
#if !GTK_CHECK_VERSION(2, 24, 0)
GdkColormap *cmap;
gboolean success[8];
-#endif
- GdkColor color[8];
int i;
+ 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);
}
}
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;
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->name,
+ ainfo->content_type, ainfo->charset);
}
}
undo_block(compose->undostruct);
#ifdef USE_ENCHANT
- compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
+ compose_set_dictionaries_from_folder_prefs(compose, msginfo->folder);
+ gtkaspell_block_check(compose->gtkaspell);
#endif
if (quote_mode == COMPOSE_QUOTE_FORCED ||
_("The body of the \"Reply\" template has an error at line %d."));
compose_attach_from_list(compose, quote_fmt_get_attachments_list(), FALSE);
quote_fmt_reset_vartable();
-#ifdef USE_ENCHANT
- if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
- gtkaspell_highlight_all(compose->gtkaspell);
-#endif
}
if (MSG_IS_ENCRYPTED(compose->replyinfo->flags)) {
compose_wrap_all(compose);
+#ifdef USE_ENCHANT
+ if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
+ gtkaspell_highlight_all(compose->gtkaspell);
+ gtkaspell_unblock_check(compose->gtkaspell);
+#endif
SIGNAL_UNBLOCK(textbuf);
gtk_widget_grab_focus(compose->text);
pref_get_unescaped_pref(tmp, msginfo->folder->prefs->forward_override_from_format);
#ifdef USE_ENCHANT
+ gtkaspell_block_check(compose->gtkaspell);
quote_fmt_init(full_msginfo, NULL, NULL, FALSE, compose->account, FALSE,
compose->gtkaspell);
#else
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_attach_parts(compose, msginfo);
procmsg_msginfo_free(full_msginfo);
-#ifdef USE_ENCHANT
- if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
- gtkaspell_highlight_all(compose->gtkaspell);
-#endif
}
SIGNAL_BLOCK(textbuf);
compose_wrap_all(compose);
+#ifdef USE_ENCHANT
+ if (compose->gtkaspell && compose->gtkaspell->check_while_typing)
+ gtkaspell_highlight_all(compose->gtkaspell);
+ gtkaspell_unblock_check(compose->gtkaspell);
+#endif
SIGNAL_UNBLOCK(textbuf);
cursor_pos = quote_fmt_get_cursor_pos();
MsgInfo *replyinfo = NULL, *fwdinfo = NULL;
gboolean autowrap = prefs_common.autowrap;
gboolean autoindent = prefs_common.auto_indent;
+ HeaderEntry *manual_headers = NULL;
cm_return_val_if_fail(msginfo != NULL, NULL);
cm_return_val_if_fail(msginfo->folder != NULL, NULL);
}
g_strfreev(tokens);
}
+ /* Get manual headers */
+ if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "X-Claws-Manual-Headers:")) {
+ gchar *listmh = g_strdup(&queueheader_buf[strlen("X-Claws-Manual-Headers:")]);
+ if (*listmh != '\0') {
+ debug_print("Got manual headers: %s\n", listmh);
+ manual_headers = procheader_entries_from_str(listmh);
+ }
+ g_free(listmh);
+ }
} else {
account = msginfo->folder->folder->account;
}
}
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);
G_CALLBACK(compose_changed_cb),
compose);
+ if (manual_headers != NULL) {
+ if (compose_parse_manual_headers(compose, msginfo, manual_headers) < 0) {
+ procheader_entries_free(manual_headers);
+ compose->updating = FALSE;
+ compose_destroy(compose);
+ return NULL;
+ }
+ procheader_entries_free(manual_headers);
+ }
+
gtk_widget_grab_focus(compose->text);
if (prefs_common.auto_exteditor) {
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Message/InsertSig", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Edit", FALSE);
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Options", FALSE);
-#if !GTK_CHECK_VERSION(2, 24, 0)
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/ShowRuler", FALSE);
-#endif
cm_menu_set_sensitive_full(compose->ui_manager, "Menu/Tools/Actions", FALSE);
if (compose->toolbar->draft_btn)
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);
static void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
{
-#if !GTK_CHECK_VERSION(2, 24, 0)
+#if !GTK_CHECK_VERSION(3, 0, 0)
static GdkColor yellow;
static GdkColor black;
static gboolean yellow_initialised = FALSE;
GSList *h_list;
GtkEntry *entry;
-#if !GTK_CHECK_VERSION(2, 24, 0)
+#if !GTK_CHECK_VERSION(3, 0, 0)
if (!yellow_initialised) {
gdk_color_parse("#f5f6be", &yellow);
gdk_color_parse("#000000", &black);
entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry);
if (gtk_entry_get_text(entry) &&
!g_utf8_collate(gtk_entry_get_text(entry), mailto)) {
-#if !GTK_CHECK_VERSION(2, 24, 0)
+#if !GTK_CHECK_VERSION(3, 0, 0)
if (yellow_initialised) {
#endif
gtk_widget_modify_base(
gtk_widget_modify_text(
GTK_WIDGET(((ComposeHeaderEntry *)h_list->data)->entry),
GTK_STATE_NORMAL, &black);
-#if !GTK_CHECK_VERSION(2, 24, 0)
+#if !GTK_CHECK_VERSION(3, 0, 0)
}
#endif
}
return 0;
}
+static gint compose_parse_manual_headers(Compose *compose, MsgInfo *msginfo, HeaderEntry *entries)
+{
+ FILE *fp;
+ HeaderEntry *he;
+
+ cm_return_val_if_fail(msginfo != NULL, -1);
+
+ if ((fp = procmsg_open_message(msginfo)) == NULL) return -1;
+ procheader_get_header_fields(fp, entries);
+ fclose(fp);
+
+ he = entries;
+ while (he != NULL && he->name != NULL) {
+ GtkTreeIter iter;
+ GtkListStore *model = NULL;
+
+ debug_print("Adding manual header: %s with value %s\n", he->name, he->body);
+ model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(compose->header_last->combo)));
+ COMBOBOX_ADD(model, he->name, COMPOSE_TO);
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(compose->header_last->combo), &iter);
+ gtk_entry_set_text(GTK_ENTRY(compose->header_last->entry), he->body);
+ ++he;
+ }
+
+ return 0;
+}
+
static gchar *compose_parse_references(const gchar *ref, const gchar *msgid)
{
GSList *ref_id_list, *cur;
*par_iter = iter;
undo_wrapping(compose->undostruct, FALSE);
compose->autowrap = prev_autowrap;
-
+
return modified;
}
}
if (msgpath == NULL) {
msgpath = folder_item_fetch_msg(folder, msgnum);
- val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
+ val = procmsg_send_message_queue_with_lock(msgpath, &errstr, folder, msgnum, &queued_removed);
g_free(msgpath);
} else {
- val = procmsg_send_message_queue(msgpath, &errstr, folder, msgnum, &queued_removed);
+ val = procmsg_send_message_queue_with_lock(msgpath, &errstr, folder, msgnum, &queued_removed);
claws_unlink(msgpath);
g_free(msgpath);
}
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;
}
if ((fp = g_fopen(tmp, "wb")) == NULL) {
FILE_OP_ERROR(tmp, "fopen");
g_free(tmp);
- lock = FALSE;
return -2;
}
if (compose->use_encryption) {
gchar *encdata;
if (!compose_warn_encryption(compose)) {
- lock = FALSE;
fclose(fp);
claws_unlink(tmp);
g_free(tmp);
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);
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;
}
!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;
}
+static gchar *compose_get_manual_headers_info(Compose *compose)
+{
+ GString *sh_header = g_string_new(" ");
+ GSList *list;
+ gchar *std_headers[] = {"To:", "Cc:", "Bcc:", "Newsgroups:", "Reply-To:", "Followup-To:", NULL};
+
+ for (list = compose->header_list; list; list = list->next) {
+ ComposeHeaderEntry *headerentry;
+ gchar *tmp;
+ gchar *headername;
+ gchar *headername_wcolon;
+ const gchar *headername_trans;
+ gchar **string;
+ gboolean standard_header = FALSE;
+
+ headerentry = ((ComposeHeaderEntry *)list->data);
+
+ tmp = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((headerentry->combo))))));
+ g_strstrip(tmp);
+ if (*tmp == '\0' || strchr(tmp, ' ') != NULL || strchr(tmp, '\r') != NULL || strchr(tmp, '\n') != NULL) {
+ g_free(tmp);
+ continue;
+ }
+
+ if (!strstr(tmp, ":")) {
+ headername_wcolon = g_strconcat(tmp, ":", NULL);
+ headername = g_strdup(tmp);
+ } else {
+ headername_wcolon = g_strdup(tmp);
+ headername = g_strdup(strtok(tmp, ":"));
+ }
+ g_free(tmp);
+
+ string = std_headers;
+ while (*string != NULL) {
+ headername_trans = prefs_common_translated_header_name(*string);
+ if (!strcmp(headername_trans, headername_wcolon))
+ standard_header = TRUE;
+ string++;
+ }
+ if (!standard_header && !IS_IN_CUSTOM_HEADER(headername))
+ g_string_append_printf(sh_header, "%s ", headername);
+ g_free(headername);
+ g_free(headername_wcolon);
+ }
+ g_string_truncate(sh_header, strlen(sh_header->str) - 1); /* remove last space */
+ return g_string_free(sh_header, FALSE);
+}
+
static gchar *compose_get_header(Compose *compose)
{
gchar buf[BUFFSIZE];
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 \n */
+ buf[lastc] = (buf[lastc] == '\n')? '\0': buf[lastc];
+ --lastc;
+ 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};
COMPOSE_REPLYTO);
COMBOBOX_ADD(model, prefs_common_translated_header_name("Followup-To:"),
COMPOSE_FOLLOWUPTO);
+ compose_add_extra_header_entries(model);
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);
+
+ 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);
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);
gtk_container_set_border_width(GTK_CONTAINER(header_table), BORDER_WIDTH);
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;
- /* 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(compose_savemsg_select_cb),
compose);
- rowcount++;
-
return table;
}
GtkWidget *paned;
GtkWidget *edit_vbox;
-#if !GTK_CHECK_VERSION(2, 24, 0)
GtkWidget *ruler_hbox;
GtkWidget *ruler;
-#endif
GtkWidget *scrolledwin;
GtkWidget *text;
GtkTextBuffer *buffer;
GtkClipboard *clipboard;
- CLAWS_TIP_DECL();
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;
window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "compose");
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
- gtk_widget_set_size_request(window, -1, prefs_common.compose_height);
+ gtk_widget_set_size_request(window, prefs_common.compose_width,
+ prefs_common.compose_height);
if (!geometry.max_width) {
geometry.max_width = gdk_screen_width();
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/Message", "Print", "Message/Print", GTK_UI_MANAGER_MENUITEM)
+ MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Separator4", "Message/---", GTK_UI_MANAGER_SEPARATOR)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Message", "Close", "Message/Close", GTK_UI_MANAGER_MENUITEM)
/* Edit menu */
/* phew. */
/* Tools menu */
-#if !GTK_CHECK_VERSION(2, 24, 0)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "ShowRuler", "Tools/ShowRuler", GTK_UI_MANAGER_MENUITEM)
-#endif
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "AddressBook", "Tools/AddressBook", GTK_UI_MANAGER_MENUITEM)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools", "Template", "Tools/Template", GTK_UI_MANAGER_MENU)
MENUITEM_ADDUI_MANAGER(compose->ui_manager, "/Menu/Tools/Template", "PlaceHolder", "Tools/Template/PlaceHolder", GTK_UI_MANAGER_MENUITEM)
/* Notebook */
notebook = gtk_notebook_new();
- gtk_widget_set_size_request(notebook, -1, 130);
+ gtk_widget_set_size_request(notebook, -1, prefs_common.compose_notebook_height);
gtk_widget_show(notebook);
/* header labels and entries */
gtk_box_pack_start(GTK_BOX(edit_vbox), subject_hbox, FALSE, FALSE, 0);
-#if !GTK_CHECK_VERSION(2, 24, 0)
/* ruler */
ruler_hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(edit_vbox), ruler_hbox, FALSE, FALSE, 0);
- ruler = gtk_shruler_new();
- gtk_ruler_set_range(GTK_RULER(ruler), 0.0, 100.0, 1.0, 100.0);
+ ruler = gtk_shruler_new(GTK_ORIENTATION_HORIZONTAL);
+ gtk_shruler_set_range(GTK_SHRULER(ruler), 0.0, 100.0, 1.0);
gtk_box_pack_start(GTK_BOX(ruler_hbox), ruler, TRUE, TRUE,
BORDER_WIDTH);
-#endif
/* text widget */
scrolledwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
GTK_SHADOW_IN);
gtk_box_pack_start(GTK_BOX(edit_vbox), scrolledwin, TRUE, TRUE, 0);
- gtk_widget_set_size_request(scrolledwin, prefs_common.compose_width, -1);
text = gtk_text_view_new();
if (prefs_common.show_compose_margin) {
gtk_text_buffer_add_selection_clipboard(buffer, clipboard);
gtk_container_add(GTK_CONTAINER(scrolledwin), text);
-#if !GTK_CHECK_VERSION(2, 24, 0)
+ 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);
-#endif
g_signal_connect(G_OBJECT(buffer), "changed",
G_CALLBACK(compose_changed_cb), compose);
g_signal_connect(G_OBJECT(text), "grab_focus",
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 */
compose->notebook = notebook;
compose->edit_vbox = edit_vbox;
-#if !GTK_CHECK_VERSION(2, 24, 0)
compose->ruler_hbox = ruler_hbox;
compose->ruler = ruler;
-#endif
compose->scrolledwin = scrolledwin;
compose->text = text;
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 {
compose_list = g_list_append(compose_list, compose);
-#if !GTK_CHECK_VERSION(2, 24, 0)
if (!prefs_common.show_ruler)
gtk_widget_hide(ruler_hbox);
cm_toggle_menu_set_active_full(compose->ui_manager, "Menu/Tools/ShowRuler", prefs_common.show_ruler);
-#endif
/* Priority */
compose->priority = PRIORITY_NORMAL;
slist_free_strings(compose->header_list);
g_slist_free(compose->header_list);
+ slist_free_strings(extra_headers);
+ extra_headers = NULL;
+
compose->header_list = compose->newsgroup_list = compose->to_list = NULL;
g_hash_table_destroy(compose->email_hashtable);
g_free(compose->privacy_system);
+#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);
#endif
if (!compose->batch) {
- gtk_widget_get_allocation(compose->scrolledwin, &allocation);
+ gtk_widget_get_allocation(compose->window, &allocation);
prefs_common.compose_width = allocation.width;
prefs_common.compose_height = allocation.height;
}
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)
/* callback functions */
+static void compose_notebook_size_alloc(GtkNotebook *notebook,
+ GtkAllocation *allocation,
+ Compose *compose)
+{
+ prefs_common.compose_notebook_height = allocation->height;
+}
+
/* compose_edit_size_alloc() - called when resized. don't know whether Gtk
* includes "non-client" (windows-izm) in calculation, so this calculation
* may not be accurate.
*/
-#if !GTK_CHECK_VERSION(2, 24, 0)
static gboolean compose_edit_size_alloc(GtkEditable *widget,
GtkAllocation *allocation,
GtkSHRuler *shruler)
(allocation->width - allocation->x) / char_width;
/* got the maximum */
- gtk_ruler_set_range(GTK_RULER(shruler),
- 0.0, line_width_in_chars, 0,
- /*line_width_in_chars*/ char_width);
+ gtk_shruler_set_range(GTK_SHRULER(shruler),
+ 0.0, line_width_in_chars, 0);
}
return TRUE;
}
-#endif
typedef struct {
gchar *header;
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);
- }
+ cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Remove", (attach_nr_selected > 0));
+ cm_menu_set_sensitive_full(compose->ui_manager, "Popup/Compose/Properties", (attach_nr_selected > 0));
gtk_menu_popup(GTK_MENU(compose->popupmenu), NULL, NULL,
NULL, NULL, event->button, event->time);
Compose *compose = (Compose *)data;
FolderItem *draft;
gchar *tmp;
+ gchar *sheaders;
gint msgnum;
MsgFlags flag = {0, 0};
static gboolean lock = FALSE;
err |= (fprintf(fp, "X-Claws-Auto-Wrapping:%d\n", compose->autowrap) < 0);
err |= (fprintf(fp, "X-Claws-Auto-Indent:%d\n", compose->autoindent) < 0);
+ sheaders = compose_get_manual_headers_info(compose);
+ err |= (fprintf(fp, "X-Claws-Manual-Headers:%s\n", sheaders) < 0);
+ g_free(sheaders);
+
/* end of headers */
err |= (fprintf(fp, "X-Claws-End-Special-Headers: 1\n") < 0);
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_close(compose);
}
+static void compose_print_cb(GtkAction *action, gpointer data)
+{
+ Compose *compose = (Compose *) data;
+
+ compose_draft((gpointer)compose, COMPOSE_AUTO_SAVE);
+ if (compose->targetinfo)
+ messageview_print(compose->targetinfo, FALSE, -1, -1, 0);
+}
+
static void compose_set_encoding_cb(GtkAction *action, GtkRadioAction *current, gpointer data)
{
gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current));
{
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)
Compose *compose = (Compose *)data;
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
)
entry_cut_clipboard(compose->focused_editable);
Compose *compose = (Compose *)data;
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
)
entry_copy_clipboard(compose->focused_editable);
GtkTextBuffer *buffer;
BLOCK_WRAP();
if (compose->focused_editable &&
- gtkut_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 (gtkut_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);
gint wrap_quote = prefs_common.linewrap_quote;
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
) {
/* let text_insert() (called directly or at a later time
BLOCK_WRAP();
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
)
entry_paste_clipboard(compose, compose->focused_editable, FALSE,
UNBLOCK_WRAP();
#ifdef USE_ENCHANT
- if (gtkut_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);
BLOCK_WRAP();
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
)
entry_paste_clipboard(compose, compose->focused_editable, TRUE,
UNBLOCK_WRAP();
#ifdef USE_ENCHANT
- if (gtkut_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);
Compose *compose = (Compose *)data;
if (compose->focused_editable
#ifndef GENERIC_UMPC
- && gtkut_widget_has_focus(compose->focused_editable)
+ && gtk_widget_has_focus(compose->focused_editable)
#endif
)
entry_allsel(compose->focused_editable);
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);
}
{textview_delete_to_line_end}
};
- if (!gtkut_widget_has_focus(GTK_WIDGET(text))) return;
+ if (!gtk_widget_has_focus(GTK_WIDGET(text))) return;
if (action >= COMPOSE_CALL_ADVANCED_ACTION_MOVE_BEGINNING_OF_LINE &&
action <= COMPOSE_CALL_ADVANCED_ACTION_DELETE_TO_LINE_END) {
compose_update_privacy_system_menu_item(compose, warn);
}
-#if !GTK_CHECK_VERSION(2, 24, 0)
static void compose_toggle_ruler_cb(GtkToggleAction *action, gpointer data)
{
Compose *compose = (Compose *)data;
prefs_common.show_ruler = FALSE;
}
}
-#endif
static void compose_attach_drag_received_cb (GtkWidget *widget,
GdkDragContext *context,
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,
if (!compose->gtkaspell)
return;
- if (gtkut_widget_has_focus(compose->subject_entry))
+ if (gtk_widget_has_focus(compose->subject_entry))
claws_spell_entry_check_all(
CLAWS_SPELL_ENTRY(compose->subject_entry));
else
return;
}
- if (gtkut_widget_has_focus(compose->subject_entry))
+ if (gtk_widget_has_focus(compose->subject_entry))
claws_spell_entry_check_backwards(
CLAWS_SPELL_ENTRY(compose->subject_entry));
else
return;
}
- if (gtkut_widget_has_focus(compose->subject_entry))
+ if (gtk_widget_has_focus(compose->subject_entry))
claws_spell_entry_check_forwards_go(
CLAWS_SPELL_ENTRY(compose->subject_entry));
else