Statistics
| Revision:

root / src / send_message.c @ 3063

History | View | Annotate | Download (25.1 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2010 Hiroyuki Yamamoto
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <gtk/gtkmain.h>
29
#include <gtk/gtksignal.h>
30
#include <gtk/gtkwindow.h>
31
#include <stdio.h>
32
#include <string.h>
33
#include <sys/types.h>
34
#if HAVE_SYS_WAIT_H
35
#  include <sys/wait.h>
36
#endif
37
38
#include "send_message.h"
39
#include "session.h"
40
#include "ssl.h"
41
#include "smtp.h"
42
#include "news.h"
43
#include "imap.h"
44
#include "prefs_common.h"
45
#include "prefs_account.h"
46
#include "procheader.h"
47
#include "account.h"
48
#include "folder.h"
49
#include "procmsg.h"
50
#include "filter.h"
51
#include "progressdialog.h"
52
#include "statusbar.h"
53
#include "alertpanel.h"
54
#include "manage_window.h"
55
#include "socket.h"
56
#include "socks.h"
57
#include "utils.h"
58
#include "inc.h"
59
#include "mainwindow.h"
60
#include "summaryview.h"
61
62
#define SMTP_PORT        25
63
#if USE_SSL
64
#define SSMTP_PORT        465
65
#endif
66
67
typedef struct _SendProgressDialog        SendProgressDialog;
68
69
struct _SendProgressDialog
70
{
71
        ProgressDialog *dialog;
72
        Session *session;
73
        gboolean show_dialog;
74
        gboolean cancelled;
75
};
76
77
static gint send_message_local                (const gchar                *command,
78
                                         FILE                        *fp);
79
static gint send_message_smtp                (PrefsAccount                *ac_prefs,
80
                                         GSList                        *to_list,
81
                                         FILE                        *fp);
82
83
static gint send_recv_message                (Session                *session,
84
                                         const gchar                *msg,
85
                                         gpointer                 data);
86
static gint send_send_data_progressive        (Session                *session,
87
                                         guint                         cur_len,
88
                                         guint                         total_len,
89
                                         gpointer                 data);
90
static gint send_send_data_finished        (Session                *session,
91
                                         guint                         len,
92
                                         gpointer                 data);
93
94
static SendProgressDialog *send_progress_dialog_create(void);
95
static void send_progress_dialog_destroy(SendProgressDialog *dialog);
96
97
static void send_cancel_button_cb        (GtkWidget        *widget,
98
                                         gpointer         data);
99
100
static void send_put_error                (Session        *session);
101
102
103
gint send_message(const gchar *file, PrefsAccount *ac_prefs, GSList *to_list)
104
{
105
        FILE *fp;
106
        gint val;
107
108
        g_return_val_if_fail(file != NULL, -1);
109
        g_return_val_if_fail(ac_prefs != NULL, -1);
110
        g_return_val_if_fail(to_list != NULL, -1);
111
112
        if ((fp = g_fopen(file, "rb")) == NULL) {
113
                FILE_OP_ERROR(file, "fopen");
114
                return -1;
115
        }
116
117
        if (prefs_common.use_extsend && prefs_common.extsend_cmd) {
118
                val = send_message_local(prefs_common.extsend_cmd, fp);
119
                fclose(fp);
120
                return val;
121
        }
122
123
        val = send_message_smtp(ac_prefs, to_list, fp);
124
125
        fclose(fp);
126
        return val;
127
}
128
129
enum
130
{
131
        Q_SENDER     = 0,
132
        Q_SMTPSERVER = 1,
133
        Q_RECIPIENTS = 2,
134
        Q_ACCOUNT_ID = 3,
135
        Q_REPLY_TARGET = 4,
136
        Q_FORWARD_TARGETS = 5
137
};
138
139
QueueInfo *send_get_queue_info(const gchar *file)
140
{
141
        static HeaderEntry qentry[] = {{"S:",   NULL, FALSE},
142
                                       {"SSV:", NULL, FALSE},
143
                                       {"R:",   NULL, FALSE},
144
                                       {"AID:", NULL, FALSE},
145
                                       {"REP:", NULL, FALSE},
146
                                       {"FWD:", NULL, FALSE},
147
                                       {NULL,   NULL, FALSE}};
148
        FILE *fp;
149
        gchar buf[BUFFSIZE];
150
        gint hnum;
151
        QueueInfo *qinfo;
152
153
        g_return_val_if_fail(file != NULL, NULL);
154
155
        if ((fp = g_fopen(file, "rb")) == NULL) {
156
                FILE_OP_ERROR(file, "fopen");
157
                return NULL;
158
        }
159
160
        qinfo = g_new0(QueueInfo, 1);
161
162
        while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
163
               != -1) {
164
                gchar *p;
165
166
                p = buf + strlen(qentry[hnum].name);
167
168
                switch (hnum) {
169
                case Q_SENDER:
170
                        if (!qinfo->from)
171
                                qinfo->from = g_strdup(p);
172
                        break;
173
                case Q_SMTPSERVER:
174
                        if (!qinfo->server)
175
                                qinfo->server = g_strdup(p);
176
                        break;
177
                case Q_RECIPIENTS:
178
                        qinfo->to_list =
179
                                address_list_append(qinfo->to_list, p);
180
                        break;
181
                case Q_ACCOUNT_ID:
182
                        qinfo->ac = account_find_from_id(atoi(p));
183
                        break;
184
                case Q_REPLY_TARGET:
185
                        qinfo->reply_target = g_strdup(p);
186
                        break;
187
                case Q_FORWARD_TARGETS:
188
                        qinfo->forward_targets = g_strdup(p);
189
                        break;
190
                default:
191
                        break;
192
                }
193
        }
194
195
        qinfo->fp = fp;
196
197
        if (((!qinfo->ac || (qinfo->ac && qinfo->ac->protocol != A_NNTP)) &&
198
             !qinfo->to_list) || !qinfo->from) {
199
                g_warning(_("Queued message header is broken.\n"));
200
                send_queue_info_free(qinfo);
201
                return NULL;
202
        }
203
204
        if (!qinfo->ac) {
205
                qinfo->ac = account_find_from_smtp_server(qinfo->from,
206
                                                          qinfo->server);
207
                if (!qinfo->ac) {
208
                        g_warning("Account not found. "
209
                                  "Using current account...\n");
210
                        qinfo->ac = cur_account;
211
                }
212
        }
213
214
        return qinfo;
215
}
216
217
static gint send_get_queue_contents(QueueInfo *qinfo, const gchar *dest)
218
{
219
        FILE *fp;
220
        glong pos;
221
        gchar buf[BUFFSIZE];
222
223
        g_return_val_if_fail(qinfo != NULL, -1);
224
        g_return_val_if_fail(qinfo->fp != NULL, -1);
225
        g_return_val_if_fail(dest != NULL, -1);
226
227
        if ((fp = g_fopen(dest, "wb")) == NULL) {
228
                FILE_OP_ERROR(dest, "fopen");
229
                return -1;
230
        }
231
232
        pos = ftell(qinfo->fp);
233
234
        while (fgets(buf, sizeof(buf), qinfo->fp) != NULL)
235
                fputs(buf, fp);
236
237
        if (fclose(fp) < 0) {
238
                FILE_OP_ERROR(dest, "fclose");
239
                g_unlink(dest);
240
                return -1;
241
        }
242
243
        fseek(qinfo->fp, pos, SEEK_SET);
244
245
        return 0;
246
}
247
248
static gint send_save_queued_message(QueueInfo *qinfo, gboolean filter_msgs)
249
{
250
        FolderItem *outbox;
251
        gboolean drop_done = FALSE;
252
        gchar tmp[MAXPATHLEN + 1];
253
254
        g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg.out.%08x",
255
                   get_rc_dir(), G_DIR_SEPARATOR, g_random_int());
256
257
        if (send_get_queue_contents(qinfo, tmp) < 0)
258
                return -1;
259
260
        if (filter_msgs) {
261
                FilterInfo *fltinfo;
262
263
                fltinfo = filter_info_new();
264
                fltinfo->account = qinfo->ac;
265
                fltinfo->flags.perm_flags = 0;
266
                fltinfo->flags.tmp_flags = MSG_RECEIVED;
267
268
                filter_apply(prefs_common.fltlist, tmp, fltinfo);
269
270
                drop_done = fltinfo->drop_done;
271
                filter_info_free(fltinfo);
272
        }
273
274
        if (!drop_done) {
275
                outbox = account_get_special_folder(qinfo->ac, F_OUTBOX);
276
                procmsg_save_to_outbox(outbox, tmp);
277
        }
278
279
        g_unlink(tmp);
280
281
        return 0;
282
}
283
284
void send_queue_info_free(QueueInfo *qinfo)
285
{
286
        if (qinfo == NULL) return;
287
288
        slist_free_strings(qinfo->to_list);
289
        g_slist_free(qinfo->to_list);
290
        g_free(qinfo->from);
291
        g_free(qinfo->server);
292
        g_free(qinfo->reply_target);
293
        g_free(qinfo->forward_targets);
294
        if (qinfo->fp)
295
                fclose(qinfo->fp);
296
        g_free(qinfo);
297
}
298
299
gint send_message_queue(QueueInfo *qinfo)
300
{
301
        gint val = 0;
302
        glong fpos;
303
        PrefsAccount *mailac = NULL, *newsac = NULL;
304
305
        g_return_val_if_fail(qinfo != NULL, -1);
306
307
        fpos = ftell(qinfo->fp);
308
309
        if (prefs_common.use_extsend && prefs_common.extsend_cmd) {
310
                val = send_message_local(prefs_common.extsend_cmd, qinfo->fp);
311
        } else {
312
                if (qinfo->ac && qinfo->ac->protocol == A_NNTP) {
313
                        newsac = qinfo->ac;
314
315
                        /* search mail account */
316
                        mailac = account_find_from_address(qinfo->from);
317
                        if (!mailac) {
318
                                if (cur_account &&
319
                                    cur_account->protocol != A_NNTP)
320
                                        mailac = cur_account;
321
                                else {
322
                                        mailac = account_get_default();
323
                                        if (mailac->protocol == A_NNTP)
324
                                                mailac = NULL;
325
                                }
326
                        }
327
                } else
328
                        mailac = qinfo->ac;
329
330
                if (qinfo->to_list) {
331
                        if (mailac)
332
                                val = send_message_smtp(mailac, qinfo->to_list,
333
                                                        qinfo->fp);
334
                        else {
335
                                PrefsAccount tmp_ac;
336
337
                                g_warning("Account not found.\n");
338
339
                                memset(&tmp_ac, 0, sizeof(PrefsAccount));
340
                                tmp_ac.address = qinfo->from;
341
                                tmp_ac.smtp_server = qinfo->server;
342
                                tmp_ac.smtpport = SMTP_PORT;
343
                                val = send_message_smtp(&tmp_ac, qinfo->to_list,
344
                                                        qinfo->fp);
345
                        }
346
                }
347
348
                if (val == 0 && newsac) {
349
                        fseek(qinfo->fp, fpos, SEEK_SET);
350
                        val = news_post_stream(FOLDER(newsac->folder),
351
                                               qinfo->fp);
352
                        if (val < 0)
353
                                alertpanel_error(_("Error occurred while posting the message to %s ."),
354
                                                 newsac->nntp_server);
355
                }
356
        }
357
358
        fseek(qinfo->fp, fpos, SEEK_SET);
359
360
        return val;
361
}
362
363
gint send_message_queue_all(FolderItem *queue, gboolean save_msgs,
364
                            gboolean filter_msgs)
365
{
366
        gint ret = 0;
367
        GSList *mlist = NULL;
368
        GSList *cur;
369
370
        if (!queue)
371
                queue = folder_get_default_queue();
372
        g_return_val_if_fail(queue != NULL, -1);
373
374
        mlist = folder_item_get_msg_list(queue, FALSE);
375
        mlist = procmsg_sort_msg_list(mlist, SORT_BY_NUMBER, SORT_ASCENDING);
376
377
        for (cur = mlist; cur != NULL; cur = cur->next) {
378
                gchar *file;
379
                MsgInfo *msginfo = (MsgInfo *)cur->data;
380
                QueueInfo *qinfo;
381
382
                file = procmsg_get_message_file(msginfo);
383
                if (!file)
384
                        continue;
385
386
                qinfo = send_get_queue_info(file);
387
                if (!qinfo || send_message_queue(qinfo) < 0) {
388
                        g_warning("Sending queued message %d failed.\n",
389
                                  msginfo->msgnum);
390
                        send_queue_info_free(qinfo);
391
                        g_free(file);
392
                        continue;
393
                }
394
395
                if (qinfo->reply_target)
396
                        send_message_set_reply_flag(qinfo->reply_target,
397
                                                    msginfo->inreplyto);
398
                else if (qinfo->forward_targets)
399
                        send_message_set_forward_flags(qinfo->forward_targets);
400
401
                if (save_msgs)
402
                        send_save_queued_message(qinfo, filter_msgs);
403
404
                send_queue_info_free(qinfo);
405
                g_free(file);
406
407
                folder_item_remove_msg(queue, msginfo);
408
                ret++;
409
        }
410
411
        procmsg_msg_list_free(mlist);
412
413
        procmsg_clear_cache(queue);
414
        queue->cache_dirty = FALSE;
415
        queue->mtime = 0;
416
417
        return ret;
418
}
419
420
gint send_message_set_reply_flag(const gchar *target, const gchar *msgid)
421
{
422
        FolderItem *item;
423
        gint num;
424
        MsgInfo *msginfo;
425
        SummaryView *summaryview;
426
427
        g_return_val_if_fail(target != NULL, -1);
428
429
        debug_print("send_message_set_reply_flag(): "
430
                    "setting reply flag to: %s\n", target);
431
432
        summaryview = main_window_get()->summaryview;
433
434
        item = folder_find_item_and_num_from_id(target, &num);
435
        if (!item || num <= 0)
436
                return -1;
437
438
        if (summaryview->folder_item == item) {
439
                msginfo = summary_get_msginfo_by_msgnum(summaryview, num);
440
                if (msginfo) {
441
                        if (msgid && strcmp2(msgid, msginfo->msgid) != 0) {
442
                                debug_print("send_message_set_reply_flag(): "
443
                                            "message-id mismatch\n");
444
                                return -1;
445
                        }
446
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_FORWARDED);
447
                        MSG_SET_PERM_FLAGS(msginfo->flags, MSG_REPLIED);
448
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
449
                        if (MSG_IS_IMAP(msginfo->flags))
450
                                imap_msg_set_perm_flags(msginfo, MSG_REPLIED);
451
                        if (msginfo->folder)
452
                                msginfo->folder->mark_dirty = TRUE;
453
                        summary_update_by_msgnum(summaryview, msginfo->msgnum);
454
                }
455
        } else {
456
                msginfo = procmsg_get_msginfo(item, num);
457
                if (msginfo) {
458
                        if (msgid && strcmp2(msgid, msginfo->msgid) != 0) {
459
                                debug_print("send_message_set_reply_flag(): "
460
                                            "message-id mismatch\n");
461
                                procmsg_msginfo_free(msginfo);
462
                                return -1;
463
                        }
464
                        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_FORWARDED);
465
                        MSG_SET_PERM_FLAGS(msginfo->flags, MSG_REPLIED);
466
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
467
                        if (MSG_IS_IMAP(msginfo->flags))
468
                                imap_msg_set_perm_flags(msginfo, MSG_REPLIED);
469
                        if (msginfo->folder)
470
                                msginfo->folder->mark_dirty = TRUE;
471
                        procmsg_add_flags(msginfo->folder, msginfo->msgnum,
472
                                          msginfo->flags);
473
                        procmsg_msginfo_free(msginfo);
474
                }
475
        }
476
477
        return 0;
478
}
479
480
gint send_message_set_forward_flags(const gchar *targets)
481
{
482
        FolderItem *item;
483
        gint num;
484
        MsgInfo *msginfo;
485
        SummaryView *summaryview;
486
        gchar **paths;
487
        gint i;
488
        GSList *mlist = NULL;
489
490
        g_return_val_if_fail(targets != NULL, -1);
491
492
        debug_print("send_message_set_forward_flags(): "
493
                    "setting forward flags to: %s\n", targets);
494
495
        summaryview = main_window_get()->summaryview;
496
497
        paths = g_strsplit(targets, "\n", 0);
498
499
        for (i = 0; paths[i] != NULL; i++) {
500
                g_strstrip(paths[i]);
501
502
                item = folder_find_item_and_num_from_id(paths[i], &num);
503
                if (!item || num <= 0)
504
                        continue;
505
506
                if (summaryview->folder_item == item) {
507
                        msginfo = summary_get_msginfo_by_msgnum(summaryview,
508
                                                                num);
509
                        if (msginfo) {
510
                                MSG_UNSET_PERM_FLAGS(msginfo->flags,
511
                                                     MSG_REPLIED);
512
                                MSG_SET_PERM_FLAGS(msginfo->flags,
513
                                                   MSG_FORWARDED);
514
                                MSG_SET_TMP_FLAGS(msginfo->flags,
515
                                                  MSG_FLAG_CHANGED);
516
                                if (msginfo->folder)
517
                                        msginfo->folder->mark_dirty = TRUE;
518
                                summary_update_by_msgnum
519
                                        (summaryview, msginfo->msgnum);
520
                                msginfo = procmsg_msginfo_copy(msginfo);
521
                        }
522
                } else {
523
                        msginfo = procmsg_get_msginfo(item, num);
524
                        if (msginfo) {
525
                                MSG_UNSET_PERM_FLAGS(msginfo->flags,
526
                                                     MSG_REPLIED);
527
                                MSG_SET_PERM_FLAGS(msginfo->flags,
528
                                                   MSG_FORWARDED);
529
                                MSG_SET_TMP_FLAGS(msginfo->flags,
530
                                                  MSG_FLAG_CHANGED);
531
                                if (msginfo->folder)
532
                                        msginfo->folder->mark_dirty = TRUE;
533
                                procmsg_add_flags(msginfo->folder,
534
                                                  msginfo->msgnum,
535
                                                  msginfo->flags);
536
                        }
537
                }
538
539
                if (msginfo)
540
                        mlist = g_slist_append(mlist, msginfo);
541
        }
542
543
        if (mlist) {
544
                msginfo = (MsgInfo *)mlist->data;
545
                if (MSG_IS_IMAP(msginfo->flags))
546
                        imap_msg_list_unset_perm_flags(mlist, MSG_REPLIED);
547
        }
548
549
        procmsg_msg_list_free(mlist);
550
        g_strfreev(paths);
551
552
        return 0;
553
}
554
555
static gint send_message_local(const gchar *command, FILE *fp)
556
{
557
        gchar **argv;
558
        GPid pid;
559
        gint child_stdin;
560
        gchar buf[BUFFSIZE];
561
        gboolean err = FALSE;
562
        gint status;
563
564
        g_return_val_if_fail(command != NULL, -1);
565
        g_return_val_if_fail(fp != NULL, -1);
566
567
        log_message(_("Sending message using command: %s\n"), command);
568
569
        argv = strsplit_with_quote(command, " ", 0);
570
571
        if (g_spawn_async_with_pipes(NULL, argv, NULL,
572
                                     G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
573
                                     &pid, &child_stdin, NULL, NULL,
574
                                     NULL) == FALSE) {
575
                g_snprintf(buf, sizeof(buf),
576
                           _("Can't execute command: %s"), command);
577
                log_warning("%s\n", buf);
578
                alertpanel_error("%s", buf);
579
                g_strfreev(argv);
580
                return -1;
581
        }
582
        g_strfreev(argv);
583
584
        while (fgets(buf, sizeof(buf), fp) != NULL) {
585
                strretchomp(buf);
586
                if (buf[0] == '.' && buf[1] == '\0') {
587
                        if (fd_write_all(child_stdin, ".", 1) < 0) {
588
                                err = TRUE;
589
                                break;
590
                        }
591
                }
592
                if (fd_write_all(child_stdin, buf, strlen(buf)) < 0 ||
593
                    fd_write_all(child_stdin, "\n", 1) < 0) {
594
                        err = TRUE;
595
                        break;
596
                }
597
        }
598
599
        fd_close(child_stdin);
600
601
#ifdef G_OS_UNIX
602
        waitpid(pid, &status, 0);
603
        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
604
                err = TRUE;
605
#endif
606
607
        g_spawn_close_pid(pid);
608
609
        if (err) {
610
                g_snprintf(buf, sizeof(buf),
611
                           _("Error occurred while executing command: %s"),
612
                           command);
613
                log_warning("%s\n", buf);
614
                alertpanel_error("%s", buf);
615
                return -1;
616
        }
617
618
        return 0;
619
}
620
621
static gint send_message_smtp(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp)
622
{
623
        Session *session;
624
        SMTPSession *smtp_session;
625
        SocksInfo *socks_info = NULL;
626
        FILE *out_fp;
627
        gushort port;
628
        SendProgressDialog *dialog;
629
        gchar buf[BUFFSIZE];
630
        gint ret = 0;
631
632
        g_return_val_if_fail(ac_prefs != NULL, -1);
633
        g_return_val_if_fail(ac_prefs->address != NULL, -1);
634
        g_return_val_if_fail(ac_prefs->smtp_server != NULL, -1);
635
        g_return_val_if_fail(to_list != NULL, -1);
636
        g_return_val_if_fail(fp != NULL, -1);
637
638
        session = smtp_session_new();
639
        smtp_session = SMTP_SESSION(session);
640
641
        smtp_session->hostname =
642
                ac_prefs->set_domain ? g_strdup(ac_prefs->domain) : NULL;
643
644
        if (ac_prefs->use_smtp_auth) {
645
                inc_lock();
646
647
                smtp_session->forced_auth_type = ac_prefs->smtp_auth_type;
648
649
                if (ac_prefs->smtp_userid) {
650
                        smtp_session->user = g_strdup(ac_prefs->smtp_userid);
651
                        if (ac_prefs->smtp_passwd)
652
                                smtp_session->pass =
653
                                        g_strdup(ac_prefs->smtp_passwd);
654
                        else if (ac_prefs->tmp_smtp_pass)
655
                                smtp_session->pass =
656
                                        g_strdup(ac_prefs->tmp_smtp_pass);
657
                        else {
658
                                smtp_session->pass =
659
                                        input_query_password
660
                                                (ac_prefs->smtp_server,
661
                                                 smtp_session->user);
662
                                if (!smtp_session->pass)
663
                                        smtp_session->pass = g_strdup("");
664
                                ac_prefs->tmp_smtp_pass =
665
                                        g_strdup(smtp_session->pass);
666
                        }
667
                } else {
668
                        smtp_session->user = g_strdup(ac_prefs->userid);
669
                        if (ac_prefs->passwd)
670
                                smtp_session->pass = g_strdup(ac_prefs->passwd);
671
                        else if (ac_prefs->tmp_pass)
672
                                smtp_session->pass =
673
                                        g_strdup(ac_prefs->tmp_pass);
674
                        else {
675
                                smtp_session->pass =
676
                                        input_query_password
677
                                                (ac_prefs->smtp_server,
678
                                                 smtp_session->user);
679
                                if (!smtp_session->pass)
680
                                        smtp_session->pass = g_strdup("");
681
                                ac_prefs->tmp_pass =
682
                                        g_strdup(smtp_session->pass);
683
                        }
684
                }
685
686
                inc_unlock();
687
        } else {
688
                smtp_session->user = NULL;
689
                smtp_session->pass = NULL;
690
        }
691
692
        smtp_session->from = g_strdup(ac_prefs->address);
693
        smtp_session->to_list = to_list;
694
        smtp_session->cur_to = to_list;
695
696
        out_fp = get_outgoing_rfc2822_file(fp);
697
        if (!out_fp) {
698
                session_destroy(session);
699
                return -1;
700
        }
701
        smtp_session->send_data_fp = out_fp;
702
        smtp_session->send_data_len = get_left_file_size(out_fp);
703
        if (smtp_session->send_data_len < 0) {
704
                session_destroy(session);
705
                return -1;
706
        }
707
708
#if USE_SSL
709
        port = ac_prefs->set_smtpport ? ac_prefs->smtpport :
710
                ac_prefs->ssl_smtp == SSL_TUNNEL ? SSMTP_PORT : SMTP_PORT;
711
        session->ssl_type = ac_prefs->ssl_smtp;
712
        if (ac_prefs->ssl_smtp != SSL_NONE)
713
                session->nonblocking = ac_prefs->use_nonblocking_ssl;
714
#else
715
        port = ac_prefs->set_smtpport ? ac_prefs->smtpport : SMTP_PORT;
716
#endif
717
718
        if (ac_prefs->pop_before_smtp && ac_prefs->protocol == A_POP3) {
719
                if (inc_pop_before_smtp(ac_prefs) < 0) {
720
                        session_destroy(session);
721
                        return -1;
722
                }
723
        }
724
725
        dialog = send_progress_dialog_create();
726
        dialog->session = session;
727
728
        progress_dialog_append(dialog->dialog, NULL, ac_prefs->smtp_server,
729
                               _("Connecting"), "", NULL);
730
731
        g_snprintf(buf, sizeof(buf), _("Connecting to SMTP server: %s ..."),
732
                   ac_prefs->smtp_server);
733
        progress_dialog_set_label(dialog->dialog, buf);
734
        log_message("%s\n", buf);
735
736
        session_set_recv_message_notify(session, send_recv_message, dialog);
737
        session_set_send_data_progressive_notify
738
                (session, send_send_data_progressive, dialog);
739
        session_set_send_data_notify(session, send_send_data_finished, dialog);
740
741
        session_set_timeout(session, prefs_common.io_timeout_secs * 1000);
742
743
        if (ac_prefs->use_socks && ac_prefs->use_socks_for_send) {
744
                socks_info = socks_info_new(ac_prefs->socks_type,
745
                                            ac_prefs->proxy_host,
746
                                            ac_prefs->proxy_port,
747
                                            ac_prefs->use_proxy_auth
748
                                                ? ac_prefs->proxy_name : NULL,
749
                                            ac_prefs->use_proxy_auth
750
                                                ? ac_prefs->proxy_pass : NULL);
751
        }
752
753
        inc_lock();
754
755
        if (session_connect_full(session, ac_prefs->smtp_server, port,
756
                                 socks_info) < 0) {
757
                if (dialog->show_dialog)
758
                        manage_window_focus_in(dialog->dialog->window, NULL, NULL);
759
                send_put_error(session);
760
                if (dialog->show_dialog)
761
                        manage_window_focus_out(dialog->dialog->window, NULL, NULL);
762
                session_destroy(session);
763
                send_progress_dialog_destroy(dialog);
764
                inc_unlock();
765
                return -1;
766
        }
767
768
        debug_print("send_message_smtp(): begin event loop\n");
769
770
        while (session_is_connected(session) && dialog->cancelled == FALSE)
771
                gtk_main_iteration();
772
        log_window_flush();
773
774
        if (SMTP_SESSION(session)->error_val == SM_AUTHFAIL) {
775
                if (ac_prefs->smtp_userid && ac_prefs->tmp_smtp_pass) {
776
                        g_free(ac_prefs->tmp_smtp_pass);
777
                        ac_prefs->tmp_smtp_pass = NULL;
778
                } else if (!ac_prefs->smtp_userid && ac_prefs->tmp_pass) {
779
                        g_free(ac_prefs->tmp_pass);
780
                        ac_prefs->tmp_pass = NULL;
781
                }
782
                ret = -1;
783
        } else if (session->state == SESSION_EOF &&
784
                   SMTP_SESSION(session)->state == SMTP_QUIT) {
785
                /* consider EOF right after QUIT successful */
786
                log_warning("%s\n", _("Connection closed by the remote host."));
787
                ret = 0;
788
        } else if (session->state == SESSION_ERROR &&
789
                   SMTP_SESSION(session)->state == SMTP_QUIT) {
790
                /* ignore errors right after QUIT */
791
                log_warning("%s\n", _("Error occurred after QUIT command (ignored)"));
792
                ret = 0;
793
        } else if (session->state == SESSION_ERROR ||
794
                   session->state == SESSION_EOF ||
795
                   session->state == SESSION_TIMEOUT ||
796
                   SMTP_SESSION(session)->state == SMTP_ERROR ||
797
                   SMTP_SESSION(session)->error_val != SM_OK)
798
                ret = -1;
799
        else if (dialog->cancelled == TRUE)
800
                ret = -1;
801
802
        if (ret == -1) {
803
                if (dialog->show_dialog)
804
                        manage_window_focus_in(dialog->dialog->window, NULL, NULL);
805
                send_put_error(session);
806
                if (dialog->show_dialog)
807
                        manage_window_focus_out(dialog->dialog->window, NULL, NULL);
808
        }
809
810
        session_destroy(session);
811
        send_progress_dialog_destroy(dialog);
812
        inc_unlock();
813
814
        return ret;
815
}
816
817
static gint send_recv_message(Session *session, const gchar *msg, gpointer data)
818
{
819
        gchar buf[BUFFSIZE];
820
        SMTPSession *smtp_session = SMTP_SESSION(session);
821
        SendProgressDialog *dialog = (SendProgressDialog *)data;
822
        gchar *state_str = NULL;
823
824
        g_return_val_if_fail(dialog != NULL, -1);
825
826
        gdk_threads_enter();
827
828
        switch (smtp_session->state) {
829
        case SMTP_READY:
830
        case SMTP_CONNECTED:
831
                gdk_threads_leave();
832
                return 0;
833
        case SMTP_HELO:
834
                g_snprintf(buf, sizeof(buf), _("Sending HELO..."));
835
                state_str = _("Authenticating");
836
                statusbar_print_all(_("Sending message via %s:%d..."),
837
                                    session->server, session->port);
838
                break;
839
        case SMTP_EHLO:
840
                g_snprintf(buf, sizeof(buf), _("Sending EHLO..."));
841
                state_str = _("Authenticating");
842
                statusbar_print_all(_("Sending message via %s:%d..."),
843
                                    session->server, session->port);
844
                break;
845
        case SMTP_AUTH:
846
                g_snprintf(buf, sizeof(buf), _("Authenticating..."));
847
                state_str = _("Authenticating");
848
                break;
849
        case SMTP_FROM:
850
                g_snprintf(buf, sizeof(buf), _("Sending MAIL FROM..."));
851
                state_str = _("Sending");
852
                break;
853
        case SMTP_RCPT:
854
                g_snprintf(buf, sizeof(buf), _("Sending RCPT TO..."));
855
                state_str = _("Sending");
856
                break;
857
        case SMTP_DATA:
858
        case SMTP_EOM:
859
                g_snprintf(buf, sizeof(buf), _("Sending DATA..."));
860
                state_str = _("Sending");
861
                break;
862
        case SMTP_QUIT:
863
                g_snprintf(buf, sizeof(buf), _("Quitting..."));
864
                state_str = _("Quitting");
865
                break;
866
        case SMTP_ERROR:
867
                g_warning("send: error: %s\n", msg);
868
                gdk_threads_leave();
869
                return 0;
870
        default:
871
                gdk_threads_leave();
872
                return 0;
873
        }
874
875
        progress_dialog_set_label(dialog->dialog, buf);
876
        progress_dialog_set_row_status(dialog->dialog, 0, state_str);
877
878
        gdk_threads_leave();
879
880
        return 0;
881
}
882
883
static gint send_send_data_progressive(Session *session, guint cur_len,
884
                                       guint total_len, gpointer data)
885
{
886
        gchar buf[BUFFSIZE];
887
        SendProgressDialog *dialog = (SendProgressDialog *)data;
888
889
        g_return_val_if_fail(dialog != NULL, -1);
890
891
        if (SMTP_SESSION(session)->state != SMTP_SEND_DATA &&
892
            SMTP_SESSION(session)->state != SMTP_EOM)
893
                return 0;
894
895
        gdk_threads_enter();
896
897
        g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
898
                   cur_len, total_len);
899
        progress_dialog_set_label(dialog->dialog, buf);
900
        progress_dialog_set_percentage
901
                (dialog->dialog, (gfloat)cur_len / (gfloat)total_len);
902
        g_snprintf(buf, sizeof(buf), _("%d / %d bytes"),
903
                   cur_len, total_len);
904
        progress_dialog_set_row_progress(dialog->dialog, 0, buf);
905
#ifdef G_OS_WIN32
906
        GTK_EVENTS_FLUSH();
907
#endif
908
        gdk_threads_leave();
909
910
        return 0;
911
}
912
913
static gint send_send_data_finished(Session *session, guint len, gpointer data)
914
{
915
        SendProgressDialog *dialog = (SendProgressDialog *)data;
916
917
        g_return_val_if_fail(dialog != NULL, -1);
918
919
        send_send_data_progressive(session, len, len, dialog);
920
921
        return 0;
922
}
923
924
static SendProgressDialog *send_progress_dialog_create(void)
925
{
926
        SendProgressDialog *dialog;
927
        ProgressDialog *progress;
928
929
        dialog = g_new0(SendProgressDialog, 1);
930
931
        progress = progress_dialog_create();
932
        gtk_window_set_title(GTK_WINDOW(progress->window),
933
                             _("Sending message"));
934
        g_signal_connect(G_OBJECT(progress->cancel_btn), "clicked",
935
                         G_CALLBACK(send_cancel_button_cb), dialog);
936
        g_signal_connect(G_OBJECT(progress->window), "delete_event",
937
                         G_CALLBACK(gtk_true), NULL);
938
        /* gtk_window_set_modal(GTK_WINDOW(progress->window), TRUE); */
939
        manage_window_set_transient(GTK_WINDOW(progress->window));
940
941
        progress_dialog_set_value(progress, 0.0);
942
943
        if (prefs_common.show_send_dialog) {
944
                dialog->show_dialog = TRUE;
945
                gtk_widget_show_now(progress->window);
946
        }
947
948
        dialog->dialog = progress;
949
950
        return dialog;
951
}
952
953
static void send_progress_dialog_destroy(SendProgressDialog *dialog)
954
{
955
        g_return_if_fail(dialog != NULL);
956
957
        manage_window_destroy(dialog->dialog->window, NULL);
958
        progress_dialog_destroy(dialog->dialog);
959
        g_free(dialog);
960
}
961
962
static void send_cancel_button_cb(GtkWidget *widget, gpointer data)
963
{
964
        SendProgressDialog *dialog = (SendProgressDialog *)data;
965
966
        dialog->cancelled = TRUE;
967
        session_disconnect(dialog->session);
968
}
969
970
static void send_put_error(Session *session)
971
{
972
        gchar *msg;
973
        gchar *log_msg = NULL;
974
        gchar *err_msg = NULL;
975
976
        msg = SMTP_SESSION(session)->error_msg;
977
978
        switch (SMTP_SESSION(session)->error_val) {
979
        case SM_ERROR:
980
        case SM_UNRECOVERABLE:
981
                log_msg = _("Error occurred while sending the message.");
982
                if (msg)
983
                        err_msg = g_strdup_printf
984
                                (_("Error occurred while sending the message:\n%s"),
985
                                 msg);
986
                else
987
                        err_msg = g_strdup(log_msg);
988
                break;
989
        case SM_AUTHFAIL:
990
                log_msg = _("Authentication failed.");
991
                if (msg)
992
                        err_msg = g_strdup_printf
993
                                (_("Authentication failed:\n%s"), msg);
994
                else
995
                        err_msg = g_strdup(log_msg);
996
                break;
997
        default:
998
                switch (session->state) {
999
                case SESSION_ERROR:
1000
                        if (SMTP_SESSION(session)->state == SMTP_READY) {
1001
                                log_msg = _("Can't connect to SMTP server.");
1002
                                err_msg = g_strdup_printf
1003
                                        (_("Can't connect to SMTP server: %s:%d"), session->server, session->port);
1004
                        } else {
1005
                                log_msg = _("Error occurred while sending the message.");
1006
                                err_msg = g_strdup(log_msg);
1007
                        }
1008
                        break;
1009
                case SESSION_EOF:
1010
                        log_msg = _("Connection closed by the remote host.");
1011
                        err_msg = g_strdup(log_msg);
1012
                        break;
1013
                case SESSION_TIMEOUT:
1014
                        log_msg = _("Session timed out.");
1015
                        err_msg = g_strdup(log_msg);
1016
                        break;
1017
                default:
1018
                        break;
1019
                }
1020
                break;
1021
        }
1022
1023
        if (log_msg)
1024
                log_warning("%s\n", log_msg);
1025
        if (err_msg) {
1026
                alertpanel_error("%s", err_msg);
1027
                g_free(err_msg);
1028
        }
1029
}
1030