#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
+#include <libgen.h>
#if (HAVE_WCTYPE_H && HAVE_WCHAR_H)
# include <wchar.h>
PRIORITY_LOWEST
} PriorityLevel;
+typedef enum
+{
+ COMPOSE_INSERT_SUCCESS,
+ COMPOSE_INSERT_READ_ERROR,
+ COMPOSE_INSERT_INVALID_CHARACTER,
+ COMPOSE_INSERT_NO_FILE
+} ComposeInsertResult;
+
#define B64_LINE_SIZE 57
#define B64_BUFFSIZE 77
Compose *compose_generic_new (PrefsAccount *account,
const gchar *to,
FolderItem *item,
- GPtrArray *attach_files);
+ GPtrArray *attach_files,
+ GList *listAddress );
static Compose *compose_create (PrefsAccount *account,
ComposeMode mode);
static void compose_insert_sig (Compose *compose,
gboolean replace);
static gchar *compose_get_signature_str (Compose *compose);
-static void compose_insert_file (Compose *compose,
+static ComposeInsertResult compose_insert_file (Compose *compose,
const gchar *file);
static void compose_attach_append (Compose *compose,
const gchar *file,
gchar *src,
gint header_len,
gboolean addr_field);
-static void compose_generate_msgid (Compose *compose,
- gchar *buf,
+static void compose_generate_msgid (gchar *buf,
gint len);
static void compose_attach_info_free (AttachInfo *ainfo);
static void compose_add_header_entry (Compose *compose, gchar *header, gchar *text);
static void compose_update_priority_menu_item(Compose * compose);
+static void compose_add_field_list ( Compose *compose,
+ GList *listAddress );
+
/* callback functions */
static gboolean compose_edit_size_alloc (GtkEditable *widget,
void compose_headerentry_key_press_event_cb(GtkWidget *entry,
GdkEventKey *event,
ComposeHeaderEntry *headerentry);
+static gboolean compose_headerentry_button_pressed (GtkWidget *entry,
+ GdkEventButton *event,
+ gpointer data);
static void compose_show_first_last_header (Compose *compose, gboolean show_first);
{N_("/_Message/---"), NULL, NULL, 0, "<Separator>"},
{N_("/_Message/Si_gn"), NULL, compose_toggle_sign_cb , 0, "<ToggleItem>"},
{N_("/_Message/_Encrypt"), NULL, compose_toggle_encrypt_cb, 0, "<ToggleItem>"},
- {N_("/_Message/Mode/MIME"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_DETACH, "<RadioItem>"},
+ {N_("/_Message/Mode"), NULL, NULL, 0, "<Branch>"},
+ {N_("/_Message/Mode/MIME"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_DETACH, "<RadioItem>"},
{N_("/_Message/Mode/Inline"), NULL, compose_set_gnupg_mode_cb, GNUPG_MODE_INLINE, "/Message/Mode/MIME"},
#endif /* USE_GPGME */
{N_("/_Message/---"), NULL, NULL, 0, "<Separator>"},
Compose *compose_new(PrefsAccount *account, const gchar *mailto,
GPtrArray *attach_files)
{
- return compose_generic_new(account, mailto, NULL, attach_files);
+ return compose_generic_new(account, mailto, NULL, attach_files, NULL);
}
Compose *compose_new_with_folderitem(PrefsAccount *account, FolderItem *item)
{
- return compose_generic_new(account, NULL, item, NULL);
+ return compose_generic_new(account, NULL, item, NULL, NULL);
+}
+
+Compose *compose_new_with_list( PrefsAccount *account, GList *listAddress )
+{
+ return compose_generic_new( account, NULL, NULL, NULL, listAddress );
}
Compose *compose_generic_new(PrefsAccount *account, const gchar *mailto, FolderItem *item,
- GPtrArray *attach_files)
+ GPtrArray *attach_files, GList *listAddress )
{
Compose *compose;
GtkSText *text;
GtkItemFactory *ifactory;
- gboolean grab_focus_on_last = TRUE;
if (item && item->prefs && item->prefs->enable_default_account)
account = account_find_from_id(item->prefs->default_account);
text = GTK_STEXT(compose->text);
gtk_stext_freeze(text);
+#ifdef USE_ASPELL
+ if (item && item->prefs && item->prefs->enable_default_dictionary &&
+ compose->gtkaspell)
+ gtkaspell_change_dict(compose->gtkaspell,
+ item->prefs->default_dictionary);
+#endif
+
if (account->auto_sig)
compose_insert_sig(compose, FALSE);
gtk_editable_set_position(GTK_EDITABLE(text), 0);
} else if (item && item->prefs->enable_default_to) {
compose_entry_append(compose, item->prefs->default_to, COMPOSE_TO);
- compose_entry_select(compose, item->prefs->default_to);
- grab_focus_on_last = FALSE;
+ compose_entry_mark_default_to(compose, item->prefs->default_to);
}
if (item && item->ret_rcpt) {
menu_set_toggle(ifactory, "/Message/Request Return Receipt", TRUE);
*/
menu_set_sensitive(ifactory, "/Message/Request Return Receipt", FALSE);
}
+ compose_add_field_list( compose, listAddress );
if (attach_files) {
gint i;
g_free(folderidentifier);
}
- /* Grab focus on last header only if no default_to was set */
- if (grab_focus_on_last)
- gtk_widget_grab_focus(compose->header_last->entry);
+ gtk_widget_grab_focus(compose->header_last->entry);
if (prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
case COMPOSE_FORWARD_INLINE:
/* check if we reply to more than one Message */
if (list_len == 1) {
- compose_forward(NULL, msginfo, FALSE, body);
+ compose_forward(NULL, msginfo, FALSE, body, FALSE);
break;
}
/* more messages FALL THROUGH */
text = GTK_STEXT(compose->text);
gtk_stext_freeze(text);
+#ifdef USE_ASPELL
+ if (msginfo->folder && msginfo->folder->prefs &&
+ msginfo->folder->prefs &&
+ msginfo->folder->prefs->enable_default_dictionary &&
+ compose->gtkaspell)
+ gtkaspell_change_dict(compose->gtkaspell,
+ msginfo->folder->prefs->default_dictionary);
+#endif
+
if (quote) {
gchar *qmark;
if (account->auto_sig)
compose_insert_sig(compose, FALSE);
- if (quote && prefs_common.linewrap_quote)
- compose_wrap_line_all(compose);
+ /* Must thaw here, otherwise the GtkSTextEdit will become confused
+ * when positioning cursor */
+ gtk_stext_thaw(text);
- gtk_editable_set_position(GTK_EDITABLE(text), 0);
- gtk_stext_set_point(text, 0);
+ gtk_editable_set_position
+ (GTK_EDITABLE(text), quote_fmt_get_cursor_pos());
+ gtk_stext_set_point(text, quote_fmt_get_cursor_pos());
+
+ if (quote && prefs_common.linewrap_quote) {
+ gtk_stext_freeze(text);
+ compose_wrap_line_all(compose);
+ gtk_stext_thaw(text);
+ }
- gtk_stext_thaw(text);
gtk_widget_grab_focus(compose->text);
if (prefs_common.auto_exteditor)
}
Compose *compose_forward(PrefsAccount *account, MsgInfo *msginfo,
- gboolean as_attach, const gchar *body)
+ gboolean as_attach, const gchar *body,
+ gboolean no_extedit)
{
Compose *compose;
GtkSText *text;
if (!account && prefs_common.forward_account_autosel) {
gchar cc[BUFFSIZE];
- if (!get_header_from_msginfo(msginfo,cc,sizeof(cc),"CC:")){ /* Found a CC header */
+ if (!procheader_get_header_from_msginfo(msginfo,cc,sizeof(cc),"CC:")){ /* Found a CC header */
extract_address(cc);
account = account_find_from_address(cc);
}
#endif
gtk_widget_grab_focus(compose->header_last->entry);
- if (prefs_common.auto_exteditor)
+ if (!no_extedit && prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
/*save folder*/
gint id;
/* Select Account from queue headers */
- if (!get_header_from_msginfo(msginfo, queueheader_buf,
+ if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf,
sizeof(queueheader_buf), "X-Sylpheed-Account-Id:")) {
id = atoi(&queueheader_buf[22]);
account = account_find_from_id(id);
}
- if (!account && !get_header_from_msginfo(msginfo, queueheader_buf,
+ if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf,
sizeof(queueheader_buf), "NAID:")) {
id = atoi(&queueheader_buf[5]);
account = account_find_from_id(id);
}
- if (!account && !get_header_from_msginfo(msginfo, queueheader_buf,
+ if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf,
sizeof(queueheader_buf), "MAID:")) {
id = atoi(&queueheader_buf[5]);
account = account_find_from_id(id);
}
- if (!account && !get_header_from_msginfo(msginfo, queueheader_buf,
+ if (!account && !procheader_get_header_from_msginfo(msginfo, queueheader_buf,
sizeof(queueheader_buf), "S:")) {
account = account_find_from_address(queueheader_buf);
}
if (!account && prefs_common.reedit_account_autosel) {
gchar from[BUFFSIZE];
- if (!get_header_from_msginfo(msginfo, from, sizeof(from), "FROM:")){
+ if (!procheader_get_header_from_msginfo(msginfo, from, sizeof(from), "FROM:")){
extract_address(from);
account = account_find_from_address(from);
}
gchar queueheader_buf[BUFFSIZE];
/* Set message save folder */
- if (!get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "SCF:")) {
+ if (!procheader_get_header_from_msginfo(msginfo, queueheader_buf, sizeof(queueheader_buf), "SCF:")) {
gint startpos = 0;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), TRUE);
Compose *compose;
gchar *filename;
GtkItemFactory *ifactory;
+ FolderItem *item;
g_return_val_if_fail(msginfo != NULL, NULL);
compose->redirect_filename = filename;
+ /* Set save folder */
+ item = msginfo->folder;
+ if (item && item->prefs && item->prefs->save_copy_to_folder) {
+ gchar *folderidentifier;
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
+ folderidentifier = folder_item_get_identifier(item);
+ gtk_entry_set_text(GTK_ENTRY(compose->savemsg_entry), folderidentifier);
+ g_free(folderidentifier);
+ }
+
compose_attach_parts(compose, msginfo);
if (msginfo->subject)
gtk_widget_set_sensitive(compose->toolbar->attach_btn, FALSE);
gtk_widget_set_sensitive(compose->toolbar->sig_btn, FALSE);
gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, FALSE);
- gtk_widget_set_sensitive(compose->toolbar->linewrap_btn, FALSE);
+ gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
+ gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
return compose;
}
compose_add_header_entry(compose, header, (gchar *)address);
}
-void compose_entry_select (Compose *compose, const gchar *mailto)
+void compose_entry_mark_default_to(Compose *compose, const gchar *mailto)
{
- GSList *header_list;
+ static GtkStyle *bold_style = NULL;
+ static GdkColor bold_color;
+ static GdkFont *bold_font = NULL;
+ GSList *h_list;
+ GtkEntry *entry;
- for (header_list = compose->header_list; header_list != NULL; header_list = header_list->next) {
- GtkEntry * entry = GTK_ENTRY(((ComposeHeaderEntry *)header_list->data)->entry);
-
- if (gtk_entry_get_text(entry) && !g_strcasecmp(gtk_entry_get_text(entry), mailto)) {
- gtk_entry_select_region(entry, 0, -1);
- gtk_widget_grab_focus(GTK_WIDGET(entry));
+ for (h_list = compose->header_list; h_list != NULL; h_list = h_list->next) {
+ entry = GTK_ENTRY(((ComposeHeaderEntry *)h_list->data)->entry);
+ if (gtk_entry_get_text(entry) &&
+ !g_strcasecmp(gtk_entry_get_text(entry), mailto)) {
+ gtk_widget_ensure_style(GTK_WIDGET(entry));
+ if (!bold_style) {
+ gtkut_convert_int_to_gdk_color
+ (prefs_common.color_new, &bold_color);
+ bold_style = gtk_style_copy(gtk_widget_get_style
+ (GTK_WIDGET(entry)));
+ if (!bold_font)
+ bold_font = gtkut_font_load
+ (prefs_common.boldfont);
+ if (bold_font)
+ bold_style->font = bold_font;
+ bold_style->fg[GTK_STATE_NORMAL] = bold_color;
+ }
+ gtk_widget_set_style(GTK_WIDGET(entry), bold_style);
}
}
}
case A_EXTEDITOR:
compose_ext_editor_cb(compose, 0, NULL);
break;
- case A_LINEWRAP:
+ case A_LINEWRAP_CURRENT:
compose_wrap_line(compose);
break;
+ case A_LINEWRAP_ALL:
+ compose_wrap_line_all(compose);
+ break;
case A_ADDRBOOK:
compose_address_cb(compose, 0, NULL);
break;
+#ifdef USE_ASPELL
+ case A_CHECK_SPELLING:
+ compose_check_all(compose);
+ break;
+#endif
default:
break;
}
}
if (msginfo->subject && *msginfo->subject) {
- gchar *buf, *buf2, *p;
+ gchar *buf, *buf2;
+ guchar *p;
buf = p = g_strdup(msginfo->subject);
p += subject_get_prefix_length(p);
if (replyto && from)
cc_list = address_list_append_with_comments(cc_list, from);
+ if (to_all && msginfo->folder &&
+ msginfo->folder->prefs->enable_default_reply_to)
+ cc_list = address_list_append_with_comments(cc_list,
+ msginfo->folder->prefs->default_reply_to);
cc_list = address_list_append_with_comments(cc_list, msginfo->to);
cc_list = address_list_append_with_comments(cc_list, compose->cc);
gtk_stext_freeze(text);
- len = gtk_stext_get_length(text);
- gtk_stext_set_point(text, len);
+ if (replace) {
+ len = gtk_stext_get_length(text);
+ gtk_stext_set_point(text, len);
+ }
if (replace && compose->sig_str) {
gint pos;
return sig_str;
}
-static void compose_insert_file(Compose *compose, const gchar *file)
+static ComposeInsertResult compose_insert_file(Compose *compose, const gchar *file)
{
GtkSText *text = GTK_STEXT(compose->text);
gchar buf[BUFFSIZE];
gint len;
FILE *fp;
+ gboolean badtxt = FALSE;
- g_return_if_fail(file != NULL);
+ g_return_val_if_fail(file != NULL, COMPOSE_INSERT_NO_FILE);
if ((fp = fopen(file, "rb")) == NULL) {
FILE_OP_ERROR(file, "fopen");
- return;
+ return COMPOSE_INSERT_READ_ERROR;
}
gtk_stext_freeze(text);
while (--len >= 0)
if (buf[len] == '\r') buf[len] = '\n';
}
+ if (mbstowcs(NULL, buf, 0) == -1)
+ badtxt = TRUE;
gtk_stext_insert(text, NULL, NULL, NULL, buf, -1);
}
gtk_stext_thaw(text);
fclose(fp);
+
+ if (badtxt)
+ return COMPOSE_INSERT_INVALID_CHARACTER;
+ else
+ return COMPOSE_INSERT_SUCCESS;
}
static void compose_attach_append(Compose *compose, const gchar *file,
gtk_clist_set_row_data(GTK_CLIST(compose->attach_clist), row, ainfo);
}
-#define IS_FIRST_PART_TEXT(info) \
- ((info->mime_type == MIME_TEXT || info->mime_type == MIME_TEXT_HTML || \
- info->mime_type == MIME_TEXT_ENRICHED) || \
- (info->mime_type == MIME_MULTIPART && info->content_type && \
- !strcasecmp(info->content_type, "multipart/alternative") && \
- (info->children && \
- (info->children->mime_type == MIME_TEXT || \
- info->children->mime_type == MIME_TEXT_HTML || \
- info->children->mime_type == MIME_TEXT_ENRICHED))))
+#ifdef USE_GPGME
+static void compose_use_signing(Compose *compose, gboolean use_signing)
+{
+ GtkItemFactory *ifactory;
+ GtkWidget *menuitem = NULL;
+
+ compose->use_signing = use_signing;
+ ifactory = gtk_item_factory_from_widget(compose->menubar);
+ menuitem = gtk_item_factory_get_item
+ (ifactory, "/Message/Sign");
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
+ use_signing);
+ compose_update_gnupg_mode_menu_item(compose);
+}
+#endif /* USE_GPGME */
+
+#define NEXT_PART_NOT_CHILD(info) \
+{ \
+ node = info->node; \
+ while (node->children) \
+ node = g_node_last_child(node); \
+ info = procmime_mimeinfo_next((MimeInfo *)node->data); \
+}
static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
{
MimeInfo *mimeinfo;
MimeInfo *child;
- gchar *infile;
+ MimeInfo *firsttext = NULL;
+ MimeInfo *encrypted = NULL;
+ GNode *node;
gchar *outfile;
+ const gchar *partname = NULL;
mimeinfo = procmime_scan_message(msginfo);
if (!mimeinfo) return;
- /* skip first text (presumably message body) */
- child = mimeinfo->children;
- if (!child || IS_FIRST_PART_TEXT(mimeinfo)) {
+ if (mimeinfo->node->children == NULL) {
procmime_mimeinfo_free_all(mimeinfo);
return;
}
- if (IS_FIRST_PART_TEXT(child))
- child = child->next;
-
- infile = procmsg_get_message_file_path(msginfo);
+ /* find first content part */
+ child = (MimeInfo *) mimeinfo->node->children->data;
+ while (child && child->node->children && (child->type == MIMETYPE_MULTIPART))
+ child = (MimeInfo *)child->node->children->data;
+ if (child->type == MIMETYPE_TEXT) {
+ firsttext = child;
+ debug_print("First text part found\n");
+ } else if (compose->mode == COMPOSE_REEDIT &&
+ child->type == MIMETYPE_APPLICATION &&
+ !strcasecmp(child->subtype, "pgp-encrypted")) {
+ AlertValue val;
+ val = alertpanel(_("Encrypted message"),
+ _("Cannot re-edit an encrypted message. \n"
+ "Discard encrypted part?"),
+ _("Yes"), _("No"), NULL);
+ if (val == G_ALERTDEFAULT)
+ encrypted = (MimeInfo *)child->node->parent->data;
+ }
+
+ child = (MimeInfo *) mimeinfo->node->children->data;
while (child != NULL) {
- if (child->children || child->mime_type == MIME_MULTIPART) {
+ if (child == encrypted) {
+ /* skip this part of tree */
+ NEXT_PART_NOT_CHILD(child);
+ continue;
+ }
+
+ if (child->type == MIMETYPE_MULTIPART) {
+ /* get the actual content */
+ child = procmime_mimeinfo_next(child);
+ continue;
+ }
+
+ if (child == firsttext) {
child = procmime_mimeinfo_next(child);
continue;
}
- if (child->parent && child->parent->parent
- && !strcasecmp(child->parent->parent->content_type, "multipart/signed")
- && child->mime_type == MIME_TEXT) {
- /* this is the main text part of a signed message */
+
+ if ((compose->mode == COMPOSE_REEDIT ||
+ compose->mode == COMPOSE_FORWARD_INLINE ||
+ compose->mode == COMPOSE_FORWARD ) &&
+ (child->type == MIMETYPE_APPLICATION) &&
+ !strcmp(child->subtype, "pgp-signature")) {
+#ifdef USE_GPGME
+ if (compose->mode == COMPOSE_REEDIT) {
+ compose->gnupg_mode = GNUPG_MODE_DETACH;
+ compose_use_signing(compose, TRUE);
+ }
+#endif
child = procmime_mimeinfo_next(child);
continue;
}
outfile = procmime_get_tmp_file_name(child);
- if (procmime_get_part(outfile, infile, child) < 0)
+ if (procmime_get_part(outfile, child) < 0)
g_warning("Can't get the part of multipart message.");
- else if (compose->mode != COMPOSE_REEDIT || strcmp(child->content_type, "application/pgp-signature"))
- compose_attach_append
- (compose, outfile,
- child->filename ? child->filename : child->name,
- child->content_type);
-
- child = child->next;
+ else {
+ gchar *content_type;
+
+ content_type = procmime_get_content_type_str(child->type, child->subtype);
+ partname = procmime_mimeinfo_get_parameter(child, "name");
+ if (partname == NULL)
+ partname = "";
+ compose_attach_append(compose, outfile,
+ partname, content_type);
+ g_free(content_type);
+ }
+ g_free(outfile);
+ NEXT_PART_NOT_CHILD(child);
}
-
- g_free(infile);
procmime_mimeinfo_free_all(mimeinfo);
}
-#undef IS_FIRST_PART_TEXT
+#undef NEXT_PART_NOT_CHILD
#define GET_CHAR(pos, buf, len) \
{ \
((len > 2 && conv_get_current_charset() == C_UTF_8) ? 2 : \
(len == 2 && conv_get_current_charset() == C_UTF_8) ? 1 : len)
-#define INDENT_CHARS ">|#"
#define SPACE_CHARS " \t"
static void compose_wrap_line(Compose *compose)
if (ch_len == 1
&& strchr(prefs_common.quote_chars, *cbuf))
quoted = 1;
- else if (ch_len != 1 || !isspace(*cbuf))
+ else if (ch_len != 1 || !isspace(*(guchar *)cbuf))
quoted = 0;
line_end = 0;
ch_len = 1;
}
- if (ch_len == 1 && isspace(*cbuf))
+ if (ch_len == 1 && isspace(*(guchar *)cbuf))
space = 1;
if (ch_len == 1 && *cbuf == '\n') {
guint replace = 0;
- if (last_ch_len == 1 && !isspace(last_ch)) {
+ if (last_ch_len == 1 && !isspace((guchar)last_ch)) {
if (cur_pos + 1 < p_end) {
GET_CHAR(cur_pos + 1, cbuf, ch_len);
- if (ch_len == 1 && !isspace(*cbuf))
+ if (ch_len == 1 &&
+ !isspace(*(guchar *)cbuf))
replace = 1;
}
}
gint tlen = ch_len;
GET_CHAR(line_pos - 1, cbuf, ch_len);
- if (ch_len == 1 && isspace(*cbuf)) {
+ if (ch_len == 1 && isspace(*(guchar *)cbuf)) {
gtk_stext_set_point(text, line_pos);
gtk_stext_backward_delete(text, 1);
p_end--;
break;
case WAIT_FOR_INDENT_CHAR_OR_SPACE:
if (is_indent == FALSE && is_space == FALSE &&
- !isupper(cbuf[0]))
+ !isupper((guchar)cbuf[0]))
goto out;
if (is_space == TRUE) {
alnum_cnt = 0;
}
break;
case WAIT_FOR_INDENT_CHAR:
- if (is_indent == FALSE && !isupper(cbuf[0]))
+ if (is_indent == FALSE && !isupper((guchar)cbuf[0]))
goto out;
if (is_indent == TRUE) {
if (alnum_cnt > 0
/* insert space if it's alphanumeric */
if ((cur_pos != line_pos) &&
- ((clen > 1) || isalnum(cb[0]))) {
+ ((clen > 1) || isalnum((guchar)cb[0]))) {
gtk_stext_insert(text, NULL, NULL,
NULL, " ", 1);
tlen++;
}
/* possible line break */
- if (ch_len == 1 && isspace(*cbuf)) {
+ if (ch_len == 1 && isspace(*(guchar *)cbuf)) {
line_pos = cur_pos + 1;
line_len = cur_len + ch_len;
}
GET_CHAR(line_pos - 1, cbuf, clen);
/* if next character is space delete it */
- if (clen == 1 && isspace(*cbuf)) {
+ if (clen == 1 && isspace(*(guchar *)cbuf)) {
if (p_pos + i_len != line_pos ||
!gtk_stext_is_uri_string
(text, line_pos, tlen)) {
{
gchar buf[BUFFSIZE];
gchar *str;
- gboolean first_address;
+ gboolean first_to_address;
+ gboolean first_cc_address;
GSList *list;
ComposeHeaderEntry *headerentry;
gchar *headerentryname;
cc_hdr = prefs_common.trans_hdr ? _("Cc:") : "Cc:";
to_hdr = prefs_common.trans_hdr ? _("To:") : "To:";
- first_address = TRUE;
+ first_to_address = TRUE;
+ first_cc_address = TRUE;
for (list = compose->header_list; list; list = list->next) {
headerentry = ((ComposeHeaderEntry *)list->data);
headerentryname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry));
compose_convert_header
(buf, sizeof(buf), str,
strlen("Resent-To") + 2, TRUE);
- if (first_address) {
- fprintf(fp, "Resent-To: ");
- first_address = FALSE;
- } else {
- fprintf(fp, ",");
+ if (g_strcasecmp(headerentryname, to_hdr) == 0) {
+ if (first_to_address) {
+ fprintf(fp, "Resent-To: ");
+ first_to_address = FALSE;
+ } else {
+ fprintf(fp, ",");
+ }
}
+ if (g_strcasecmp(headerentryname, cc_hdr) == 0) {
+ if (first_cc_address) {
+ fprintf(fp, "\n");
+ fprintf(fp, "Resent-Cc: ");
+ first_cc_address = FALSE;
+ } else {
+ fprintf(fp, ",");
+ }
+ }
+
fprintf(fp, "%s", buf);
}
}
/* Resent-Message-ID */
if (compose->account->gen_msgid) {
- compose_generate_msgid(compose, buf, sizeof(buf));
+ compose_generate_msgid(buf, sizeof(buf));
fprintf(fp, "Resent-Message-Id: <%s>\n", buf);
compose->msgid = g_strdup(buf);
}
g_warning("can't change file mode\n");
}
- while (procheader_get_unfolded_line(buf, sizeof(buf), fp)) {
+ while (procheader_get_one_field_asis(buf, sizeof(buf), fp) != -1) {
/* should filter returnpath, delivered-to */
if (g_strncasecmp(buf, "Return-Path:",
strlen("Return-Path:")) == 0 ||
/* get all composed text */
chars = gtk_editable_get_chars(GTK_EDITABLE(compose->text), 0, -1);
- len = strlen(chars);
if (is_ascii_str(chars)) {
buf = chars;
chars = NULL;
GSList *cur;
gchar buf[BUFFSIZE];
gint num;
- MsgFlags flag = {0, 0};
static gboolean lock = FALSE;
PrefsAccount *mailac = NULL, *newsac = NULL;
static gint compose_write_headers_from_headerlist(Compose *compose,
FILE *fp,
- gchar *header)
+ const gchar *header,
+ const gchar *seperator)
{
- gchar buf[BUFFSIZE];
gchar *str, *header_w_colon, *trans_hdr;
- gboolean first_address;
+ gboolean write_header = FALSE;
GSList *list;
ComposeHeaderEntry *headerentry;
gchar * headerentryname;
+ GString *headerstr;
if (IS_IN_CUSTOM_HEADER(header)) {
return 0;
debug_print("Writing %s-header\n", header);
+ headerstr = g_string_sized_new(64);
+
header_w_colon = g_strconcat(header, ":", NULL);
trans_hdr = (prefs_common.trans_hdr ? gettext(header_w_colon) : header_w_colon);
- first_address = TRUE;
for (list = compose->header_list; list; list = list->next) {
headerentry = ((ComposeHeaderEntry *)list->data);
headerentryname = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry));
Xstrdup_a(str, str, return -1);
g_strstrip(str);
if (str[0] != '\0') {
- compose_convert_header
- (buf, sizeof(buf), str,
- strlen(header) + 2, TRUE);
- if (first_address) {
- fprintf(fp, "%s: ", header);
- first_address = FALSE;
- } else {
- fprintf(fp, ",");
- }
- fprintf(fp, "%s", buf);
+ if (write_header)
+ g_string_append(headerstr, seperator);
+ g_string_append(headerstr, str);
+ write_header = TRUE;
}
}
}
- if (!first_address) {
- fprintf(fp, "\n");
+ if (write_header) {
+ gchar *buf;
+
+ buf = g_new0(gchar, headerstr->len * 4 + 256);
+ compose_convert_header
+ (buf, headerstr->len * 4 + 256, headerstr->str,
+ strlen(header) + 2, TRUE);
+ fprintf(fp, "%s: %s\n", header, buf);
+ g_free(buf);
}
g_free(header_w_colon);
+ g_string_free(headerstr, TRUE);
return(0);
}
}
/* From */
- if (!IS_IN_CUSTOM_HEADER("From")) {
- if (compose->account->name && *compose->account->name) {
- compose_convert_header
- (buf, sizeof(buf), compose->account->name,
- strlen("From: "), TRUE);
- QUOTE_IF_REQUIRED(name, buf);
- fprintf(fp, "From: %s <%s>\n",
- name, compose->account->address);
- } else
- fprintf(fp, "From: %s\n", compose->account->address);
- }
+ if (compose->account->name && *compose->account->name) {
+ compose_convert_header
+ (buf, sizeof(buf), compose->account->name,
+ strlen("From: "), TRUE);
+ QUOTE_IF_REQUIRED(name, buf);
+ fprintf(fp, "From: %s <%s>\n",
+ name, compose->account->address);
+ } else
+ fprintf(fp, "From: %s\n", compose->account->address);
/* To */
- compose_write_headers_from_headerlist(compose, fp, "To");
+ compose_write_headers_from_headerlist(compose, fp, "To", ", ");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_to) {
str = gtk_entry_get_text(GTK_ENTRY(compose->to_entry));
#endif
/* Newsgroups */
- compose_write_headers_from_headerlist(compose, fp, "Newsgroups");
+ compose_write_headers_from_headerlist(compose, fp, "Newsgroups", ",");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_newsgroups) {
str = gtk_entry_get_text(GTK_ENTRY(compose->newsgroups_entry));
}
#endif
/* Cc */
- compose_write_headers_from_headerlist(compose, fp, "Cc");
+ compose_write_headers_from_headerlist(compose, fp, "Cc", ", ");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_cc) {
str = gtk_entry_get_text(GTK_ENTRY(compose->cc_entry));
}
#endif
/* Bcc */
- compose_write_headers_from_headerlist(compose, fp, "Bcc");
+ compose_write_headers_from_headerlist(compose, fp, "Bcc", ", ");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_bcc) {
str = gtk_entry_get_text(GTK_ENTRY(compose->bcc_entry));
/* Message-ID */
if (compose->account->gen_msgid) {
- compose_generate_msgid(compose, buf, sizeof(buf));
+ compose_generate_msgid(buf, sizeof(buf));
fprintf(fp, "Message-Id: <%s>\n", buf);
compose->msgid = g_strdup(buf);
}
}
/* Followup-To */
- compose_write_headers_from_headerlist(compose, fp, "Followup-To");
+ compose_write_headers_from_headerlist(compose, fp, "Followup-To", ",");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_followupto && !IS_IN_CUSTOM_HEADER("Followup-To")) {
str = gtk_entry_get_text(GTK_ENTRY(compose->followup_entry));
}
#endif
/* Reply-To */
- compose_write_headers_from_headerlist(compose, fp, "Reply-To");
+ compose_write_headers_from_headerlist(compose, fp, "Reply-To", ", ");
#if 0 /* NEW COMPOSE GUI */
if (compose->use_replyto && !IS_IN_CUSTOM_HEADER("Reply-To")) {
str = gtk_entry_get_text(GTK_ENTRY(compose->reply_entry));
cur = cur->next) {
CustomHeader *chdr = (CustomHeader *)cur->data;
- if (strcasecmp(chdr->name, "Date") != 0 &&
- strcasecmp(chdr->name, "From") != 0 &&
- strcasecmp(chdr->name, "To") != 0 &&
- /* strcasecmp(chdr->name, "Sender") != 0 && */
- strcasecmp(chdr->name, "Message-Id") != 0 &&
- strcasecmp(chdr->name, "In-Reply-To") != 0 &&
- strcasecmp(chdr->name, "References") != 0 &&
- strcasecmp(chdr->name, "Mime-Version") != 0 &&
- strcasecmp(chdr->name, "Content-Type") != 0 &&
- strcasecmp(chdr->name, "Content-Transfer-Encoding")
- != 0) {
+ if (custom_header_is_allowed(chdr->name)) {
compose_convert_header
(buf, sizeof(buf),
chdr->value ? chdr->value : "",
/* MIME */
fprintf(fp, "Mime-Version: 1.0\n");
if (compose_use_attach(compose)) {
- get_rfc822_date(buf, sizeof(buf));
- subst_char(buf, ' ', '_');
- subst_char(buf, ',', '_');
- compose->boundary = g_strdup_printf("Multipart_%s_%08x",
- buf, (guint)compose);
+ compose->boundary = generate_mime_boundary(NULL);
fprintf(fp,
"Content-Type: multipart/mixed;\n"
" boundary=\"%s\"\n", compose->boundary);
} else {
fprintf(fp, "Content-Type: text/plain; charset=%s\n", charset);
+#if USE_GPGME
+ if (compose->use_signing && !compose->gnupg_mode)
+ fprintf(fp, "Content-Disposition: inline\n");
+#endif
fprintf(fp, "Content-Transfer-Encoding: %s\n",
procmime_get_encoding_str(encoding));
}
headerentry = ((ComposeHeaderEntry *)list->data);
tmp = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(headerentry->combo)->entry)));
+ if (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);
g_free(tmp);
headervalue = gtk_entry_get_text(GTK_ENTRY(headerentry->entry));
+ subst_char(headervalue, '\r', ' ');
+ subst_char(headervalue, '\n', ' ');
string = std_headers;
while (*string != NULL) {
headername_trans = prefs_common.trans_hdr ? gettext(*string) : *string;
fprintf(fp, "%s %s\n", headername_wcolon, headervalue);
g_free(headername);
- g_free(headername_wcolon);
-
+ g_free(headername_wcolon);
}
/* separator between header and body */
if (len < 1) return;
+ subst_char(src, '\n', ' ');
+ subst_char(src, '\r', ' ');
g_strchomp(src);
conv_encode_header(dest, len, src, header_len, addr_field);
}
-static void compose_generate_msgid(Compose *compose, gchar *buf, gint len)
+static void compose_generate_msgid(gchar *buf, gint len)
{
struct tm *lt;
time_t t;
t = time(NULL);
lt = localtime(&t);
- if (compose->account && compose->account->address &&
- *compose->account->address) {
- if (strchr(compose->account->address, '@'))
- addr = g_strdup(compose->account->address);
- else
- addr = g_strconcat(compose->account->address, "@",
- get_domain_name(), NULL);
- } else
- addr = g_strconcat(g_get_user_name(), "@", get_domain_name(),
- NULL);
+ addr = g_strconcat("@", get_domain_name(), NULL);
- g_snprintf(buf, len, "%04d%02d%02d%02d%02d%02d.%08x.%s",
+ g_snprintf(buf, len, "%04d%02d%02d%02d%02d%02d.%08x%s",
lt->tm_year + 1900, lt->tm_mon + 1,
lt->tm_mday, lt->tm_hour,
lt->tm_min, lt->tm_sec,
gtk_signal_connect(GTK_OBJECT(entry), "key-press-event", GTK_SIGNAL_FUNC(compose_headerentry_key_press_event_cb), headerentry);
gtk_signal_connect(GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(compose_headerentry_changed_cb), headerentry);
gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(text_activated), compose);
+ gtk_signal_connect(GTK_OBJECT(entry), "button-press-event",
+ GTK_SIGNAL_FUNC(compose_headerentry_button_pressed),
+ NULL);
address_completion_register_entry(GTK_ENTRY(entry));
}
gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL,
&geometry, GDK_HINT_MAX_SIZE);
-
+ gtk_widget_set_uposition(window, prefs_common.compose_x,
+ prefs_common.compose_y);
gtk_signal_connect(GTK_OBJECT(window), "delete_event",
GTK_SIGNAL_FUNC(compose_delete_cb), compose);
gtk_signal_connect(GTK_OBJECT(window), "destroy",
}
#endif
- action_update_compose_menu(ifactory, compose);
-
-
undostruct = undo_init(text);
undo_set_change_state_func(undostruct, &compose_undo_state_changed,
menubar);
compose->exteditor_pid = -1;
compose->exteditor_readdes = -1;
compose->exteditor_tag = -1;
+ compose->draft_timeout_tag = -1;
#if USE_ASPELL
menu_set_sensitive(ifactory, "/Spelling", FALSE);
}
}
}
+ compose->gtkaspell = gtkaspell;
#endif
compose_select_account(compose, account, TRUE);
-#if USE_ASPELL
- compose->gtkaspell = gtkaspell;
-#endif
-
if (account->set_autocc && account->auto_cc && mode != COMPOSE_REEDIT)
compose_entry_append(compose, account->auto_cc, COMPOSE_CC);
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(compose->header_last->combo)->entry), prefs_common.trans_hdr ? _("Newsgroups:") : "Newsgroups:");
addressbook_set_target_compose(compose);
- action_update_compose_menu(ifactory, compose);
if (mode != COMPOSE_REDIRECT)
compose_set_template_menu(compose);
/* Priority */
compose->priority = PRIORITY_NORMAL;
compose_update_priority_menu_item(compose);
-
+
+ /* Actions menu */
+ compose_update_actions_menu(compose);
+
#if USE_GPGME
activate_gnupg_mode(compose, account);
#endif
gtk_menu_item_set_submenu(GTK_MENU_ITEM(compose->tmpl_menu), menu);
}
+void compose_update_actions_menu(Compose *compose)
+{
+ GtkItemFactory *ifactory;
+
+ ifactory = gtk_item_factory_from_widget(compose->menubar);
+ action_update_compose_menu(ifactory, "/Tools/Actions", compose);
+}
+
void compose_reflect_prefs_all(void)
{
GList *cur;
gtk_widget_set_sensitive(compose->toolbar->insert_btn, sensitive);
gtk_widget_set_sensitive(compose->toolbar->sig_btn, sensitive);
gtk_widget_set_sensitive(compose->toolbar->exteditor_btn, sensitive);
- gtk_widget_set_sensitive(compose->toolbar->linewrap_btn, sensitive);
+ gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, sensitive);
+ gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, sensitive);
}
/**
g_return_if_fail(widget != NULL);
- debug_print("Set_undo. UNDO:%i REDO:%i\n", undo_state, redo_state);
-
ifactory = gtk_item_factory_from_widget(widget);
switch (undo_state) {
case UNDO_STATE_TRUE:
if (!undostruct->undo_state) {
- debug_print ("Set_undo - Testpoint\n");
undostruct->undo_state = TRUE;
menu_set_sensitive(ifactory, "/Edit/Undo", TRUE);
}
Compose *compose = (Compose *)data;
PrefsAccount *ac;
+ gchar *folderidentifier;
ac = account_find_from_id(
GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem))));
if (ac != compose->account)
compose_select_account(compose, ac, FALSE);
+
+ /* Set message save folder */
+ if (account_get_special_folder(compose->account, F_OUTBOX)) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compose->savemsg_checkbtn), prefs_common.savemsg);
+ }
+ gtk_signal_connect(GTK_OBJECT(compose->savemsg_checkbtn), "toggled",
+ GTK_SIGNAL_FUNC(compose_savemsg_checkbtn_cb), compose);
+
+ gtk_editable_delete_text(GTK_EDITABLE(compose->savemsg_entry), 0, -1);
+ if (account_get_special_folder(compose->account, F_OUTBOX)) {
+ folderidentifier = folder_item_get_identifier(account_get_special_folder
+ (compose->account, F_OUTBOX));
+ gtk_entry_set_text(GTK_ENTRY(compose->savemsg_entry), folderidentifier);
+ g_free(folderidentifier);
+ }
}
static void attach_selected(GtkCList *clist, gint row, gint column,
_("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
return;
+ if (compose->draft_timeout_tag != -1) { /* CLAWS: disable draft timeout */
+ gtk_timeout_remove(compose->draft_timeout_tag);
+ compose->draft_timeout_tag = -1;
+ }
+
compose_allow_user_actions (compose, FALSE);
compose->sending = TRUE;
val = compose_send(compose);
for ( tmp = file_list; tmp; tmp = tmp->next) {
gchar *file = (gchar *) tmp->data;
- compose_insert_file(compose, file);
+ gchar *filedup = g_strdup(file);
+ gchar *shortfile;
+ ComposeInsertResult res;
+
+ res = compose_insert_file(compose, file);
+ shortfile = g_basename(filedup);
+ if (res == COMPOSE_INSERT_READ_ERROR) {
+ alertpanel_error(_("File '%s' could not be read."), shortfile);
+ } else if (res == COMPOSE_INSERT_INVALID_CHARACTER) {
+ alertpanel_error(_("File '%s' contained invalid characters\n"
+ "for the current encoding, insertion may be incorrect."), shortfile);
+ }
+ g_free(filedup);
g_free(file);
}
g_list_free(file_list);
static gint compose_delete_cb(GtkWidget *widget, GdkEventAny *event,
gpointer data)
{
+ gint x, y;
Compose *compose = (Compose *)data;
+
+ gtkut_widget_get_uposition(widget, &x, &y);
+ prefs_common.compose_x = x;
+ prefs_common.compose_y = y;
+
if (compose->sending)
return TRUE;
compose_close_cb(compose, 0, NULL);
{
Compose *compose = (Compose *)data;
AlertValue val;
-
+
if (compose->exteditor_tag != -1) {
if (!compose_ext_editor_kill(compose))
return;
}
}
+static gboolean compose_headerentry_button_pressed
+ (GtkWidget *entry, GdkEventButton *event, gpointer data)
+{
+ /* if this is a lclick, grab the focus */
+ if (event->button == 1)
+ gtk_widget_grab_focus(entry);
+ return FALSE;
+}
+
static void compose_show_first_last_header(Compose *compose, gboolean show_first)
{
GtkAdjustment *vadj;
if (prefs_common.autosave &&
gtk_stext_get_length(GTK_STEXT(widget)) % prefs_common.autosave_length == 0)
- gtk_timeout_add(500, (GtkFunction) compose_defer_auto_save_draft, compose);
+ compose->draft_timeout_tag = gtk_timeout_add
+ (500, (GtkFunction) compose_defer_auto_save_draft, compose);
}
static gint compose_defer_auto_save_draft(Compose *compose)
{
+ compose->draft_timeout_tag = -1;
compose_draft_cb((gpointer)compose, 2, NULL);
return FALSE;
}
if (!(kev->keyval == GDK_Return && (kev->state & GDK_CONTROL_MASK)))
return FALSE;
+ if (compose->exteditor_tag != -1)
+ return FALSE;
+
ifactory = gtk_item_factory_from_widget(compose->menubar);
send_menu = gtk_item_factory_get_widget(ifactory, "/Message/Send");
list = gtk_accel_group_entries_from_object(GTK_OBJECT(send_menu));
}
#endif
+/**
+ * Add entry field for each address in list.
+ * \param compose E-Mail composition object.
+ * \param listAddress List of (formatted) E-Mail addresses.
+ */
+static void compose_add_field_list( Compose *compose, GList *listAddress ) {
+ GList *node;
+ gchar *addr;
+ node = listAddress;
+ while( node ) {
+ addr = ( gchar * ) node->data;
+ compose_entry_append( compose, addr, COMPOSE_TO );
+ node = g_list_next( node );
+ }
+}
+
+/*
+ * End of Source.
+ */
+