Statistics
| Revision:

root / src / send_message.c @ 1973

History | View | Annotate | Download (23.9 kB)

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