*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
# include <wctype.h>
#endif
+#include "sylpheed.h"
#include "main.h"
#include "mainwindow.h"
#include "compose.h"
static gint compose_defer_auto_save_draft (Compose *compose);
static PrefsAccount *compose_guess_forward_account_from_msginfo (MsgInfo *msginfo);
-static void compose_close (Compose *compose);
+static gboolean compose_close (Compose *compose);
static GtkItemFactoryEntry compose_popup_entries[] =
{
if (prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
+ compose_set_title(compose);
return compose;
}
to_sender, TRUE, body);
}
+static void compose_extract_original_charset(Compose *compose)
+{
+ MsgInfo *info = NULL;
+ if (compose->replyinfo) {
+ info = compose->replyinfo;
+ } else if (compose->fwdinfo) {
+ info = compose->fwdinfo;
+ } else if (compose->targetinfo) {
+ info = compose->targetinfo;
+ }
+ if (info) {
+ MimeInfo *mimeinfo = procmime_scan_message(info);
+ MimeInfo *partinfo = mimeinfo;
+ while (partinfo && partinfo->type != MIMETYPE_TEXT)
+ partinfo = procmime_mimeinfo_next(partinfo);
+ if (partinfo) {
+ compose->orig_charset =
+ g_strdup(procmime_mimeinfo_get_parameter(
+ partinfo, "charset"));
+ }
+ procmime_mimeinfo_free_all(mimeinfo);
+ }
+}
+
static void compose_generic_reply(MsgInfo *msginfo, gboolean quote,
gboolean to_all, gboolean to_ml,
gboolean to_sender,
if (!compose->replyinfo)
compose->replyinfo = procmsg_msginfo_copy(msginfo);
+ compose_extract_original_charset(compose);
+
if (msginfo->folder && msginfo->folder->ret_rcpt)
menu_set_active(ifactory, "/Options/Request Return Receipt", TRUE);
if (prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
+
+ compose_set_title(compose);
}
#define INSERT_FW_HEADER(var, hdr) \
if (!compose->fwdinfo)
compose->fwdinfo = procmsg_msginfo_copy(msginfo);
+ compose_extract_original_charset(compose);
+
if (msginfo->subject && *msginfo->subject) {
gchar *buf, *buf2, *p;
g_free(folderidentifier);
}
+ compose_set_title(compose);
return compose;
}
gtk_widget_grab_focus(compose->header_last->entry);
+ compose_set_title(compose);
return compose;
}
}
compose->targetinfo = procmsg_msginfo_copy(msginfo);
+ compose_extract_original_charset(compose);
+
if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
gchar queueheader_buf[BUFFSIZE];
if (prefs_common.auto_exteditor)
compose_exec_ext_editor(compose);
+ compose_set_title(compose);
}
Compose *compose_redirect(PrefsAccount *account, MsgInfo *msginfo)
gtk_widget_set_sensitive(compose->toolbar->linewrap_current_btn, FALSE);
gtk_widget_set_sensitive(compose->toolbar->linewrap_all_btn, FALSE);
+ compose_set_title(compose);
return compose;
}
{
gchar *str;
gchar *edited;
-
+ gchar *subject;
+
edited = compose->modified ? _(" [Edited]") : "";
- if (compose->account && compose->account->address)
+
+ subject = gtk_editable_get_chars(
+ GTK_EDITABLE(compose->subject_entry), 0, -1);
+
+ if (subject && strlen(subject))
+ str = g_strdup_printf(_("%s - Compose message%s"),
+ subject, edited);
+ else if (compose->account && compose->account->address)
str = g_strdup_printf(_("%s - Compose message%s"),
compose->account->address, edited);
else
str = g_strdup_printf(_("Compose message%s"), edited);
gtk_window_set_title(GTK_WINDOW(compose->window), str);
g_free(str);
+ g_free(subject);
}
/**
val = compose_queue(compose, &msgnum, &folder);
if (val) {
- if (val == -3) {
+ if (val == -4) {
+ alertpanel_error(_("Could not queue message for sending:\n\n"
+ "Charset conversion failed."));
+ } else if (val == -3) {
alertpanel_error(_("Could not queue message for sending:\n\n"
"Signature failed."));
} else if (val == -2) {
out_codeset = CS_US_ASCII;
encoding = ENC_7BIT;
} else {
- const gchar *src_codeset;
+ const gchar *src_codeset = CS_INTERNAL;
out_codeset = conv_get_charset_str(compose->out_encoding);
- if (!out_codeset)
+
+ if (!out_codeset) {
+ gchar *test_conv_global_out = NULL;
+ gchar *test_conv_reply = NULL;
+
+ /* automatic mode. be automatic. */
+ codeconv_set_strict(TRUE);
+
out_codeset = conv_get_outgoing_charset_str();
+ if (out_codeset) {
+ debug_print("trying to convert to %s\n", out_codeset);
+ test_conv_global_out = conv_codeset_strdup(chars, src_codeset, out_codeset);
+ }
+
+ if (!test_conv_global_out && compose->orig_charset) {
+ out_codeset = compose->orig_charset;
+ debug_print("failure; trying to convert to %s\n", out_codeset);
+ test_conv_reply = conv_codeset_strdup(chars, src_codeset, out_codeset);
+ }
+
+ if (!test_conv_global_out && !test_conv_reply) {
+ /* we're lost */
+ out_codeset = CS_INTERNAL;
+ debug_print("finally using %s\n", out_codeset);
+ }
+ g_free(test_conv_global_out);
+ g_free(test_conv_reply);
+ codeconv_set_strict(FALSE);
+ }
if (!g_ascii_strcasecmp(out_codeset, CS_US_ASCII))
out_codeset = CS_ISO_8859_1;
else
encoding = procmime_get_encoding_for_charset(out_codeset);
- src_codeset = CS_INTERNAL;
- /* if current encoding is US-ASCII, set it the same as
- outgoing one to prevent code conversion failure */
- if (!g_ascii_strcasecmp(src_codeset, CS_US_ASCII))
- src_codeset = out_codeset;
-
debug_print("src encoding = %s, out encoding = %s, transfer encoding = %s\n",
src_codeset, out_codeset, procmime_get_encoding_str(encoding));
if (action == COMPOSE_WRITE_FOR_SEND) {
+ codeconv_set_strict(TRUE);
buf = conv_codeset_strdup(chars, src_codeset, out_codeset);
-
+ codeconv_set_strict(FALSE);
+
if (!buf) {
AlertValue aval;
gchar *msg;
- msg = g_strdup_printf(_("Can't convert the character encoding of the message from\n"
- "%s to %s.\n"
- "Send it anyway?"), src_codeset, out_codeset);
+ msg = g_strdup_printf(_("Can't convert the character encoding of the message \n"
+ "to the specified %s charset.\n"
+ "Send it as %s?"), out_codeset, src_codeset);
aval = alertpanel_full(_("Error"), msg, GTK_STOCK_YES, GTK_STOCK_NO, NULL, FALSE,
NULL, ALERT_ERROR, G_ALERTALTERNATE);
- g_free(msg);
+ g_free(msg);
if (aval != G_ALERTDEFAULT) {
g_free(chars);
- return -1;
+ return -3;
} else {
buf = chars;
out_codeset = src_codeset;
fclose(fp);
g_unlink(tmp);
g_free(tmp);
- return result - 1; /* -2 for a generic error, -3 for signing error */
+ return result - 1; /* -2 for a generic error, -3 for signing error, -4 for encoding */
}
}
gint header_len, gboolean addr_field)
{
gchar *tmpstr = NULL;
-
+ const gchar *out_codeset = NULL;
+
g_return_if_fail(src != NULL);
g_return_if_fail(dest != NULL);
g_free(tmpstr);
tmpstr = mybuf;
}
+
+ codeconv_set_strict(TRUE);
conv_encode_header_full(dest, len, tmpstr, header_len, addr_field,
conv_get_charset_str(compose->out_encoding));
+ codeconv_set_strict(FALSE);
+
+ if (!dest || *dest == '\0') {
+ gchar *test_conv_global_out = NULL;
+ gchar *test_conv_reply = NULL;
+
+ /* automatic mode. be automatic. */
+ codeconv_set_strict(TRUE);
+
+ out_codeset = conv_get_outgoing_charset_str();
+ if (out_codeset) {
+ debug_print("trying to convert to %s\n", out_codeset);
+ test_conv_global_out = conv_codeset_strdup(src, CS_INTERNAL, out_codeset);
+ }
+
+ if (!test_conv_global_out && compose->orig_charset) {
+ out_codeset = compose->orig_charset;
+ debug_print("failure; trying to convert to %s\n", out_codeset);
+ test_conv_reply = conv_codeset_strdup(src, CS_INTERNAL, out_codeset);
+ }
+
+ if (!test_conv_global_out && !test_conv_reply) {
+ /* we're lost */
+ out_codeset = CS_INTERNAL;
+ debug_print("finally using %s\n", out_codeset);
+ }
+ g_free(test_conv_global_out);
+ g_free(test_conv_reply);
+ conv_encode_header_full(dest, len, tmpstr, header_len, addr_field,
+ out_codeset);
+ codeconv_set_strict(FALSE);
+ }
g_free(tmpstr);
}
titles[COL_NAME] = _("Name");
compose->account = account;
-
+
+ compose->mutex = g_mutex_new();
+
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
gtk_widget_set_size_request(window, -1, prefs_common.compose_height);
g_free(compose->exteditor_file);
+ g_free(compose->orig_charset);
if (addressbook_get_target_compose() == compose)
addressbook_set_target_compose(NULL);
gtk_widget_destroy(compose->window);
toolbar_destroy(compose->toolbar);
g_free(compose->toolbar);
+ g_mutex_free(compose->mutex);
g_free(compose);
}
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
COL_MIMETYPE, ainfo->content_type,
COL_SIZE, text,
- COL_NAME, ainfo->file,
+ COL_NAME, ainfo->name,
-1);
break;
draft = account_get_special_folder(compose->account, F_DRAFT);
g_return_if_fail(draft != NULL);
-
+
+ if (!g_mutex_trylock(compose->mutex)) {
+ /* we don't want to lock the mutex once it's available,
+ * because as the only other part of compose.c locking
+ * it is compose_close - which means once unlocked,
+ * the compose struct will be freed */
+ debug_print("couldn't lock mutex, probably sending\n");
+ return;
+ }
+
lock = TRUE;
tmp = g_strdup_printf("%s%cdraft.%p", get_tmp_dir(),
G_DIR_SEPARATOR, compose);
if ((fp = g_fopen(tmp, "wb")) == NULL) {
FILE_OP_ERROR(tmp, "fopen");
- return;
+ goto unlock;
}
/* chmod for security */
fclose(fp);
g_unlink(tmp);
g_free(tmp);
- lock = FALSE;
- return;
+ goto unlock;
}
fclose(fp);
if ((msgnum = folder_item_add_msg(draft, tmp, &flag, TRUE)) < 0) {
g_unlink(tmp);
g_free(tmp);
- lock = FALSE;
if (action != COMPOSE_AUTO_SAVE)
alertpanel_error(_("Could not save draft."));
- return;
+ goto unlock;
}
g_free(tmp);
draft->mtime = 0; /* force updating */
folder_item_scan(draft);
- lock = FALSE;
-
- if (action == COMPOSE_QUIT_EDITING)
+ if (action == COMPOSE_QUIT_EDITING) {
+ lock = FALSE;
+ g_mutex_unlock(compose->mutex); /* must be done before closing */
compose_close(compose);
- else {
+ return;
+ } else {
struct stat s;
gchar *path;
if (g_stat(path, &s) < 0) {
FILE_OP_ERROR(path, "stat");
g_free(path);
- lock = FALSE;
- return;
+ goto unlock;
}
g_free(path);
compose->modified = FALSE;
compose_set_title(compose);
}
+unlock:
+ lock = FALSE;
+ g_mutex_unlock(compose->mutex);
}
static void compose_attach_cb(gpointer data, guint action, GtkWidget *widget)
if (compose->modified) {
val = alertpanel(_("Discard message"),
- _("This message has been modified. discard it?"),
- _("Discard"), _("to Draft"), GTK_STOCK_CANCEL);
+ _("This message has been modified. Discard it?"),
+ _("Discard"), _("Save to Drafts"), GTK_STOCK_CANCEL);
switch (val) {
case G_ALERTDEFAULT:
static void compose_changed_cb(GtkTextBuffer *textbuf, Compose *compose)
{
- if (compose->modified == FALSE) {
- compose->modified = TRUE;
- compose_set_title(compose);
- }
+ compose->modified = TRUE;
+ compose_set_title(compose);
}
static void compose_wrap_cb(gpointer data, guint action, GtkWidget *widget)
{
Compose *compose = (Compose *)user_data;
GList *list, *tmp;
-
- if (gdk_atom_name(data->type) && !strcmp(gdk_atom_name(data->type), "text/uri-list")) {
+
+ if (gdk_atom_name(data->type) &&
+ !strcmp(gdk_atom_name(data->type), "text/uri-list")) {
list = uri_list_extract_filenames((const gchar *)data->data);
for (tmp = list; tmp != NULL; tmp = tmp->next)
compose_attach_append
if (list) compose_changed_cb(NULL, compose);
list_free_strings(list);
g_list_free(list);
+ } else if (gdk_atom_name(data->type) &&
+ !strcmp(gdk_atom_name(data->type), "text/plain") &&
+ data->data && !strcmp(data->data, "Dummy-Summaryview")) {
+ /* comes from our summaryview */
+ SummaryView * summaryview = NULL;
+ GSList * list = NULL, *cur = NULL;
+
+ if (mainwindow_get_mainwindow())
+ summaryview = mainwindow_get_mainwindow()->summaryview;
+
+ if (summaryview)
+ list = summary_get_selected_msg_list(summaryview);
+
+ for (cur = list; cur; cur = cur->next) {
+ MsgInfo *msginfo = (MsgInfo *)cur->data;
+ gchar *file = NULL;
+ if (msginfo)
+ file = procmsg_get_message_file_full(msginfo,
+ TRUE, TRUE);
+ if (file) {
+ compose_attach_append(compose, (const gchar *)file,
+ (const gchar *)file, "message/rfc822");
+ g_free(file);
+ }
+ }
+ g_slist_free(list);
}
}
return account;
}
-static void compose_close(Compose *compose)
+static gboolean compose_close(Compose *compose)
{
gint x, y;
- g_return_if_fail(compose);
+ 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");
+ g_timeout_add (500, (GSourceFunc) compose_close, compose);
+ return FALSE;
+ }
+ g_return_val_if_fail(compose, FALSE);
gtkut_widget_get_uposition(compose->window, &x, &y);
prefs_common.compose_x = x;
prefs_common.compose_y = y;
+ g_mutex_unlock(compose->mutex);
compose_destroy(compose);
+ return FALSE;
}
/**