2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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.
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.
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.
27 #include <gtk/gtkmain.h>
28 #include <gtk/gtksignal.h>
29 #include <gtk/gtkwindow.h>
30 #include <gtk/gtkclist.h>
40 #include "prefs_account.h"
43 #include "progressdialog.h"
44 #include "manage_window.h"
46 #include "procheader.h"
52 #define SSMTP_PORT 465
55 typedef struct _SendProgressDialog SendProgressDialog
;
57 struct _SendProgressDialog
59 ProgressDialog
*dialog
;
65 static gint
send_message_smtp (GSList
*to_list
, const gchar
*from
,
66 const gchar
*server
, gushort port
,
67 const gchar
*domain
, const gchar
*userid
,
68 const gchar
*passwd
, gboolean use_smtp_auth
,
71 static SockInfo
*send_smtp_open (const gchar
*server
, gushort port
,
72 const gchar
*domain
, gboolean use_smtp_auth
);
74 static gint
send_message_smtp (GSList
*to_list
, const gchar
*from
,
75 const gchar
*server
, gushort port
,
76 const gchar
*domain
, const gchar
*userid
,
77 const gchar
*passwd
, gboolean use_smtp_auth
,
78 FILE *fp
, SSLSMTPType ssl
);
80 static SockInfo
*send_smtp_open (const gchar
*server
, gushort port
,
81 const gchar
*domain
, gboolean use_smtp_auth
, SSLSMTPType ssl
);
84 static SendProgressDialog
*send_progress_dialog_create(void);
85 static void send_progress_dialog_destroy(SendProgressDialog
*dialog
);
86 static void send_cancel(GtkWidget
*widget
, gpointer data
);
88 static gint
send_message_with_command(GSList
*to_list
, gchar
* mailcmd
,
91 gint
send_message(const gchar
*file
, PrefsAccount
*ac_prefs
, GSList
*to_list
)
98 g_return_val_if_fail(file
!= NULL
, -1);
99 g_return_val_if_fail(ac_prefs
!= NULL
, -1);
100 g_return_val_if_fail(to_list
!= NULL
, -1);
102 if ((fp
= fopen(file
, "r")) == NULL
) {
103 FILE_OP_ERROR(file
, "fopen");
107 if (ac_prefs
->protocol
== A_LOCAL
&& ac_prefs
->use_mail_command
) {
108 val
= send_message_with_command(to_list
,
109 ac_prefs
->mail_command
,
113 port
= ac_prefs
->set_smtpport
? ac_prefs
->smtpport
: SMTP_PORT
;
115 port
= ac_prefs
->set_smtpport
? ac_prefs
->smtpport
:
116 (ac_prefs
->ssl_smtp
== SSL_SMTP_TUNNEL
? SSMTP_PORT
: SMTP_PORT
);
118 domain
= ac_prefs
->set_domain
? ac_prefs
->domain
: NULL
;
121 val
= send_message_smtp(to_list
, ac_prefs
->address
,
122 ac_prefs
->smtp_server
, port
, domain
,
123 ac_prefs
->userid
, ac_prefs
->passwd
,
124 ac_prefs
->use_smtp_auth
, fp
);
126 val
= send_message_smtp(to_list
, ac_prefs
->address
,
127 ac_prefs
->smtp_server
, port
, domain
,
128 ac_prefs
->userid
, ac_prefs
->passwd
,
129 ac_prefs
->use_smtp_auth
, fp
,
145 static gint
send_message_with_command(GSList
*to_list
, gchar
* mailcmd
,
154 len
= strlen(mailcmd
);
155 for (cur
= to_list
; cur
!= NULL
; cur
= cur
->next
)
156 len
+= strlen((gchar
*)cur
->data
) + 1;
158 cmdline
= g_new(gchar
, len
+ 1);
159 strcpy(cmdline
, mailcmd
);
161 for (cur
= to_list
; cur
!= NULL
; cur
= cur
->next
) {
162 cmdline
= strncat(cmdline
, " ", len
);
163 cmdline
= strncat(cmdline
, (gchar
*)cur
->data
, len
);
166 log_message(_("Using command to send mail: %s ...\n"), cmdline
);
168 p
= popen(cmdline
, "w");
170 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
173 /* escape when a dot appears on the top */
183 log_message(_("Mail sent successfully ...\n"));
188 gint
send_message_queue(const gchar
*file
)
190 static HeaderEntry qentry
[] = {{"S:", NULL
, FALSE
},
191 {"SSV:", NULL
, FALSE
},
193 {NULL
, NULL
, FALSE
}};
197 gchar
*server
= NULL
;
198 GSList
*to_list
= NULL
;
202 g_return_val_if_fail(file
!= NULL
, -1);
204 if ((fp
= fopen(file
, "r")) == NULL
) {
205 FILE_OP_ERROR(file
, "fopen");
209 while ((hnum
= procheader_get_one_field(buf
, sizeof(buf
), fp
, qentry
))
211 gchar
*p
= buf
+ strlen(qentry
[hnum
].name
);
215 if (!from
) from
= g_strdup(p
);
218 if (!server
) server
= g_strdup(p
);
221 to_list
= address_list_append(to_list
, p
);
227 if (!to_list
|| !from
|| !server
) {
228 g_warning(_("Queued message header is broken.\n"));
235 ac
= account_find_from_smtp_server(from
, server
);
237 g_warning(_("Account not found. Using current account...\n"));
243 port
= ac
->set_smtpport
? ac
->smtpport
: SMTP_PORT
;
245 port
= ac
->set_smtpport
? ac
->smtpport
: (ac
->ssl_smtp
== SSL_SMTP_TUNNEL
? SSMTP_PORT
: SMTP_PORT
);
247 domain
= ac
->set_domain
? ac
->domain
: NULL
;
249 val
= send_message_smtp
250 (to_list
, from
, server
, port
, domain
,
251 ac
->userid
, ac
->passwd
, ac
->use_smtp_auth
, fp
);
253 val
= send_message_smtp
254 (to_list
, from
, server
, port
, domain
,
255 ac
->userid
, ac
->passwd
, ac
->use_smtp_auth
, fp
, ac
->ssl_smtp
);
258 g_warning(_("Account not found.\n"));
260 val
= send_message_smtp
261 (to_list
, from
, server
, SMTP_PORT
, NULL
,
262 NULL
, NULL
, FALSE
, fp
);
264 val
= send_message_smtp
265 (to_list
, from
, server
, SMTP_PORT
, NULL
,
266 NULL
, NULL
, FALSE
, fp
, FALSE
);
271 slist_free_strings(to_list
);
272 g_slist_free(to_list
);
280 #define EXIT_IF_CANCELLED() \
282 if (dialog->cancelled) { \
283 sock_close(smtp_sock); \
284 send_progress_dialog_destroy(dialog); \
289 #define SEND_EXIT_IF_ERROR(f, s) \
291 EXIT_IF_CANCELLED(); \
293 log_warning("Error occurred while %s\n", s); \
294 sock_close(smtp_sock); \
295 send_progress_dialog_destroy(dialog); \
300 #define SEND_EXIT_IF_NOTOK(f, s) \
302 EXIT_IF_CANCELLED(); \
303 if ((f) != SM_OK) { \
304 log_warning("Error occurred while %s\n", s); \
305 if (smtp_quit(smtp_sock) != SM_OK) \
306 log_warning("Error occurred while sending QUIT\n"); \
307 sock_close(smtp_sock); \
308 send_progress_dialog_destroy(dialog); \
314 static gint
send_message_smtp(GSList
*to_list
, const gchar
*from
,
315 const gchar
*server
, gushort port
,
316 const gchar
*domain
, const gchar
*userid
,
317 const gchar
*passwd
, gboolean use_smtp_auth
,
320 static gint
send_message_smtp(GSList
*to_list
, const gchar
*from
,
321 const gchar
*server
, gushort port
,
322 const gchar
*domain
, const gchar
*userid
,
323 const gchar
*passwd
, gboolean use_smtp_auth
,
324 FILE *fp
, SSLSMTPType ssl
)
327 SockInfo
*smtp_sock
= NULL
;
328 SendProgressDialog
*dialog
;
330 const gchar
*text
[3];
336 struct timeval tv_prev
, tv_cur
;
338 g_return_val_if_fail(to_list
!= NULL
, -1);
339 g_return_val_if_fail(from
!= NULL
, -1);
340 g_return_val_if_fail(server
!= NULL
, -1);
341 g_return_val_if_fail(fp
!= NULL
, -1);
343 size
= get_left_file_size(fp
);
344 if (size
< 0) return -1;
346 dialog
= send_progress_dialog_create();
350 text
[2] = _("Standby");
351 clist
= GTK_CLIST(dialog
->dialog
->clist
);
352 gtk_clist_append(clist
, (gchar
**)text
);
354 g_snprintf(buf
, sizeof(buf
), _("Connecting to SMTP server: %s ..."),
356 log_message("%s\n", buf
);
357 progress_dialog_set_label(dialog
->dialog
, buf
);
358 gtk_clist_set_text(clist
, 0, 2, _("Connecting"));
362 SEND_EXIT_IF_ERROR((smtp_sock
= send_smtp_open
363 (server
, port
, domain
, use_smtp_auth
)),
364 "connecting to server");
366 SEND_EXIT_IF_ERROR((smtp_sock
= send_smtp_open
367 (server
, port
, domain
, use_smtp_auth
, ssl
)),
368 "connecting to server");
371 progress_dialog_set_label(dialog
->dialog
, _("Sending MAIL FROM..."));
372 gtk_clist_set_text(clist
, 0, 2, _("Sending"));
376 (smtp_from(smtp_sock
, from
, userid
, passwd
, use_smtp_auth
),
377 "sending MAIL FROM");
379 progress_dialog_set_label(dialog
->dialog
, _("Sending RCPT TO..."));
382 for (cur
= to_list
; cur
!= NULL
; cur
= cur
->next
)
383 SEND_EXIT_IF_NOTOK(smtp_rcpt(smtp_sock
, (gchar
*)cur
->data
),
386 progress_dialog_set_label(dialog
->dialog
, _("Sending DATA..."));
389 SEND_EXIT_IF_NOTOK(smtp_data(smtp_sock
), "sending DATA");
391 gettimeofday(&tv_prev
, NULL
);
394 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
395 bytes
+= strlen(buf
);
398 gettimeofday(&tv_cur
, NULL
);
399 if (tv_cur
.tv_sec
- tv_prev
.tv_sec
> 0 ||
400 tv_cur
.tv_usec
- tv_prev
.tv_usec
> UI_REFRESH_INTERVAL
) {
401 g_snprintf(str
, sizeof(str
),
402 _("Sending message (%d / %d bytes)"),
404 progress_dialog_set_label(dialog
->dialog
, str
);
405 progress_dialog_set_percentage
406 (dialog
->dialog
, (gfloat
)bytes
/ (gfloat
)size
);
408 gettimeofday(&tv_prev
, NULL
);
411 /* escape when a dot appears on the top */
413 SEND_EXIT_IF_ERROR(sock_write(smtp_sock
, ".", 1),
416 SEND_EXIT_IF_ERROR(sock_puts(smtp_sock
, buf
), "sending data");
419 progress_dialog_set_label(dialog
->dialog
, _("Quitting..."));
422 SEND_EXIT_IF_NOTOK(smtp_eom(smtp_sock
), "terminating data");
423 SEND_EXIT_IF_NOTOK(smtp_quit(smtp_sock
), "sending QUIT");
426 ssl_done_socket(smtp_sock
);
429 sock_close(smtp_sock
);
430 send_progress_dialog_destroy(dialog
);
436 static SockInfo
*send_smtp_open(const gchar
*server
, gushort port
,
437 const gchar
*domain
, gboolean use_smtp_auth
)
439 static SockInfo
*send_smtp_open(const gchar
*server
, gushort port
,
440 const gchar
*domain
, gboolean use_smtp_auth
, SSLSMTPType ssl
)
446 g_return_val_if_fail(server
!= NULL
, NULL
);
448 if ((sock
= sock_connect(server
, port
)) == NULL
) {
449 log_warning(_("Can't connect to SMTP server: %s:%d\n"),
455 if((ssl
== SSL_SMTP_TUNNEL
) && !ssl_init_socket(sock
)) {
456 log_warning(_("SSL connection failed"));
462 if (smtp_ok(sock
) == SM_OK
) {
463 val
= smtp_helo(sock
, domain
? domain
: get_domain_name(),
466 log_warning(_("Error occurred while sending HELO\n"));
473 if(ssl
== SSL_SMTP_STARTTLS
) {
474 val
= smtp_starttls(sock
, domain
? domain
: get_domain_name(),
477 log_warning(_("Error occurred while sending STARTTLS\n"));
488 static SendProgressDialog
*send_progress_dialog_create(void)
490 SendProgressDialog
*dialog
;
491 ProgressDialog
*progress
;
493 dialog
= g_new0(SendProgressDialog
, 1);
495 progress
= progress_dialog_create();
496 gtk_window_set_title(GTK_WINDOW(progress
->window
),
497 _("Sending message"));
498 gtk_signal_connect(GTK_OBJECT(progress
->cancel_btn
), "clicked",
499 GTK_SIGNAL_FUNC(send_cancel
), dialog
);
500 gtk_signal_connect(GTK_OBJECT(progress
->window
), "delete_event",
501 GTK_SIGNAL_FUNC(gtk_true
), NULL
);
502 gtk_window_set_modal(GTK_WINDOW(progress
->window
), TRUE
);
503 manage_window_set_transient(GTK_WINDOW(progress
->window
));
505 progress_dialog_set_value(progress
, 0.0);
507 gtk_widget_show_now(progress
->window
);
509 dialog
->dialog
= progress
;
510 dialog
->queue_list
= NULL
;
511 dialog
->cancelled
= FALSE
;
516 static void send_progress_dialog_destroy(SendProgressDialog
*dialog
)
518 g_return_if_fail(dialog
!= NULL
);
520 progress_dialog_destroy(dialog
->dialog
);
524 static void send_cancel(GtkWidget
*widget
, gpointer data
)
526 SendProgressDialog
*dialog
= data
;
528 dialog
->cancelled
= TRUE
;