#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
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,
#endif
static gboolean compose_send_control_enter (Compose *compose);
+static gint compose_defer_auto_save_draft (Compose *compose);
static GtkItemFactoryEntry compose_popup_entries[] =
{
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);
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;
}
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)
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);
{
GtkSText *text = GTK_STEXT(compose->text);
gint cur_pos;
+ gint len;
g_return_if_fail(compose->account != NULL);
gtk_stext_freeze(text);
+ if (replace) {
+ len = gtk_stext_get_length(text);
+ gtk_stext_set_point(text, len);
+ }
+
if (replace && compose->sig_str) {
gint pos;
- gint len;
if (compose->sig_str[0] == '\0')
pos = -1;
if (len >= 0) {
gtk_stext_set_point(text, pos);
gtk_stext_forward_delete(text, len);
- } else {
- len = gtk_stext_get_length(text);
- gtk_stext_set_point(text, len);
}
- } else {
- len = gtk_stext_get_length(text);
- gtk_stext_set_point(text, len);
}
- } else
- gtk_stext_insert(text, NULL, NULL, NULL, "\n\n", 2);
+ }
g_free(compose->sig_str);
compose->sig_str = compose_get_signature_str(compose);
g_free(tmp);
}
- if (compose->account->sig_sep) {
- sig_str = g_strconcat(compose->account->sig_sep, "\n", sig_body,
+ if (compose->account->sig_sep)
+ sig_str = g_strconcat("\n\n", compose->account->sig_sep, "\n", sig_body,
NULL);
- g_free(sig_body);
- } else
- sig_str = sig_body;
+ else
+ sig_str = g_strconcat("\n\n", sig_body, NULL);
+ g_free(sig_body);
+
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,
}
#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))))
+ ((info->type == MIMETYPE_TEXT) || \
+ (info->type == MIMETYPE_MULTIPART && info->subtype && \
+ !strcasecmp(info->subtype, "alternative") && \
+ (info->node->children && \
+ (((MimeInfo *) info->node->children->data)->type == MIMETYPE_TEXT))))
static void compose_attach_parts(Compose *compose, MsgInfo *msginfo)
{
if (!mimeinfo) return;
/* skip first text (presumably message body) */
- child = mimeinfo->children;
+ child = (MimeInfo *) mimeinfo->node->children->data;
if (!child || IS_FIRST_PART_TEXT(mimeinfo)) {
procmime_mimeinfo_free_all(mimeinfo);
return;
}
if (IS_FIRST_PART_TEXT(child))
- child = child->next;
+ child = (MimeInfo *) child->node->next;
infile = procmsg_get_message_file_path(msginfo);
while (child != NULL) {
- if (child->children || child->mime_type == MIME_MULTIPART) {
+ if (child->node->children || child->type == MIMETYPE_MULTIPART) {
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) {
+ if (child->node->parent && child->node->parent->parent
+ && (((MimeInfo *) child->node->parent->parent->data)->type == MIMETYPE_MULTIPART)
+ && !strcasecmp(((MimeInfo *) child->node->parent->parent->data)->subtype, "signed")
+ && child->type == MIMETYPE_TEXT) {
/* this is the main text part of a signed message */
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"))
+ else if (compose->mode != COMPOSE_REEDIT ||
+ !((child->type == MIMETYPE_APPLICATION) && !strcmp(child->subtype, "pgp-signature"))) {
+ gchar *content_type;
+
+ content_type = g_strdup_printf("%s/%s", procmime_get_type_str(child->type), child->subtype);
compose_attach_append
(compose, outfile,
child->filename ? child->filename : child->name,
- child->content_type);
+ content_type);
+ g_free(content_type);
+ }
- child = child->next;
+ child = child->node->next != NULL ? (MimeInfo *) child->node->next->data : NULL;
}
g_free(infile);
g_free(msgpath);
folder_item_remove_msg(folder, msgnum);
+
+ folder_item_scan(folder);
return val;
}
g_warning("can't change file mode\n");
}
- while (procheader_get_unfolded_line(buf, sizeof(buf), fp)) {
+ while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
/* should filter returnpath, delivered-to */
if (g_strncasecmp(buf, "Return-Path:",
strlen("Return-Path:")) == 0 ||
return -1;
}
folder_item_scan(queue);
- if ((num = folder_item_add_msg(queue, tmp, TRUE)) < 0) {
+ if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
g_warning("can't queue the message\n");
unlink(tmp);
g_free(tmp);
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);
}
}
/* 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));
}
/* 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));
/* 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);
"/Spelling/Spelling Configuration");
gtkaspell_populate_submenu(gtkaspell, menuitem);
menu_set_sensitive(ifactory, "/Spelling", TRUE);
- }
+ }
}
}
#endif
FolderItem *draft;
gchar *tmp;
gint msgnum;
+ MsgFlags flag = {0, 0};
static gboolean lock = FALSE;
MsgInfo *newmsginfo;
return;
}
- if ((msgnum = folder_item_add_msg(draft, tmp, TRUE)) < 0) {
+ folder_item_scan(draft);
+ if ((msgnum = folder_item_add_msg(draft, tmp, &flag, TRUE)) < 0) {
unlink(tmp);
g_free(tmp);
lock = FALSE;
procmsg_msginfo_free(newmsginfo);
}
+ folder_item_scan(draft);
+
lock = FALSE;
/* 0: quit editing 1: keep editing 2: keep editing (autosave) */
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 = 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);
compose);
gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
-
if (prefs_common.autosave &&
gtk_stext_get_length(GTK_STEXT(widget)) % prefs_common.autosave_length == 0)
- compose_draft_cb((gpointer)compose, 2, NULL);
+ gtk_timeout_add(500, (GtkFunction) compose_defer_auto_save_draft, compose);
+}
+
+static gint compose_defer_auto_save_draft(Compose *compose)
+{
+ compose_draft_cb((gpointer)compose, 2, NULL);
+ return FALSE;
}
static gboolean compose_send_control_enter(Compose *compose)