sync with 0.8.11cvs6
authorPaul Mangan <paul@claws-mail.org>
Thu, 20 Mar 2003 11:00:55 +0000 (11:00 +0000)
committerPaul Mangan <paul@claws-mail.org>
Thu, 20 Mar 2003 11:00:55 +0000 (11:00 +0000)
23 files changed:
ChangeLog
ChangeLog.claws
ChangeLog.jp
configure.ac
src/Makefile.am
src/common/nntp.c
src/common/session.c
src/common/session.h
src/common/smtp.c
src/common/smtp.h
src/common/socket.c
src/common/socket.h
src/common/utils.c
src/common/utils.h
src/compose.c
src/imap.c
src/main.c
src/messageview.c
src/news.c
src/pop.c
src/procmsg.c
src/send_message.c [new file with mode: 0644]
src/send_message.h [new file with mode: 0644]

index 5f92961..c009e86 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2003-03-20
+
+       * src/session.[ch]: session_start_tls(): new.
+         session_recv_msg(): made it static.
+
+2003-03-20
+
+       * implemented asynchronous network I/O.
+       * src/session.[ch]: the interface to communicate with servers through
+         child process.
+       * src/smtp.[ch]
+         src/send_message.[ch]: rewrote using new I/O system.
+       * src/socket.[ch]: renamed *_write() to *_write_all(), and made
+         *_write() as just a simple wrapper for write().
+       * src/utils.c: get_outgoing_rfc2822_str(): new. It modifies the
+         message to send with SMTP or NNTP.
+         file_read_stream_to_str(): new.
+
 2003-03-12
 
        * src/textview.c: textview_button_pressed(): corrected the range of
index a1b1e89..2733a66 100644 (file)
@@ -1,3 +1,8 @@
+2003-03-20 [paul]      0.8.11claws31
+
+       * sync with 0.8.11cvs6
+               see ChangeLog 2003-03-20
+
 2003-03-19 [match]     0.8.11claws30
 
        * src/addritem.[ch]
index ec5e378..7bb3e88 100644 (file)
@@ -1,3 +1,21 @@
+2003-03-20
+
+       * src/session.[ch]: session_start_tls(): ¿·µ¬¡£
+         session_recv_msg(): static ¤Ë¤·¤¿¡£
+
+2003-03-20
+
+       * ÈóƱ´ü¥Í¥Ã¥È¥ï¡¼¥¯ I/O ¤ò¼ÂÁõ¡£
+       * src/session.[ch]: »Ò¥×¥í¥»¥¹¤òÄ̤·¤Æ¥µ¡¼¥Ð¤ÈÄÌ¿®¤¹¤ë¤¿¤á¤Î
+         ¥¤¥ó¥¿¥Õ¥§¡¼¥¹¡£
+       * src/smtp.[ch]
+         src/send_message.[ch]: ¿· I/O ¥·¥¹¥Æ¥à¤ò»È¤Ã¤Æ½ñ¤­Ä¾¤·¤¿¡£
+       * src/socket.[ch]: *_write() ¤ò *_write_all() ¤Ë̾¾ÎÊѹ¹¤·¡¢
+         *_write() ¤òñ¤Ê¤ë write() ¤Î¥é¥Ã¥Ñ¡¼¤È¤·¤¿¡£
+       * src/utils.c: get_outgoing_rfc2822_str(): ¿·µ¬¡£¥á¥Ã¥»¡¼¥¸¤ò SMTP
+         ¤Þ¤¿¤Ï NNTP ¤ÇÁ÷¿®¤¹¤ë¤¿¤á¤Ë½¤Àµ¤¹¤ë¡£
+         file_read_stream_to_str(): ¿·µ¬¡£
+
 2003-03-12
 
        * src/textview.c: textview_button_pressed(): URI ¤Î¥ê¥ó¥¯¤ÎÈϰϤò
index 3775cfe..4aa9145 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=8
 MICRO_VERSION=11
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=claws30
+EXTRA_VERSION=claws31
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
index fd0b9b5..85386d7 100644 (file)
@@ -86,7 +86,7 @@ sylpheed_SOURCES = \
        pop.c pop.h \
        mh.c mh.h \
        mbox.c mbox.h \
-       send.c send.h \
+       send_message.c send_message.h \
        recv.c recv.h \
        inc.c inc.h \
        import.c import.h \
index f98d889..74b7617 100644 (file)
@@ -256,27 +256,21 @@ gint nntp_post(NNTPSockInfo *sock, FILE *fp)
 {
        gint ok;
        gchar buf[NNTPBUFSIZE];
+       gchar *msg;
 
        ok = nntp_gen_command(sock, buf, "POST");
        if (ok != NN_SUCCESS)
                return ok;
 
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
-               strretchomp(buf);
-               if (buf[0] == '.') {
-                       if (sock_write(sock->sock, ".", 1) < 0) {
-                               log_warning(_("Error occurred while posting\n"));
-                               return NN_SOCKET;
-                       }
-               }
-
-               if (sock_puts(sock->sock, buf) < 0) {
-                       log_warning(_("Error occurred while posting\n"));
-                       return NN_SOCKET;
-               }
+       msg = get_outgoing_rfc2822_str(fp);
+       if (sock_write_all(sock->sock, msg, strlen(msg)) < 0) {
+               log_warning(_("Error occurred while posting\n"));
+               g_free(msg);
+               return NN_SOCKET;
        }
+       g_free(msg);
 
-       sock_write(sock->sock, ".\r\n", 3);
+       sock_write_all(sock->sock, ".\r\n", 3);
        if ((ok = nntp_ok(sock, buf)) != NN_SUCCESS)
                return ok;
 
@@ -350,7 +344,7 @@ static void nntp_gen_send(NNTPSockInfo *sock, const gchar *format, ...)
        }
 
        strcat(buf, "\r\n");
-       sock_write(sock->sock, buf, strlen(buf));
+       sock_write_all(sock->sock, buf, strlen(buf));
 }
 
 static gint nntp_gen_recv(NNTPSockInfo *sock, gchar *buf, gint size)
index 1af1634..e314122 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "defs.h"
+
 #include <glib.h>
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+
 #include "session.h"
+#include "utils.h"
+
+static gint session_close              (Session        *session);
+
+static gchar *session_recv_msg         (Session        *session);
+
+static guchar *session_read_data       (Session        *session,
+                                        guint           size);
+
+static gint session_send_data_to_sock          (Session        *session,
+                                                const guchar   *data,
+                                                guint           size);
+static guchar *session_recv_data_from_sock     (Session        *session,
+                                                guint           size);
+
+gboolean session_parent_input_cb       (GIOChannel     *source,
+                                        GIOCondition    condition,
+                                        gpointer        data);
+
+gboolean session_child_input           (Session        *session);
+
+
+gint session_connect(Session *session, const gchar *server, gushort port)
+{
+       pid_t pid;
+       gint pipe_fds1[2], pipe_fds2[2];
+       SockInfo *sock;
+       gchar *str;
+
+       session->server = g_strdup(server);
+       session->port = port;
+
+       if (pipe(pipe_fds1) < 0) {
+               perror("pipe");
+               return -1;
+       }
+       if (pipe(pipe_fds2) < 0) {
+               perror("pipe");
+               close(pipe_fds1[0]);
+               close(pipe_fds1[1]);
+               return -1;
+       }
+
+       if ((pid = fork()) < 0) {
+               perror("fork");
+               return -1;
+       }
+
+       if (pid != 0) {
+               session->child_pid = pid;
+               session->read_ch = g_io_channel_unix_new(pipe_fds2[0]);
+               session->write_ch = g_io_channel_unix_new(pipe_fds1[1]);
+               close(pipe_fds1[0]);
+               close(pipe_fds2[1]);
+               session->read_tag = g_io_add_watch(session->read_ch, G_IO_IN,
+                                                  session_parent_input_cb,
+                                                  session);
+               return 0;
+       }
+
+       /* child process */
+
+       session->read_ch = g_io_channel_unix_new(pipe_fds1[0]);
+       session->write_ch = g_io_channel_unix_new(pipe_fds2[1]);
+       close(pipe_fds1[1]);
+       close(pipe_fds2[0]);
+
+       g_print("child: connecting to %s:%d ...\n", server, port);
+
+       if ((sock = sock_connect(server, port)) == NULL) {
+               session_send_msg(session, SESSION_MSG_ERROR,
+                                "can't connect to server.");
+               session_close(session);
+               _exit(1);
+       }
+
+#if USE_OPENSSL
+       if (session->ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
+               session_send_msg(session, SESSION_MSG_ERROR,
+                                "can't initialize SSL.");
+               session_close(session);
+               _exit(1);
+       }
+#endif
+
+       g_print("child: connected\n");
+
+       session->sock = sock;
+       session->state = SESSION_RECV;
+
+       if ((str = sock_getline(sock)) == NULL) {
+               session_send_msg(session, SESSION_MSG_ERROR,
+                                "can't get server response.");
+               session_close(session);
+               _exit(1);
+       }
+       strretchomp(str);
+       session_send_msg(session, SESSION_MSG_NORMAL, str);
+       g_free(str);
+
+       while (session_child_input(session) == TRUE)
+               ;
+
+       session_close(session);
+
+       g_print("child: disconnected\n");
+
+       _exit(0);
+}
+
+gint session_disconnect(Session *session)
+{
+       g_print("%s: session_disconnect()\n", session->child_pid == 0 ? "child" : "parent");
+       session_send_msg(session, SESSION_MSG_CONTROL, "DISCONNECT");
+       return 0;
+}
 
 void session_destroy(Session *session)
 {
        g_return_if_fail(session != NULL);
        g_return_if_fail(session->destroy != NULL);
 
+       g_print("session_destroy()\n");
+       session_close(session);
        session->destroy(session);
        g_free(session->server);
        g_free(session);
 }
+
+void session_set_recv_message_notify(Session *session,
+                                    RecvMsgNotify notify_func, gpointer data)
+{
+       session->recv_msg_notify = notify_func;
+       session->recv_msg_notify_data = data;
+}
+
+void session_set_recv_data_progressive_notify
+                                       (Session *session,
+                                        RecvDataProgressiveNotify notify_func,
+                                        gpointer data)
+{
+       session->recv_data_progressive_notify = notify_func,
+       session->recv_data_progressive_notify_data = data;
+}
+
+void session_set_recv_data_notify(Session *session, RecvDataNotify notify_func,
+                                 gpointer data)
+{
+       session->recv_data_notify = notify_func;
+       session->recv_data_notify_data = data;
+}
+
+void session_set_send_data_progressive_notify
+                                       (Session *session,
+                                        SendDataProgressiveNotify notify_func,
+                                        gpointer data)
+{
+       session->send_data_progressive_notify = notify_func;
+       session->send_data_progressive_notify_data = data;
+}
+
+void session_set_send_data_notify(Session *session, SendDataNotify notify_func,
+                                 gpointer data)
+{
+       session->send_data_notify = notify_func;
+       session->send_data_notify_data = data;
+}
+
+static gint session_close(Session *session)
+{
+       g_return_val_if_fail(session != NULL, -1);
+
+       g_print("%s: session_close()\n", session->child_pid == 0 ? "child" : "parent");
+
+       if (session->read_tag > 0) {
+               g_source_remove(session->read_tag);
+               session->read_tag = 0;
+       }
+
+       if (session->read_ch) {
+               g_io_channel_close(session->read_ch);
+               g_io_channel_unref(session->read_ch);
+               session->read_ch = NULL;
+       }
+       if (session->write_ch) {
+               g_io_channel_close(session->write_ch);
+               g_io_channel_unref(session->write_ch);
+               session->write_ch = NULL;
+       }
+
+       if (session->sock) {
+               sock_close(session->sock);
+               session->sock = NULL;
+               session->state = SESSION_DISCONNECTED;
+       }
+
+       if (session->child_pid) {
+               kill(session->child_pid, SIGTERM);
+               waitpid(session->child_pid, NULL, 0);
+               session->child_pid = 0;
+       }
+
+       return 0;
+}
+
+gint session_send_msg(Session *session, SessionMsgType type, const gchar *msg)
+{
+       gchar *prefix;
+       gchar *str;
+       guint size;
+       guint bytes_written;
+
+       switch (type) {
+       case SESSION_MSG_NORMAL:
+               prefix = "MESSAGE"; break;
+       case SESSION_MSG_SEND_DATA:
+               prefix = "SENDDATA"; break;
+       case SESSION_MSG_CONTROL:
+               prefix = "CONTROL"; break;
+       case SESSION_MSG_ERROR:
+               prefix = "ERROR"; break;
+       default:
+               return -1;
+       }
+
+       str = g_strdup_printf("%s %s\n", prefix, msg);
+       g_print("%s: sending message: %s", session->child_pid == 0 ? "child" : "parent", str);
+       size = strlen(str);
+
+       while (size > 0) {
+               if (g_io_channel_write(session->write_ch, str, size,
+                                      &bytes_written)
+                   != G_IO_ERROR_NONE || bytes_written == 0) {
+                       g_warning("%s: sending message failed.\n",
+                                 session->child_pid == 0 ? "child" : "parent");
+                       return -1;
+               }
+               size -= bytes_written;
+       }
+
+       return 0;
+}
+
+static gchar *session_recv_msg(Session *session)
+{
+       gchar buf[BUFFSIZE];
+       gchar *str = NULL;
+       guint size = 1;
+       guint bytes_read;
+
+       for (;;) {
+               if (g_io_channel_read(session->read_ch, buf, sizeof(buf) - 1,
+                                     &bytes_read)
+                   != G_IO_ERROR_NONE || bytes_read == 0) {
+                       g_warning("%s: receiving message failed.\n",
+                                 session->child_pid == 0 ? "child" : "parent");
+                       g_free(str);
+                       str = NULL;
+                       break;
+               }
+
+               size += bytes_read;
+               buf[bytes_read] = '\0';
+
+               if (!str)
+                       str = g_strdup(buf);
+               else {
+                       str = g_realloc(str, size);
+                       strcat(str, buf);
+               }
+               if (str[size - 2] == '\n') {
+                       str[size - 2] = '\0';
+
+                       g_print("%s: received message: %s\n", session->child_pid == 0 ? "child" : "parent", str);
+
+                       break;
+               }
+       }
+
+       return str;
+}
+
+#if USE_OPENSSL
+gint session_start_tls(Session *session)
+{
+       gchar *ctl_msg;
+
+       session_send_msg(session, SESSION_MSG_CONTROL, "STARTTLS");
+       ctl_msg = session_recv_msg(session);
+       if (!ctl_msg || strcmp(ctl_msg, "CONTROL STARTTLSOK") != 0) {
+               g_free(ctl_msg);
+               return -1;
+       }
+       g_free(ctl_msg);
+
+       return 0;
+}
+#endif
+
+gint session_send_data(Session *session, const guchar *data, guint size)
+{
+       gchar *msg;
+       guint bytes_written;
+       GIOError err;
+
+       session_send_msg(session, SESSION_MSG_SEND_DATA, itos(size));
+       if ((msg = session_recv_msg(session)) == NULL)
+               return -1;
+       g_free(msg);
+
+       while (size > 0) {
+               if ((err = g_io_channel_write(session->write_ch, (guchar *)data,
+                                             size, &bytes_written))
+                   != G_IO_ERROR_NONE || bytes_written == 0) {
+                       g_warning("%s: sending data failed: %d\n",
+                                 session->child_pid == 0 ? "child" : "parent",
+                                 err);
+                       return -1;
+               }
+               size -= bytes_written;
+               g_print("%s: sent %d bytes of data\n", session->child_pid == 0 ? "child" : "parent", bytes_written);
+       }
+
+       return 0;
+}
+
+static guchar *session_read_data(Session *session, guint size)
+{
+       guchar *data;
+       guchar *cur;
+       guint bytes_read;
+       GIOError err;
+
+       cur = data = g_malloc(size);
+
+       while (size > 0) {
+               if ((err = g_io_channel_read(session->read_ch, cur, size,
+                                            &bytes_read))
+                   != G_IO_ERROR_NONE || bytes_read == 0) {
+                       g_warning("%s: reading data failed: %d\n",
+                                 session->child_pid == 0 ? "child" : "parent",
+                                 err);
+                       g_free(data);
+                       return NULL;
+               }
+               size -= bytes_read;
+               cur += bytes_read;
+               g_print("%s: received %d bytes of data\n", session->child_pid == 0 ? "child" : "parent", bytes_read);
+       }
+
+       return data;
+}
+
+#define MAX_CHUNK_SIZE 4096
+
+static gint session_send_data_to_sock(Session *session, const guchar *data,
+                                     guint size)
+{
+       const guchar *cur = data;
+       gint bytes_written;
+       gint total_write_len = 0;
+       guint left = size;
+       gchar buf[BUFFSIZE];
+       gchar *msg;
+
+       while (left > 0) {
+               bytes_written = sock_write(session->sock, cur,
+                                          MIN(left, MAX_CHUNK_SIZE));
+               if (bytes_written <= 0)
+                       return -1;
+               left -= bytes_written;
+               cur += bytes_written;
+               total_write_len += bytes_written;
+               if (left > 0) {
+                       g_snprintf(buf, sizeof(buf), "DATASENDINPROG %d %d",
+                                  total_write_len, size);
+                       session_send_msg(session, SESSION_MSG_CONTROL, buf);
+                       if ((msg = session_recv_msg(session)) == NULL)
+                               return -1;
+                       g_free(msg);
+               }
+       }
+
+       return 0;
+}
+
+static guchar *session_recv_data_from_sock(Session *session, guint size)
+{
+       guchar *data;
+       guchar *cur;
+       gint bytes_read;
+       gint total_read_len = 0;
+       guint left = size;
+       gchar buf[BUFFSIZE];
+       gchar *msg;
+
+       cur = data = g_malloc(size);
+
+       while (left > 0) {
+               bytes_read = sock_read(session->sock, cur, left);
+               if (bytes_read <= 0) {
+                       g_free(data);
+                       return NULL;
+               }
+               g_print("child: received %d bytes of data from sock\n", bytes_read);
+               left -= bytes_read;
+               cur += bytes_read;
+               total_read_len += bytes_read;
+               g_snprintf(buf, sizeof(buf), "DATARECVINPROG %d %d",
+                          total_read_len, size);
+               session_send_msg(session, SESSION_MSG_CONTROL, buf);
+               if ((msg = session_recv_msg(session)) == NULL) {
+                       g_free(data);
+                       return NULL;
+               }
+               g_free(msg);
+       }
+
+       return data;
+}
+
+static SessionMsgType session_get_msg_type(const gchar *str)
+{
+       if (!strncmp(str, "MESSAGE ", 8))
+               return SESSION_MSG_NORMAL;
+       else if (!strncmp(str, "SENDDATA ", 9))
+               return SESSION_MSG_SEND_DATA;
+       else if (!strncmp(str, "RECVDATA ", 9))
+               return SESSION_MSG_RECV_DATA;
+       else if (!strncmp(str, "CONTROL ", 8))
+               return SESSION_MSG_CONTROL;
+       else if (!strncmp(str, "ERROR ", 6))
+               return SESSION_MSG_ERROR;
+       else
+               return SESSION_MSG_UNKNOWN;
+}
+
+gboolean session_parent_input_cb(GIOChannel *source, GIOCondition condition,
+                                gpointer data)
+{
+       Session *session = SESSION(data);
+       gchar *msg;
+       gchar *msg_data;
+       gint len;
+       gint total;
+       guchar *recv_data;
+       guint size;
+       gint ret;
+
+       if ((msg = session_recv_msg(session)) == NULL) {
+               session->state = SESSION_ERROR;
+               return FALSE;
+       }
+
+       switch (session_get_msg_type(msg)) {
+       case SESSION_MSG_NORMAL:
+               msg_data = msg + strlen("MESSAGE ");
+               ret = session->recv_msg(session, msg_data);
+               if (ret <= 0)
+                       session->recv_msg_notify(session, msg_data,
+                                                session->recv_msg_notify_data);
+               else
+                       session_send_msg(session, SESSION_MSG_CONTROL,
+                                        "CONTINUE");
+               if (ret < 0) {
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               break;
+       case SESSION_MSG_SEND_DATA:
+               msg_data = msg + strlen("SENDDATA ");
+               size = atoi(msg_data);
+               session_send_msg(session, SESSION_MSG_CONTROL, "ACCEPTDATA");
+               recv_data = session_read_data(session, size);
+               if (!recv_data) {
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               session->recv_data_finished(session, recv_data, size);
+               g_free(recv_data);
+               break;
+       case SESSION_MSG_RECV_DATA:
+               break;
+       case SESSION_MSG_CONTROL:
+               msg_data = msg + strlen("CONTROL ");
+               if (!strncmp(msg_data, "DATARECVINPROG ", 15)) {
+                       ret = sscanf(msg_data,
+                                    "DATARECVINPROG %d %d", &len, &total);
+                       if (ret != 2) {
+                               g_warning("wrong control message: %s\n", msg);
+                               session->state = SESSION_ERROR;
+                               g_free(msg);
+                               return FALSE;
+                       }
+                       session_send_msg(session, SESSION_MSG_CONTROL,
+                                        "CONTINUE");
+                       session->recv_data_progressive_notify
+                               (session, len, total,
+                                session->recv_data_progressive_notify_data);
+               } else if (!strncmp(msg_data, "DATASENDINPROG ", 15)) {
+                       ret = sscanf(msg_data,
+                                    "DATASENDINPROG %d %d", &len, &total);
+                       if (ret != 2) {
+                               g_warning("wrong control message: %s\n", msg);
+                               session->state = SESSION_ERROR;
+                               g_free(msg);
+                               return FALSE;
+                       }
+                       session_send_msg(session, SESSION_MSG_CONTROL,
+                                        "CONTINUE");
+                       session->send_data_progressive_notify
+                               (session, len, total,
+                                session->send_data_progressive_notify_data);
+               } else if (!strncmp(msg_data, "DATASENT ", 9)) {
+                       len = atoi(msg_data + 9);
+                       ret = session->send_data_finished(session, len);
+                       session->send_data_notify
+                               (session, len, session->send_data_notify_data);
+               } else if (!strcmp(msg_data, "DISCONNECTED")) {
+                       session->state = SESSION_DISCONNECTED;
+                       g_free(msg);
+                       return FALSE;
+               } else {
+                       g_warning("wrong control message: %s\n", msg);
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               break;
+       case SESSION_MSG_ERROR:
+       default:
+               g_warning("error from child: %s\n", msg + strlen("ERROR "));
+               session->state = SESSION_ERROR;
+               g_free(msg);
+               return FALSE;
+       }
+
+       g_free(msg);
+       return TRUE;
+}
+
+gboolean session_child_input(Session *session)
+{
+       gchar buf[BUFFSIZE];
+       gchar *msg;
+       gchar *msg_data;
+       gchar *str;
+       guchar *send_data;
+       guchar *recv_data;
+       guint size;
+
+       if ((msg = session_recv_msg(session)) == NULL) {
+               session_send_msg(session, SESSION_MSG_ERROR,
+                                "receiving message failed.");
+               session_close(session);
+               session->state = SESSION_ERROR;
+               return FALSE;
+       }
+
+       switch (session_get_msg_type(msg)) {
+       case SESSION_MSG_NORMAL:
+               msg_data = msg + strlen("MESSAGE ");
+               session->state = SESSION_SEND;
+               sock_puts(session->sock, msg_data);
+               session->state = SESSION_RECV;
+               str = sock_getline(session->sock);
+               if (!str) {
+                       session_send_msg(session, SESSION_MSG_ERROR,
+                                        "receiving message failed.");
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               strretchomp(str);
+               session_send_msg(session, SESSION_MSG_NORMAL, str);
+               g_free(str);
+               break;
+       case SESSION_MSG_SEND_DATA:
+               msg_data = msg + strlen("SENDDATA ");
+               size = atoi(msg_data);
+               session_send_msg(session, SESSION_MSG_CONTROL, "ACCEPTDATA");
+               send_data = session_read_data(session, size);
+               if (!send_data) {
+                       session_send_msg(session, SESSION_MSG_ERROR,
+                                        "sending data failed.");
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               session->state = SESSION_SEND;
+               if (session_send_data_to_sock(session, send_data, size) < 0) {
+                       session_send_msg(session, SESSION_MSG_ERROR,
+                                        "sending data failed.");
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(send_data);
+                       g_free(msg);
+                       return FALSE;
+               }
+               g_free(send_data);
+               g_snprintf(buf, sizeof(buf), "DATASENT %d", size);
+               session_send_msg(session, SESSION_MSG_CONTROL, buf);
+               break;
+       case SESSION_MSG_RECV_DATA:
+               msg_data = msg + strlen("RECVDATA ");
+               size = atoi(msg_data);
+               session->state = SESSION_RECV;
+               recv_data = session_recv_data_from_sock(session, size);
+               if (!recv_data) {
+                       session_send_msg(session, SESSION_MSG_ERROR,
+                                        "receiving data failed.");
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               if (session_send_data(session, recv_data, size) < 0) {
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(recv_data);
+                       g_free(msg);
+                       return FALSE;
+               }
+               g_free(recv_data);
+               break;
+       case SESSION_MSG_CONTROL:
+               msg_data = msg + strlen("CONTROL ");
+               if (!strcmp(msg_data, "CONTINUE")) {
+                       session->state = SESSION_RECV;
+                       str = sock_getline(session->sock);
+                       if (!str) {
+                               session_send_msg(session, SESSION_MSG_ERROR,
+                                                "receiving message failed.");
+                               session_close(session);
+                               session->state = SESSION_ERROR;
+                               g_free(msg);
+                               return FALSE;
+                       }
+                       strretchomp(str);
+                       session_send_msg(session, SESSION_MSG_NORMAL, str);
+                       g_free(str);
+                       break;
+#if USE_OPENSSL
+               } else if (!strcmp(msg_data, "STARTTLS")) {
+                       if (!ssl_init_socket_with_method(session->sock,
+                                                        SSL_METHOD_TLSv1)) {
+                               session_send_msg(session, SESSION_MSG_ERROR,
+                                                "can't start TLS session.");
+                               session_close(session);
+                               session->state = SESSION_ERROR;
+                               g_free(msg);
+                               return FALSE;
+                       }
+                       session_send_msg(session, SESSION_MSG_CONTROL,
+                                        "STARTTLSOK");
+                       break;
+#endif
+               } else if (!strcmp(msg_data, "DISCONNECT")) {
+                       sock_close(session->sock);
+                       session->sock = NULL;
+                       session->state = SESSION_DISCONNECTED;
+                       session_send_msg(session, SESSION_MSG_CONTROL,
+                                        "DISCONNECTED");
+                       g_free(msg);
+                       return FALSE;
+               } else {
+                       session_send_msg(session, SESSION_MSG_ERROR,
+                                        "wrong control message.");
+                       session_close(session);
+                       session->state = SESSION_ERROR;
+                       g_free(msg);
+                       return FALSE;
+               }
+               break;
+       case SESSION_MSG_ERROR:
+       default:
+               session_send_msg(session, SESSION_MSG_ERROR,
+                                "error received from parent.");
+               session_close(session);
+               session->state = SESSION_ERROR;
+               g_free(msg);
+               return FALSE;
+       }
+
+       g_free(msg);
+       return TRUE;
+}
index b57c57d..0f58f2b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #ifndef __SESSION_H__
 #define __SESSION_H__
 
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include <glib.h>
+
 #include <time.h>
+#include <unistd.h>
 
 #include "socket.h"
 
@@ -32,37 +38,132 @@ typedef struct _Session    Session;
 typedef enum {
        SESSION_IMAP,
        SESSION_NEWS,
-       SESSION_SMTP
+       SESSION_SMTP,
+       SESSION_POP3
 } SessionType;
 
 typedef enum {
        SESSION_READY,
        SESSION_SEND,
-       SESSION_RECV
-} SessionPhase;
+       SESSION_RECV,
+       SESSION_ERROR,
+       SESSION_DISCONNECTED
+} SessionState;
 
-typedef void (*SessionUIFunc)  (gpointer        data,
-                                gint            state);
+typedef enum
+{
+       SESSION_MSG_NORMAL,
+       SESSION_MSG_SEND_DATA,
+       SESSION_MSG_RECV_DATA,
+       SESSION_MSG_CONTROL,
+       SESSION_MSG_ERROR,
+       SESSION_MSG_UNKNOWN
+} SessionMsgType;
+
+typedef gint (*RecvMsgNotify)                  (Session        *session,
+                                                const gchar    *msg,
+                                                gpointer        user_data);
+typedef gint (*RecvDataProgressiveNotify)      (Session        *session,
+                                                guint           cur_len,
+                                                guint           total_len,
+                                                gpointer        user_data);
+typedef gint (*RecvDataNotify)                 (Session        *session,
+                                                guint           len,
+                                                gpointer        user_data);
+typedef gint (*SendDataProgressiveNotify)      (Session        *session,
+                                                guint           cur_len,
+                                                guint           total_len,
+                                                gpointer        user_data);
+typedef gint (*SendDataNotify)                 (Session        *session,
+                                                guint           len,
+                                                gpointer        user_data);
 
 struct _Session
 {
        SessionType type;
 
        SockInfo *sock;
+
        gchar *server;
+       gushort port;
+
+#if USE_OPENSSL
+       SSLType ssl_type;
+#endif
 
-       gboolean connected;
-       SessionPhase phase;
+       SessionState state;
 
        time_t last_access_time;
 
-       gpointer data;
+       pid_t child_pid;
+
+       /* pipe I/O */
+       GIOChannel *read_ch;
+       GIOChannel *write_ch;
 
-       void (*destroy)         (Session        *session);
+       gint read_tag;
 
-       SessionUIFunc ui_func;
+       gpointer data;
+
+       /* virtual methods to parse server responses */
+       gint (*recv_msg)                (Session        *session,
+                                        const gchar    *msg);
+
+       gint (*recv_data_finished)      (Session        *session,
+                                        guchar         *data,
+                                        guint           len);
+       gint (*send_data_finished)      (Session        *session,
+                                        guint           len);
+
+       void (*destroy)                 (Session        *session);
+
+       /* notification functions */
+       RecvMsgNotify                   recv_msg_notify;
+       RecvDataProgressiveNotify       recv_data_progressive_notify;
+       RecvDataNotify                  recv_data_notify;
+       SendDataProgressiveNotify       send_data_progressive_notify;
+       SendDataNotify                  send_data_notify;
+
+       gpointer recv_msg_notify_data;
+       gpointer recv_data_progressive_notify_data;
+       gpointer recv_data_notify_data;
+       gpointer send_data_progressive_notify_data;
+       gpointer send_data_notify_data;
 };
 
+gint session_connect   (Session        *session,
+                        const gchar    *server,
+                        gushort         port);
+gint session_disconnect        (Session        *session);
 void session_destroy   (Session        *session);
 
+void session_set_recv_message_notify   (Session        *session,
+                                        RecvMsgNotify   notify_func,
+                                        gpointer        data);
+void session_set_recv_data_progressive_notify
+                                       (Session        *session,
+                                        RecvDataProgressiveNotify notify_func,
+                                        gpointer        data);
+void session_set_recv_data_notify      (Session        *session,
+                                        RecvDataNotify  notify_func,
+                                        gpointer        data);
+void session_set_send_data_progressive_notify
+                                       (Session        *session,
+                                        SendDataProgressiveNotify notify_func,
+                                        gpointer        data);
+void session_set_send_data_notify      (Session        *session,
+                                        SendDataNotify  notify_func,
+                                        gpointer        data);
+
+gint session_send_msg  (Session        *session,
+                        SessionMsgType  type,
+                        const gchar    *msg);
+gint session_send_data (Session        *session,
+                        const guchar   *data,
+                        guint           size);
+
+#if USE_OPENSSL
+gint session_start_tls (Session        *session);
+#endif
+
 #endif /* __SESSION_H__ */
index 6179443..af730c3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "intl.h"
 #include "smtp.h"
-#include "socket.h"
 #include "md5.h"
 #include "base64.h"
 #include "utils.h"
 #include "log.h"
 
-static gint verbose = 1;
+static void smtp_session_destroy(Session *session);
 
-#define UI_UPDATE(session, phase) \
-{ \
-       if (SESSION(session)->ui_func) \
-               SESSION(session)->ui_func(SESSION(session), phase); \
-}
+static gint smtp_from(SMTPSession *session);
 
+static gint smtp_auth(SMTPSession *session);
 static gint smtp_starttls(SMTPSession *session);
-static gint smtp_auth_cram_md5(SMTPSession *session, gchar *buf, gint len);
-static gint smtp_auth_login(SMTPSession *session, gchar *buf, gint len);
+static gint smtp_auth_cram_md5(SMTPSession *session);
+static gint smtp_auth_login(SMTPSession *session);
+
+static gint smtp_ehlo(SMTPSession *session);
+static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg);
+
+static gint smtp_helo(SMTPSession *session);
+static gint smtp_rcpt(SMTPSession *session);
+static gint smtp_data(SMTPSession *session);
+static gint smtp_send_data(SMTPSession *session);
+static gint smtp_rset(SMTPSession *session);
+static gint smtp_quit(SMTPSession *session);
+static gint smtp_eom(SMTPSession *session);
+
+static gint smtp_session_recv_msg(Session *session, const gchar *msg);
+static gint smtp_session_send_data_finished(Session *session, guint len);
 
-static gint smtp_ok(SockInfo *sock, gchar *buf, gint len);
 
 Session *smtp_session_new(void)
 {
@@ -54,207 +63,131 @@ Session *smtp_session_new(void)
        session = g_new0(SMTPSession, 1);
        SESSION(session)->type             = SESSION_SMTP;
        SESSION(session)->server           = NULL;
+       SESSION(session)->port             = 0;
        SESSION(session)->sock             = NULL;
-       SESSION(session)->connected        = FALSE;
-       SESSION(session)->phase            = SESSION_READY;
-       SESSION(session)->last_access_time = 0;
+       SESSION(session)->state            = SESSION_READY;
        SESSION(session)->data             = NULL;
 
-       SESSION(session)->destroy          = smtp_session_destroy;
-       SESSION(session)->ui_func          = NULL;
-
-       session->avail_auth_type           = 0;
-       session->user                      = NULL;
-       session->pass                      = NULL;
-
-       return SESSION(session);
-}
-
-void smtp_session_destroy(Session *session)
-{
-       sock_close(session->sock);
-       session->sock = NULL;
+       SESSION(session)->recv_msg         = smtp_session_recv_msg;
 
-       g_free(SMTP_SESSION(session)->user);
-       g_free(SMTP_SESSION(session)->pass);
-}
+       SESSION(session)->recv_data_finished = NULL;
+       SESSION(session)->send_data_finished = smtp_session_send_data_finished;
 
-#if USE_OPENSSL
-gint smtp_connect(SMTPSession *session, const gchar *server, gushort port,
-                 const gchar *domain, const gchar *user, const gchar *pass,
-                 SSLType ssl_type)
-#else
-gint smtp_connect(SMTPSession *session, const gchar *server, gushort port,
-                 const gchar *domain, const gchar *user, const gchar *pass)
-#endif
-{
-       SockInfo *sock;
-       gboolean use_esmtp;
-       SMTPAuthType avail_auth_type = 0;
-       gint val;
+       SESSION(session)->destroy          = smtp_session_destroy;
 
-       g_return_val_if_fail(session != NULL, SM_ERROR);
-       g_return_val_if_fail(server != NULL, SM_ERROR);
+       session->state                     = SMTP_READY;
 
 #if USE_OPENSSL
-       use_esmtp = user != NULL || ssl_type == SSL_STARTTLS;
-#else
-       use_esmtp = user != NULL;
+       session->tls_init_done             = FALSE;
 #endif
 
-       SESSION(session)->server = g_strdup(server);
-       session->user = user ? g_strdup(user) : NULL;
-       session->pass = pass ? g_strdup(pass) : user ? g_strdup("") : NULL;
-
-       UI_UPDATE(session, SMTP_CONNECT);
+       session->hostname                  = NULL;
+       session->user                      = NULL;
+       session->pass                      = NULL;
 
-       if ((sock = sock_connect(server, port)) == NULL) {
-               log_warning(_("Can't connect to SMTP server: %s:%d\n"),
-                           server, port);
-               return SM_ERROR;
-       }
+       session->from                      = NULL;
+       session->to_list                   = NULL;
+       session->cur_to                    = NULL;
 
-#if USE_OPENSSL
-       if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) {
-               log_warning(_("SSL connection failed"));
-               sock_close(sock);
-               return SM_ERROR;
-       }
-#endif
+       session->send_data                 = NULL;
+       session->send_data_len             = 0;
 
-       if (smtp_ok(sock, NULL, 0) != SM_OK) {
-               log_warning(_("Error occurred while connecting to %s:%d\n"),
-                           server, port);
-               sock_close(sock);
-               return SM_ERROR;
-       }
-
-       SESSION(session)->sock = sock;
-       SESSION(session)->connected = TRUE;
-
-       if (!domain)
-               domain = get_domain_name();
+       session->avail_auth_type           = 0;
+       session->forced_auth_type          = 0;
+       session->auth_type                 = 0;
 
-       if (use_esmtp)
-               val = smtp_ehlo(session, domain, &avail_auth_type);
-       else
-               val = smtp_helo(session, domain);
-       if (val != SM_OK) {
-               log_warning(use_esmtp?  _("Error occurred while sending EHLO\n"):
-                                       _("Error occurred while sending HELO\n"));
-               return val;
-       }
+       return SESSION(session);
+}
 
-#if USE_OPENSSL
-       /* if we have a user to authenticate and no auth methods, but starttls,
-          try to starttls */
-       if (ssl_type == SSL_NONE && avail_auth_type == SMTPAUTH_TLS_AVAILABLE 
-           && user != NULL)
-               ssl_type = SSL_STARTTLS;
-
-       if (ssl_type == SSL_STARTTLS) {
-               val = smtp_starttls(session);
-               if (val != SM_OK) {
-                       log_warning(_("Error occurred while sending STARTTLS\n"));
-                       return val;
-               }
-               if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1)) {
-                       return SM_ERROR;
-               }
-               val = smtp_ehlo(session, domain, &avail_auth_type);
-               if (val != SM_OK) {
-                       log_warning(_("Error occurred while sending EHLO\n"));
-                       return val;
-               }
-       }
-#endif
+static void smtp_session_destroy(Session *session)
+{
+       SMTPSession *smtp_session = SMTP_SESSION(session);
 
-       session->avail_auth_type = avail_auth_type;
+       g_free(smtp_session->hostname);
+       g_free(smtp_session->user);
+       g_free(smtp_session->pass);
+       g_free(smtp_session->from);
 
-       return 0;
+       g_free(smtp_session->send_data);
 }
 
-gint smtp_from(SMTPSession *session, const gchar *from)
+static gint smtp_from(SMTPSession *session)
 {
        gchar buf[MSGBUFSIZE];
 
-       g_return_val_if_fail(session != NULL, SM_ERROR);
-       g_return_val_if_fail(from != NULL, SM_ERROR);
+       g_return_val_if_fail(session->from != NULL, SM_ERROR);
 
-       UI_UPDATE(session, SMTP_FROM);
+       session->state = SMTP_FROM;
 
-       if (strchr(from, '<'))
-               g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", from);
+       if (strchr(session->from, '<'))
+               g_snprintf(buf, sizeof(buf), "MAIL FROM: %s", session->from);
        else
-               g_snprintf(buf, sizeof(buf), "MAIL FROM: <%s>", from);
+               g_snprintf(buf, sizeof(buf), "MAIL FROM: <%s>", session->from);
 
-       sock_printf(SESSION(session)->sock, "%s\r\n", buf);
-       if (verbose)
-               log_print("SMTP> %s\n", buf);
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
+       log_print("SMTP> %s\n", buf);
 
-       return smtp_ok(SESSION(session)->sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
+static gint smtp_auth(SMTPSession *session)
 {
-       gchar buf[MSGBUFSIZE];
-       SMTPAuthType authtype = 0;
-       guchar hexdigest[33];
-       gchar *challenge, *response, *response64;
-       gint challengelen;
-       SockInfo *sock;
 
-       g_return_val_if_fail(session != NULL, SM_ERROR);
        g_return_val_if_fail(session->user != NULL, SM_ERROR);
 
-       UI_UPDATE(session, SMTP_AUTH);
+       session->state = SMTP_AUTH;
 
-       sock = SESSION(session)->sock;
-
-       if ((forced_auth_type == SMTPAUTH_CRAM_MD5 ||
-            (forced_auth_type == 0 &&
-             (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) &&
-           smtp_auth_cram_md5(session, buf, sizeof(buf)) == SM_OK)
-               authtype = SMTPAUTH_CRAM_MD5;
-       else if ((forced_auth_type == SMTPAUTH_LOGIN ||
-                 (forced_auth_type == 0 &&
-                  (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) &&
-                smtp_auth_login(session, buf, sizeof(buf)) == SM_OK)
-               authtype = SMTPAUTH_LOGIN;
+       if (session->forced_auth_type == SMTPAUTH_CRAM_MD5 ||
+           (session->forced_auth_type == 0 &&
+            (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0))
+               smtp_auth_cram_md5(session);
+       else if (session->forced_auth_type == SMTPAUTH_LOGIN ||
+                (session->forced_auth_type == 0 &&
+                 (session->avail_auth_type & SMTPAUTH_LOGIN) != 0))
+               smtp_auth_login(session);
        else {
                log_warning(_("SMTP AUTH not available\n"));
                return SM_AUTHFAIL;
        }
 
-       switch (authtype) {
-       case SMTPAUTH_LOGIN:
-               if (!strncmp(buf, "334 ", 4))
-                       base64_encode(buf, session->user, strlen(session->user));
-               else
-                       /* Server rejects AUTH */
-                       g_snprintf(buf, sizeof(buf), "*");
+       return SM_OK;
+}
 
-               sock_printf(sock, "%s\r\n", buf);
-               if (verbose) log_print("ESMTP> [USERID]\n");
+static gint smtp_auth_recv(SMTPSession *session, const gchar *msg)
+{
+       gchar buf[MSGBUFSIZE];
 
-               smtp_ok(sock, buf, sizeof(buf));
+       switch (session->auth_type) {
+       case SMTPAUTH_LOGIN:
+               session->state = SMTP_AUTH_LOGIN_USER;
 
-               if (!strncmp(buf, "334 ", 4))
-                       base64_encode(buf, session->pass, strlen(session->pass));
-               else
-                       /* Server rejects AUTH */
-                       g_snprintf(buf, sizeof(buf), "*");
+               if (!strncmp(msg, "334 ", 4)) {
+                       base64_encode(buf, session->user, strlen(session->user));
 
-               sock_printf(sock, "%s\r\n", buf);
-               if (verbose) log_print("ESMTP> [PASSWORD]\n");
+                       session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+                                        buf);
+                       log_print("ESMTP> [USERID]\n");
+               } else {
+                       /* Server rejects AUTH */
+                       session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+                                        "*");
+                       log_print("ESMTP> *\n");
+               }
                break;
        case SMTPAUTH_CRAM_MD5:
+               session->state = SMTP_AUTH_CRAM_MD5;
+
                if (!strncmp(buf, "334 ", 4)) {
+                       gchar *response;
+                       gchar *response64;
+                       gchar *challenge;
+                       gint challengelen;
+                       guchar hexdigest[33];
+
                        challenge = g_malloc(strlen(buf + 4) + 1);
                        challengelen = base64_decode(challenge, buf + 4, -1);
                        challenge[challengelen] = '\0';
-                       if (verbose)
-                               log_print("ESMTP< [Decoded: %s]\n", challenge);
+                       log_print("ESMTP< [Decoded: %s]\n", challenge);
 
                        g_snprintf(buf, sizeof(buf), "%s", session->pass);
                        md5_hex_hmac(hexdigest, challenge, challengelen,
@@ -263,255 +196,323 @@ gint smtp_auth(SMTPSession *session, SMTPAuthType forced_auth_type)
 
                        response = g_strdup_printf
                                ("%s %s", session->user, hexdigest);
-                       if (verbose)
-                               log_print("ESMTP> [Encoded: %s]\n", response);
+                       log_print("ESMTP> [Encoded: %s]\n", response);
 
                        response64 = g_malloc((strlen(response) + 3) * 2 + 1);
                        base64_encode(response64, response, strlen(response));
                        g_free(response);
 
-                       sock_printf(sock, "%s\r\n", response64);
-                       if (verbose) log_print("ESMTP> %s\n", response64);
+                       session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+                                        response64);
+                       log_print("ESMTP> %s\n", response64);
                        g_free(response64);
                } else {
                        /* Server rejects AUTH */
-                       g_snprintf(buf, sizeof(buf), "*");
-                       sock_printf(sock, "%s\r\n", buf);
-                       if (verbose)
-                               log_print("ESMTP> %s\n", buf);
+                       session_send_msg(SESSION(session), SESSION_MSG_NORMAL,
+                                        "*");
+                       log_print("ESMTP> *\n");
                }
                break;
        case SMTPAUTH_DIGEST_MD5:
         default:
                /* stop smtp_auth when no correct authtype */
-               g_snprintf(buf, sizeof(buf), "*");
-               sock_printf(sock, "%s\r\n", buf);
-               if (verbose) log_print("ESMTP> %s\n", buf);
+               session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*");
+               log_print("ESMTP> *\n");
                break;
        }
 
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_ehlo(SMTPSession *session, const gchar *hostname,
-              SMTPAuthType *avail_auth_type)
+static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg)
 {
-       SockInfo *sock;
        gchar buf[MSGBUFSIZE];
 
-       UI_UPDATE(session, SMTP_EHLO);
-
-       sock = SESSION(session)->sock;
-
-       *avail_auth_type = 0;
-
-       sock_printf(sock, "EHLO %s\r\n", hostname);
-       if (verbose)
-               log_print("ESMTP> EHLO %s\n", hostname);
-
-       while ((sock_gets(sock, buf, sizeof(buf) - 1)) != -1) {
-               if (strlen(buf) < 4)
-                       return SM_ERROR;
-               strretchomp(buf);
-
-               if (verbose)
-                       log_print("ESMTP< %s\n", buf);
-
-               if (strncmp(buf, "250-", 4) == 0) {
-                       gchar *p = buf;
-                       p += 4;
-                       if (g_strncasecmp(p, "AUTH", 4) == 0) {
-                               p += 5;
-                               if (strcasestr(p, "LOGIN"))
-                                       *avail_auth_type |= SMTPAUTH_LOGIN;
-                               if (strcasestr(p, "CRAM-MD5"))
-                                       *avail_auth_type |= SMTPAUTH_CRAM_MD5;
-                               if (strcasestr(p, "DIGEST-MD5"))
-                                       *avail_auth_type |= SMTPAUTH_DIGEST_MD5;
-                       } else if (g_strncasecmp(p, "STARTTLS", 8) == 0) {
-                               p += 9;
-                               *avail_auth_type |= SMTPAUTH_TLS_AVAILABLE;
-                       }
-               } else if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
-                   (buf[3] == ' ' || buf[3] == '\0'))
-                       return SM_OK;
-               else if (buf[3] != '-')
-                       return SM_ERROR;
-               else if (buf[0] == '5' && buf[1] == '0' &&
-                        (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
-                       return SM_ERROR;
-       }
+       session->state = SMTP_AUTH_LOGIN_PASS;
+
+       if (!strncmp(msg, "334 ", 4))
+               base64_encode(buf, session->pass, strlen(session->pass));
+       else
+               /* Server rejects AUTH */
+               g_snprintf(buf, sizeof(buf), "*");
+
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
+       log_print("ESMTP> [PASSWORD]\n");
 
-       return SM_UNRECOVERABLE;
+       return SM_OK;
 }
 
-static gint smtp_starttls(SMTPSession *session)
+static gint smtp_ehlo(SMTPSession *session)
 {
-       SockInfo *sock;
+       gchar buf[MSGBUFSIZE];
 
-       UI_UPDATE(session, SMTP_STARTTLS);
+       session->state = SMTP_EHLO;
 
-       sock = SESSION(session)->sock;
+       session->avail_auth_type = 0;
 
-       sock_printf(sock, "STARTTLS\r\n");
-       if (verbose)
-               log_print("ESMTP> STARTTLS\n");
+       g_snprintf(buf, sizeof(buf), "EHLO %s",
+                  session->hostname ? session->hostname : get_domain_name());
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
+       log_print("ESMTP> %s\n", buf);
 
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-static gint smtp_auth_cram_md5(SMTPSession *session, gchar *buf, gint len)
+static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg)
 {
-       SockInfo *sock;
+       if (strncmp(msg, "250", 3) == 0) {
+               const gchar *p = msg;
+               p += 3;
+               if (*p == '-' || *p == ' ') p++;
+               if (g_strncasecmp(p, "AUTH", 4) == 0) {
+                       p += 5;
+                       if (strcasestr(p, "LOGIN"))
+                               session->avail_auth_type |= SMTPAUTH_LOGIN;
+                       if (strcasestr(p, "CRAM-MD5"))
+                               session->avail_auth_type |= SMTPAUTH_CRAM_MD5;
+                       if (strcasestr(p, "DIGEST-MD5"))
+                               session->avail_auth_type |= SMTPAUTH_DIGEST_MD5;
+               }
+               return SM_OK;
+       } else if ((msg[0] == '1' || msg[0] == '2' || msg[0] == '3') &&
+           (msg[3] == ' ' || msg[3] == '\0'))
+               return SM_OK;
+       else if (msg[0] == '5' && msg[1] == '0' &&
+                (msg[2] == '4' || msg[2] == '3' || msg[2] == '1'))
+               return SM_ERROR;
 
-       UI_UPDATE(session, SMTP_AUTH);
+       return SM_ERROR;
+}
 
-       sock = SESSION(session)->sock;
+static gint smtp_starttls(SMTPSession *session)
+{
+       session->state = SMTP_STARTTLS;
 
-       sock_printf(sock, "AUTH CRAM-MD5\r\n");
-       if (verbose)
-               log_print("ESMTP> AUTH CRAM-MD5\n");
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "STARTTLS");
+       log_print("ESMTP> STARTTLS\n");
 
-       return smtp_ok(sock, buf, len);
+       return SM_OK;
 }
 
-static gint smtp_auth_login(SMTPSession *session, gchar *buf, gint len)
+static gint smtp_auth_cram_md5(SMTPSession *session)
 {
-       SockInfo *sock;
+       session->state = SMTP_AUTH;
+       session->auth_type = SMTPAUTH_CRAM_MD5;
 
-       UI_UPDATE(session, SMTP_AUTH);
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH CRAM-MD5");
+       log_print("ESMTP> AUTH CRAM-MD5\n");
 
-       sock = SESSION(session)->sock;
+       return SM_OK;
+}
 
-       sock_printf(sock, "AUTH LOGIN\r\n");
-       if (verbose)
-               log_print("ESMTP> AUTH LOGIN\n");
+static gint smtp_auth_login(SMTPSession *session)
+{
+       session->state = SMTP_AUTH;
+       session->auth_type = SMTPAUTH_LOGIN;
+
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH LOGIN");
+       log_print("ESMTP> AUTH LOGIN\n");
 
-       return smtp_ok(sock, buf, len);
+       return SM_OK;
 }
 
-gint smtp_helo(SMTPSession *session, const gchar *hostname)
+static gint smtp_helo(SMTPSession *session)
 {
-       SockInfo *sock;
-
-       UI_UPDATE(session, SMTP_HELO);
+       gchar buf[MSGBUFSIZE];
 
-       sock = SESSION(session)->sock;
+       session->state = SMTP_HELO;
 
-       sock_printf(sock, "HELO %s\r\n", hostname);
-       if (verbose)
-               log_print("SMTP> HELO %s\n", hostname);
+       g_snprintf(buf, sizeof(buf), "HELO %s",
+                  session->hostname ? session->hostname : get_domain_name());
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
+       log_print("SMTP> %s\n", buf);
 
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_rcpt(SMTPSession *session, const gchar *to)
+static gint smtp_rcpt(SMTPSession *session)
 {
-       SockInfo *sock;
        gchar buf[MSGBUFSIZE];
+       gchar *to;
 
-       UI_UPDATE(session, SMTP_RCPT);
+       g_return_val_if_fail(session->cur_to != NULL, SM_ERROR);
 
-       sock = SESSION(session)->sock;
+       session->state = SMTP_RCPT;
+
+       to = (gchar *)session->cur_to->data;
 
        if (strchr(to, '<'))
                g_snprintf(buf, sizeof(buf), "RCPT TO: %s", to);
        else
                g_snprintf(buf, sizeof(buf), "RCPT TO: <%s>", to);
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf);
+       log_print("SMTP> %s\n", buf);
 
-       sock_printf(sock, "%s\r\n", buf);
-       if (verbose)
-               log_print("SMTP> %s\n", buf);
+       session->cur_to = session->cur_to->next;
 
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_data(SMTPSession *session)
+static gint smtp_data(SMTPSession *session)
 {
-       SockInfo *sock;
-
-       UI_UPDATE(session, SMTP_DATA);
+       session->state = SMTP_DATA;
 
-       sock = SESSION(session)->sock;
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "DATA");
+       log_print("SMTP> DATA\n");
 
-       sock_printf(sock, "DATA\r\n");
-       if (verbose)
-               log_print("SMTP> DATA\n");
-
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_rset(SMTPSession *session)
+static gint smtp_send_data(SMTPSession *session)
 {
-       SockInfo *sock;
+       session->state = SMTP_SEND_DATA;
 
-       UI_UPDATE(session, SMTP_RSET);
+       session_send_data(SESSION(session), session->send_data,
+                         session->send_data_len);
 
-       sock = SESSION(session)->sock;
+       return SM_OK;
+}
 
-       sock_printf(sock, "RSET\r\n");
-       if (verbose)
-               log_print("SMTP> RSET\n");
+static gint smtp_rset(SMTPSession *session)
+{
+       session->state = SMTP_RSET;
+
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "RSET");
+       log_print("SMTP> RSET\n");
 
-       return smtp_ok(sock, NULL, 0);
+       return SM_OK;
 }
 
-gint smtp_quit(SMTPSession *session)
+static gint smtp_quit(SMTPSession *session)
 {
-       SockInfo *sock;
+       session->state = SMTP_QUIT;
 
-       UI_UPDATE(session, SMTP_QUIT);
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "QUIT");
+       log_print("SMTP> QUIT\n");
 
-       sock = SESSION(session)->sock;
+       return SM_OK;
+}
 
-       sock_printf(sock, "QUIT\r\n");
-       if (verbose)
-               log_print("SMTP> QUIT\n");
+static gint smtp_eom(SMTPSession *session)
+{
+       session->state = SMTP_EOM;
 
-       return smtp_ok(sock, NULL, 0);
+       session_send_msg(SESSION(session), SESSION_MSG_NORMAL, ".");
+       log_print("SMTP> . (EOM)\n");
+
+       return SM_OK;
 }
 
-gint smtp_eom(SMTPSession *session)
+static gint smtp_session_recv_msg(Session *session, const gchar *msg)
 {
-       SockInfo *sock;
-
-       UI_UPDATE(session, SMTP_EOM);
+       SMTPSession *smtp_session = SMTP_SESSION(session);
+       gboolean cont = FALSE;
 
-       sock = SESSION(session)->sock;
+       if (strlen(msg) < 4)
+               return -1;
 
-       sock_printf(sock, ".\r\n");
-       if (verbose)
-               log_print("SMTP> . (EOM)\n");
+       log_print("SMTP< %s\n", msg);
 
-       return smtp_ok(sock, NULL, 0);
-}
+       if (msg[0] == '5' && msg[1] == '0' &&
+           (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) {
+               smtp_session->state = SMTP_ERROR;
+               return -1;
+       }
 
-static gint smtp_ok(SockInfo *sock, gchar *buf, gint len)
-{
-       gchar tmpbuf[MSGBUFSIZE];
+       if (msg[0] != '1' && msg[0] != '2' && msg[0] != '3') {
+               smtp_session->state = SMTP_ERROR;
+               return -1;
+       }
 
-       if (!buf) {
-               buf = tmpbuf;
-               len = sizeof(tmpbuf);
+       if (msg[3] == '-')
+               cont = TRUE;
+       else if (msg[3] != ' ' && msg[3] != '\0') {
+               smtp_session->state = SMTP_ERROR;
+               return -1;
        }
 
-       while ((sock_gets(sock, buf, len - 1)) != -1) {
-               if (strlen(buf) < 4)
-                       return SM_ERROR;
-               strretchomp(buf);
-
-               if (verbose)
-                       log_print("SMTP< %s\n", buf);
-
-               if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') &&
-                   (buf[3] == ' ' || buf[3] == '\0'))
-                       return SM_OK;
-               else if (buf[3] != '-')
-                       return SM_ERROR;
-               else if (buf[0] == '5' && buf[1] == '0' &&
-                        (buf[2] == '4' || buf[2] == '3' || buf[2] == '1'))
-                       return SM_ERROR;
+       switch (smtp_session->state) {
+       case SMTP_READY:
+       case SMTP_CONNECTED:
+#if USE_OPENSSL
+               if (smtp_session->user || session->ssl_type != SSL_NONE)
+#else
+               if (smtp_session->user)
+#endif
+                       smtp_ehlo(smtp_session);
+               else
+                       smtp_helo(smtp_session);
+               break;
+       case SMTP_HELO:
+               smtp_from(smtp_session);
+               break;
+       case SMTP_EHLO:
+               smtp_ehlo_recv(smtp_session, msg);
+               if (cont == TRUE)
+                       break;
+#if USE_OPENSSL
+               if (session->ssl_type == SSL_STARTTLS &&
+                   smtp_session->tls_init_done == FALSE) {
+                       smtp_starttls(smtp_session);
+                       break;
+               }
+#endif
+               if (smtp_session->user) {
+                       if (smtp_auth(smtp_session) != SM_OK)
+                               smtp_from(smtp_session);
+               } else
+                       smtp_from(smtp_session);
+               break;
+       case SMTP_STARTTLS:
+#if USE_OPENSSL
+               if (session_start_tls(session) < 0)
+                       return -1;
+               smtp_session->tls_init_done = TRUE;
+               smtp_ehlo(smtp_session);
+#endif
+               break;
+       case SMTP_AUTH:
+               smtp_auth_recv(smtp_session, msg);
+               break;
+       case SMTP_AUTH_LOGIN_USER:
+               smtp_auth_login_user_recv(smtp_session, msg);
+               break;
+       case SMTP_AUTH_LOGIN_PASS:
+       case SMTP_AUTH_CRAM_MD5:
+               smtp_from(smtp_session);
+               break;
+       case SMTP_FROM:
+               if (smtp_session->cur_to)
+                       smtp_rcpt(smtp_session);
+               break;
+       case SMTP_RCPT:
+               if (smtp_session->cur_to)
+                       smtp_rcpt(smtp_session);
+               else
+                       smtp_data(smtp_session);
+               break;
+       case SMTP_DATA:
+               smtp_send_data(smtp_session);
+               break;
+       case SMTP_EOM:
+               smtp_quit(smtp_session);
+               break;
+       case SMTP_QUIT:
+               session_disconnect(session);
+               break;
+       case SMTP_ERROR:
+       default:
+               return -1;
        }
 
-       return SM_UNRECOVERABLE;
+       if (cont)
+               return 1;
+
+       return 0;
+}
+
+static gint smtp_session_send_data_finished(Session *session, guint len)
+{
+       smtp_eom(SMTP_SESSION(session));
+       return 0;
 }
index 5e58ce5..be2e812 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <glib.h>
 
-#include "socket.h"
-#if USE_OPENSSL
-#  include "ssl.h"
-#endif
 #include "session.h"
 
 typedef struct _SMTPSession    SMTPSession;
@@ -57,66 +53,55 @@ typedef enum
 
 typedef enum
 {
-       SMTP_CONNECT,
+       SMTP_READY,
+       SMTP_CONNECTED,
        SMTP_HELO,
        SMTP_EHLO,
        SMTP_STARTTLS,
        SMTP_FROM,
        SMTP_AUTH,
+       SMTP_AUTH_LOGIN_USER,
+       SMTP_AUTH_LOGIN_PASS,
+       SMTP_AUTH_CRAM_MD5,
        SMTP_RCPT,
        SMTP_DATA,
+       SMTP_SEND_DATA,
+       SMTP_EOM,
        SMTP_RSET,
        SMTP_QUIT,
-       SMTP_EOM,
+       SMTP_ERROR,
+       SMTP_DISCONNECTED,
 
        N_SMTP_PHASE
-} SMTPPhase;
+} SMTPState;
 
 struct _SMTPSession
 {
        Session session;
 
-       SMTPAuthType avail_auth_type;
+       SMTPState state;
+
+#if USE_OPENSSL
+       gboolean tls_init_done;
+#endif
+
+       gchar *hostname;
+
        gchar *user;
        gchar *pass;
-};
 
-Session *smtp_session_new      (void);
-void smtp_session_destroy      (Session        *session);
+       gchar *from;
+       GSList *to_list;
+       GSList *cur_to;
 
-#if USE_OPENSSL
-gint smtp_connect              (SMTPSession    *session,
-                                const gchar    *server,
-                                gushort         port,
-                                const gchar    *domain,
-                                const gchar    *user,
-                                const gchar    *pass,
-                                SSLType         ssl_type);
-#else
-gint smtp_connect              (SMTPSession    *session,
-                                const gchar    *server,
-                                gushort         port,
-                                const gchar    *domain,
-                                const gchar    *user,
-                                const gchar    *pass);
-#endif
+       guchar *send_data;
+       guint send_data_len;
 
-gint smtp_from                 (SMTPSession    *session,
-                                const gchar    *from);
-gint smtp_auth                 (SMTPSession    *session,
-                                SMTPAuthType    forced_auth_type);
-
-gint smtp_ehlo                 (SMTPSession    *session,
-                                const gchar    *hostname,
-                                SMTPAuthType   *avail_auth_type);
-
-gint smtp_helo                 (SMTPSession    *session,
-                                const gchar    *hostname);
-gint smtp_rcpt                 (SMTPSession    *session,
-                                const gchar    *to);
-gint smtp_data                 (SMTPSession    *session);
-gint smtp_rset                 (SMTPSession    *session);
-gint smtp_quit                 (SMTPSession    *session);
-gint smtp_eom                  (SMTPSession    *session);
+       SMTPAuthType avail_auth_type;
+       SMTPAuthType forced_auth_type;
+       SMTPAuthType auth_type;
+};
+
+Session *smtp_session_new      (void);
 
 #endif /* __SMTP_H__ */
index 1e26abe..0538fff 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -448,7 +448,7 @@ gint sock_printf(SockInfo *sock, const gchar *format, ...)
        g_vsnprintf(buf, sizeof(buf), format, args);
        va_end(args);
 
-       return sock_write(sock, buf, strlen(buf));
+       return sock_write_all(sock, buf, strlen(buf));
 }
 
 gint sock_read(SockInfo *sock, gchar *buf, gint len)
@@ -489,6 +489,32 @@ gint sock_write(SockInfo *sock, const gchar *buf, gint len)
 }
 
 gint fd_write(gint fd, const gchar *buf, gint len)
+{
+       if (fd_check_io(fd, G_IO_OUT) < 0)
+               return -1;
+
+       return write(fd, buf, len);
+}
+
+#if USE_OPENSSL
+gint ssl_write(SSL *ssl, const gchar *buf, gint len)
+{
+       return SSL_write(ssl, buf, len);
+}
+#endif
+
+gint sock_write_all(SockInfo *sock, const gchar *buf, gint len)
+{
+       g_return_val_if_fail(sock != NULL, -1);
+
+#if USE_OPENSSL
+       if (sock->ssl)
+               return ssl_write_all(sock->ssl, buf, len);
+#endif
+       return fd_write_all(sock->sock, buf, len);
+}
+
+gint fd_write_all(gint fd, const gchar *buf, gint len)
 {
        gint n, wrlen = 0;
 
@@ -510,7 +536,7 @@ gint fd_write(gint fd, const gchar *buf, gint len)
 }
 
 #if USE_OPENSSL
-gint ssl_write(SSL *ssl, const gchar *buf, gint len)
+gint ssl_write_all(SSL *ssl, const gchar *buf, gint len)
 {
        gint n, wrlen = 0;
 
@@ -660,9 +686,9 @@ gint sock_puts(SockInfo *sock, const gchar *buf)
 {
        gint ret;
 
-       if ((ret = sock_write(sock, buf, strlen(buf))) < 0)
+       if ((ret = sock_write_all(sock, buf, strlen(buf))) < 0)
                return ret;
-       return sock_write(sock, "\r\n", 2);
+       return sock_write_all(sock, "\r\n", 2);
 }
 
 /* peek at the next socket character without actually reading it */
index 68d178a..135e654 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2001 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,6 +72,7 @@ gint sock_printf      (SockInfo *sock, const gchar *format, ...)
                         G_GNUC_PRINTF(2, 3);
 gint sock_read         (SockInfo *sock, gchar *buf, gint len);
 gint sock_write                (SockInfo *sock, const gchar *buf, gint len);
+gint sock_write_all    (SockInfo *sock, const gchar *buf, gint len);
 gint sock_gets         (SockInfo *sock, gchar *buf, gint len);
 gchar *sock_getline    (SockInfo *sock);
 gint sock_puts         (SockInfo *sock, const gchar *buf);
@@ -90,16 +91,18 @@ gint fd_accept              (gint sock);
 
 gint fd_read           (gint sock, gchar *buf, gint len);
 gint fd_write          (gint sock, const gchar *buf, gint len);
+gint fd_write_all      (gint sock, const gchar *buf, gint len);
 gint fd_gets           (gint sock, gchar *buf, gint len);
 gchar *fd_getline      (gint sock);
 gint fd_close          (gint sock);
 
 /* Functions for SSL */
-#if USE_OPENSSL
-gint ssl_read(SSL *ssl, gchar *buf, gint len);
-gint ssl_write(SSL *ssl, const gchar *buf, gint len);
-gint ssl_gets(SSL *ssl, gchar *buf, gint len);
-gchar *ssl_getline(SSL *ssl);
+#if USE_SSL
+gint ssl_read          (SSL *ssl, gchar *buf, gint len);
+gint ssl_write         (SSL *ssl, const gchar *buf, gint len);
+gint ssl_write_all     (SSL *ssl, const gchar *buf, gint len);
+gint ssl_gets          (SSL *ssl, gchar *buf, gint len);
+gchar *ssl_getline     (SSL *ssl);
 #endif
 
 #endif /* __SOCKET_H__ */
index a0c3180..51a2b49 100644 (file)
@@ -2604,6 +2604,54 @@ gint uncanonicalize_file_replace(const gchar *file)
        return 0;
 }
 
+gchar *get_outgoing_rfc2822_str(FILE *fp)
+{
+       gchar buf[BUFFSIZE];
+       GString *str;
+       gchar *ret;
+
+       str = g_string_new(NULL);
+
+       /* output header part */
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               strretchomp(buf);
+               if (!g_strncasecmp(buf, "Bcc:", 4)) {
+                       gint next;
+
+                       for (;;) {
+                               next = fgetc(fp);
+                               if (next == EOF)
+                                       break;
+                               else if (next != ' ' && next != '\t') {
+                                       ungetc(next, fp);
+                                       break;
+                               }
+                               if (fgets(buf, sizeof(buf), fp) == NULL)
+                                       break;
+                       }
+               } else {
+                       g_string_append(str, buf);
+                       g_string_append(str, "\r\n");
+                       if (buf[0] == '\0')
+                               break;
+               }
+       }
+
+       /* output body part */
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               strretchomp(buf);
+               if (buf[0] == '.')
+                       g_string_append_c(str, '.');
+               g_string_append(str, buf);
+               g_string_append(str, "\r\n");
+       }
+
+       ret = str->str;
+       g_string_free(str, FALSE);
+
+       return ret;
+}
+
 gint change_file_mode_rw(FILE *fp, const gchar *file)
 {
 #if HAVE_FCHMOD
@@ -2716,10 +2764,7 @@ gint str_write_to_file(const gchar *str, const gchar *file)
 
 gchar *file_read_to_str(const gchar *file)
 {
-       GByteArray *array;
        FILE *fp;
-       gchar buf[BUFSIZ];
-       gint n_read;
        gchar *str;
 
        g_return_val_if_fail(file != NULL, NULL);
@@ -2729,6 +2774,22 @@ gchar *file_read_to_str(const gchar *file)
                return NULL;
        }
 
+       str = file_read_stream_to_str(fp);
+
+       fclose(fp);
+
+       return str;
+}
+
+gchar *file_read_stream_to_str(FILE *fp)
+{
+       GByteArray *array;
+       gchar buf[BUFSIZ];
+       gint n_read;
+       gchar *str;
+
+       g_return_val_if_fail(fp != NULL, NULL);
+
        array = g_byte_array_new();
 
        while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
@@ -2738,14 +2799,11 @@ gchar *file_read_to_str(const gchar *file)
        }
 
        if (ferror(fp)) {
-               FILE_OP_ERROR(file, "fread");
-               fclose(fp);
+               FILE_OP_ERROR("file stream", "fread");
                g_byte_array_free(array, TRUE);
                return NULL;
        }
 
-       fclose(fp);
-
        buf[0] = '\0';
        g_byte_array_append(array, buf, 1);
        str = (gchar *)array->data;
index 7529712..84e40bb 100644 (file)
@@ -371,6 +371,8 @@ gint uncanonicalize_file    (const gchar    *src,
                                 const gchar    *dest);
 gint uncanonicalize_file_replace(const gchar   *file);
 
+gchar *get_outgoing_rfc2822_str        (FILE           *fp);
+
 gint change_file_mode_rw       (FILE           *fp,
                                 const gchar    *file);
 FILE *my_tmpfile               (void);
@@ -378,6 +380,7 @@ FILE *str_open_as_stream    (const gchar    *str);
 gint str_write_to_file         (const gchar    *str,
                                 const gchar    *file);
 gchar *file_read_to_str                (const gchar    *file);
+gchar *file_read_stream_to_str (FILE           *fp);
 
 /* process execution */
 gint execute_async             (gchar *const    argv[]);
index cf02772..7785cfa 100644 (file)
@@ -78,7 +78,7 @@
 #include "procmsg.h"
 #include "menu.h"
 #include "stock_pixmap.h"
-#include "send.h"
+#include "send_message.h"
 #include "imap.h"
 #include "news.h"
 #include "customheader.h"
@@ -5761,20 +5761,20 @@ static void compose_exec_ext_editor(Compose *compose)
                close(pipe_fds[0]);
 
                if (compose_write_body_to_file(compose, tmp) < 0) {
-                       fd_write(pipe_fds[1], "2\n", 2);
+                       fd_write_all(pipe_fds[1], "2\n", 2);
                        _exit(1);
                }
 
                pid_ed = compose_exec_ext_editor_real(tmp);
                if (pid_ed < 0) {
-                       fd_write(pipe_fds[1], "1\n", 2);
+                       fd_write_all(pipe_fds[1], "1\n", 2);
                        _exit(1);
                }
 
                /* wait until editor is terminated */
                waitpid(pid_ed, NULL, 0);
 
-               fd_write(pipe_fds[1], "0\n", 2);
+               fd_write_all(pipe_fds[1], "0\n", 2);
 
                close(pipe_fds[1]);
                _exit(0);
index 44dc29b..c8dfd71 100644 (file)
@@ -559,8 +559,6 @@ Session *imap_session_new(const PrefsAccount *account)
        SESSION(session)->type             = SESSION_IMAP;
        SESSION(session)->server           = g_strdup(account->recv_server);
        SESSION(session)->sock             = imap_sock;
-       SESSION(session)->connected        = TRUE;
-       SESSION(session)->phase            = SESSION_READY;
        SESSION(session)->last_access_time = time(NULL);
        SESSION(session)->data             = NULL;
 
@@ -2971,7 +2969,7 @@ static void imap_cmd_gen_send(SockInfo *sock, const gchar *format, ...)
        } else
                log_print("IMAP4> %d %s\n", imap_cmd_count, tmp);
 
-       sock_write(sock, buf, strlen(buf));
+       sock_write_all(sock, buf, strlen(buf));
 }
 
 static gint imap_cmd_gen_recv(SockInfo *sock, gchar **buf)
index b0e127f..a18a620 100644 (file)
@@ -654,9 +654,9 @@ static gint prohibit_duplicate_launch(void)
        debug_print("another Sylpheed is already running.\n");
 
        if (cmd.receive_all)
-               fd_write(uxsock, "receive_all\n", 12);
+               fd_write_all(uxsock, "receive_all\n", 12);
        else if (cmd.receive)
-               fd_write(uxsock, "receive\n", 8);
+               fd_write_all(uxsock, "receive\n", 8);
        else if (cmd.compose && cmd.attach_files) {
                gchar *str, *compose_str;
                gint i;
@@ -667,16 +667,16 @@ static gint prohibit_duplicate_launch(void)
                else
                        compose_str = g_strdup("compose_attach\n");
 
-               fd_write(uxsock, compose_str, strlen(compose_str));
+               fd_write_all(uxsock, compose_str, strlen(compose_str));
                g_free(compose_str);
 
                for (i = 0; i < cmd.attach_files->len; i++) {
                        str = g_ptr_array_index(cmd.attach_files, i);
-                       fd_write(uxsock, str, strlen(str));
-                       fd_write(uxsock, "\n", 1);
+                       fd_write_all(uxsock, str, strlen(str));
+                       fd_write_all(uxsock, "\n", 1);
                }
 
-               fd_write(uxsock, ".\n", 2);
+               fd_write_all(uxsock, ".\n", 2);
        } else if (cmd.compose) {
                gchar *compose_str;
 
@@ -685,10 +685,10 @@ static gint prohibit_duplicate_launch(void)
                else
                        compose_str = g_strdup("compose\n");
 
-               fd_write(uxsock, compose_str, strlen(compose_str));
+               fd_write_all(uxsock, compose_str, strlen(compose_str));
                g_free(compose_str);
        } else if (cmd.send) {
-               fd_write(uxsock, "send\n", 5);
+               fd_write_all(uxsock, "send\n", 5);
        } else if (cmd.online_mode == ONLINE_MODE_ONLINE) {
                fd_write(uxsock, "online\n", 6);
        } else if (cmd.online_mode == ONLINE_MODE_OFFLINE) {
@@ -696,11 +696,11 @@ static gint prohibit_duplicate_launch(void)
        } else if (cmd.status) {
                gchar buf[BUFFSIZE];
 
-               fd_write(uxsock, "status\n", 7);
+               fd_write_all(uxsock, "status\n", 7);
                fd_gets(uxsock, buf, sizeof(buf));
                fputs(buf, stdout);
        } else
-               fd_write(uxsock, "popup\n", 6);
+               fd_write_all(uxsock, "popup\n", 6);
 
        fd_close(uxsock);
        return -1;
@@ -768,7 +768,7 @@ static void lock_socket_input_cb(gpointer data,
 
                folder_count_total_msgs(&new, &unread, &unreadmarked, &total);
                g_snprintf(buf, sizeof(buf), "%d %d %d %d\n", new, unread, unreadmarked, total);
-               fd_write(sock, buf, strlen(buf));
+               fd_write_all(sock, buf, strlen(buf));
        }
 
        fd_close(sock);
index ff7d3f4..cf89394 100644 (file)
@@ -48,7 +48,7 @@
 #include "about.h"
 #include "account.h"
 #include "alertpanel.h"
-#include "send.h"
+#include "send_message.h"
 #include "pgptext.h"
 #include "menu.h"
 #include "stock_pixmap.h"
index c2a25da..40d238d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -218,8 +218,6 @@ static Session *news_session_new(const gchar *server, gushort port,
        SESSION(session)->server           = g_strdup(server);
        session->nntp_sock                 = nntp_sock;
        SESSION(session)->sock             = nntp_sock->sock;
-       SESSION(session)->connected        = TRUE;
-       SESSION(session)->phase            = SESSION_READY;
        SESSION(session)->last_access_time = time(NULL);
        SESSION(session)->data             = NULL;
 
index 8738bb4..87c5631 100644 (file)
--- a/src/pop.c
+++ b/src/pop.c
@@ -668,7 +668,7 @@ static void pop3_gen_send(SockInfo *sock, const gchar *format, ...)
                log_print("POP3> %s\n", buf);
 
        strcat(buf, "\r\n");
-       sock_write(sock, buf, strlen(buf));
+       sock_write_all(sock, buf, strlen(buf));
 }
 
 static gint pop3_gen_recv(SockInfo *sock, gchar *buf, gint size)
index e9fea26..f6266db 100644 (file)
@@ -28,7 +28,7 @@
 #include "utils.h"
 #include "procmsg.h"
 #include "procheader.h"
-#include "send.h"
+#include "send_message.h"
 #include "procmime.h"
 #include "statusbar.h"
 #include "folder.h"
diff --git a/src/send_message.c b/src/send_message.c
new file mode 100644 (file)
index 0000000..f62e07e
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkclist.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "intl.h"
+#include "send_message.h"
+#include "session.h"
+#include "ssl.h"
+#include "smtp.h"
+#include "prefs_common.h"
+#include "prefs_account.h"
+#include "procheader.h"
+#include "account.h"
+#include "progressdialog.h"
+#include "inputdialog.h"
+#include "manage_window.h"
+#include "utils.h"
+#include "gtkutils.h"
+#include "statusbar.h"
+#include "inc.h"
+#include "log.h"
+
+typedef struct _SendProgressDialog     SendProgressDialog;
+
+struct _SendProgressDialog
+{
+       ProgressDialog *dialog;
+       Session *session;
+       gboolean cancelled;
+};
+#if 0
+static gint send_message_local         (const gchar            *command,
+                                        FILE                   *fp);
+static gint send_message_smtp          (PrefsAccount           *ac_prefs,
+                                        GSList                 *to_list,
+                                        FILE                   *fp);
+#endif
+
+static gint send_recv_message          (Session                *session,
+                                        const gchar            *msg,
+                                        gpointer                data);
+static gint send_send_data_progressive (Session                *session,
+                                        guint                   cur_len,
+                                        guint                   total_len,
+                                        gpointer                data);
+static gint send_send_data_finished    (Session                *session,
+                                        guint                   len,
+                                        gpointer                data);
+
+static SendProgressDialog *send_progress_dialog_create (void);
+static void send_progress_dialog_destroy       (SendProgressDialog *dialog);
+
+static void send_cancel_button_cb      (GtkWidget      *widget,
+                                        gpointer        data);
+
+gint send_message(const gchar *file, PrefsAccount *ac_prefs, GSList *to_list)
+{
+       FILE *fp;
+       gint val;
+
+       g_return_val_if_fail(file != NULL, -1);
+       g_return_val_if_fail(ac_prefs != NULL, -1);
+       g_return_val_if_fail(to_list != NULL, -1);
+
+       if ((fp = fopen(file, "rb")) == NULL) {
+               FILE_OP_ERROR(file, "fopen");
+               return -1;
+       }
+
+       if (ac_prefs->use_mail_command && ac_prefs->mail_command &&
+           (*ac_prefs->mail_command)) {
+               val = send_message_local(ac_prefs->mail_command, fp);
+               fclose(fp);
+               return val;
+       }
+       else if (prefs_common.use_extsend && prefs_common.extsend_cmd) {
+               val = send_message_local(prefs_common.extsend_cmd, fp);
+               fclose(fp);
+               return val;
+       }
+       else {
+               val = send_message_smtp(ac_prefs, to_list, fp);
+               
+               fclose(fp);
+               return val;
+       }
+}
+
+enum
+{
+       Q_SENDER     = 0,
+       Q_SMTPSERVER = 1,
+       Q_RECIPIENTS = 2,
+       Q_ACCOUNT_ID = 3
+};
+
+#if 0
+gint send_message_queue(const gchar *file)
+{
+       static HeaderEntry qentry[] = {{"S:",   NULL, FALSE},
+                                      {"SSV:", NULL, FALSE},
+                                      {"R:",   NULL, FALSE},
+                                      {"AID:", NULL, FALSE},
+                                      {NULL,   NULL, FALSE}};
+       FILE *fp;
+       gint val = 0;
+       gchar *from = NULL;
+       gchar *server = NULL;
+       GSList *to_list = NULL;
+       gchar buf[BUFFSIZE];
+       gint hnum;
+       glong fpos;
+       PrefsAccount *ac = NULL, *mailac = NULL, *newsac = NULL;
+
+       g_return_val_if_fail(file != NULL, -1);
+
+       if ((fp = fopen(file, "rb")) == NULL) {
+               FILE_OP_ERROR(file, "fopen");
+               return -1;
+       }
+
+       while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, qentry))
+              != -1) {
+               gchar *p;
+
+               p = buf + strlen(qentry[hnum].name);
+
+               switch (hnum) {
+               case Q_SENDER:
+                       if (!from) from = g_strdup(p);
+                       break;
+               case Q_SMTPSERVER:
+                       if (!server) server = g_strdup(p);
+                       break;
+               case Q_RECIPIENTS:
+                       to_list = address_list_append(to_list, p);
+                       break;
+               case Q_ACCOUNT_ID:
+                       ac = account_find_from_id(atoi(p));
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (((!ac || (ac && ac->protocol != A_NNTP)) && !to_list) || !from) {
+               g_warning("Queued message header is broken.\n");
+               val = -1;
+       } else if (prefs_common.use_extsend && prefs_common.extsend_cmd) {
+               val = send_message_local(prefs_common.extsend_cmd, fp);
+       } else {
+               if (ac && ac->protocol == A_NNTP) {
+                       newsac = ac;
+
+                       /* search mail account */
+                       mailac = account_find_from_address(from);
+                       if (!mailac) {
+                               if (cur_account &&
+                                   cur_account->protocol != A_NNTP)
+                                       mailac = cur_account;
+                               else {
+                                       mailac = account_get_default();
+                                       if (mailac->protocol == A_NNTP)
+                                               mailac = NULL;
+                               }
+                       }
+               } else if (ac) {
+                       mailac = ac;
+               } else {
+                       ac = account_find_from_smtp_server(from, server);
+                       if (!ac) {
+                               g_warning("Account not found. "
+                                         "Using current account...\n");
+                               ac = cur_account;
+                               if (ac && ac->protocol != A_NNTP)
+                                       mailac = ac;
+                       }
+               }
+
+               fpos = ftell(fp);
+               if (to_list) {
+                       if (mailac)
+                               val = send_message_smtp(mailac, to_list, fp);
+                       else {
+                               PrefsAccount tmp_ac;
+
+                               g_warning("Account not found.\n");
+
+                               memset(&tmp_ac, 0, sizeof(PrefsAccount));
+                               tmp_ac.address = from;
+                               tmp_ac.smtp_server = server;
+                               tmp_ac.smtpport = SMTP_PORT;
+                               val = send_message_smtp(&tmp_ac, to_list, fp);
+                       }
+               }
+
+               if (val == 0 && newsac) {
+                       fseek(fp, fpos, SEEK_SET);
+                       val = news_post_stream(FOLDER(newsac->folder), fp);
+               }
+       }
+
+       slist_free_strings(to_list);
+       g_slist_free(to_list);
+       g_free(from);
+       g_free(server);
+       fclose(fp);
+
+       return val;
+}
+#endif
+
+gint send_message_local(const gchar *command, FILE *fp)
+{
+       FILE *pipefp;
+       gchar buf[BUFFSIZE];
+       int r;
+       sigset_t osig, mask;
+
+       g_return_val_if_fail(command != NULL, -1);
+       g_return_val_if_fail(fp != NULL, -1);
+
+       pipefp = popen(command, "w");
+       if (!pipefp) {
+               g_warning("Can't execute external command: %s\n", command);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               strretchomp(buf);
+               fputs(buf, pipefp);
+               fputc('\n', pipefp);
+       }
+
+       /* we need to block SIGCHLD, otherwise pspell's handler will wait()
+        * the pipecommand away and pclose will return -1 because of its
+        * failed wait4().
+        */
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+       sigprocmask(SIG_BLOCK, &mask, &osig);
+       
+       r = pclose(pipefp);
+
+       sigprocmask(SIG_SETMASK, &osig, NULL);
+       if (r != 0) {
+               g_warning("external command `%s' failed with code `%i'\n", command, r);
+               return -1;
+       }
+
+       return 0;
+}
+
+gint send_message_smtp(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp)
+{
+       Session *session;
+       SMTPSession *smtp_session;
+       gushort port;
+       SendProgressDialog *dialog;
+       GtkCList *clist;
+       const gchar *text[3];
+       gchar buf[BUFFSIZE];
+       gint ret = 0;
+
+       g_return_val_if_fail(ac_prefs != NULL, -1);
+       g_return_val_if_fail(ac_prefs->address != NULL, -1);
+       g_return_val_if_fail(ac_prefs->smtp_server != NULL, -1);
+       g_return_val_if_fail(to_list != NULL, -1);
+       g_return_val_if_fail(fp != NULL, -1);
+
+       session = smtp_session_new();
+       smtp_session = SMTP_SESSION(session);
+
+       smtp_session->hostname =
+               ac_prefs->set_domain ? g_strdup(ac_prefs->domain) : NULL;
+
+       if (ac_prefs->use_smtp_auth) {
+               if (ac_prefs->smtp_userid) {
+                       smtp_session->user = g_strdup(ac_prefs->smtp_userid);
+                       if (ac_prefs->smtp_passwd)
+                               smtp_session->pass =
+                                       g_strdup(ac_prefs->smtp_passwd);
+                       else if (ac_prefs->tmp_smtp_pass)
+                               smtp_session->pass =
+                                       g_strdup(ac_prefs->tmp_smtp_pass);
+                       else {
+                               smtp_session->pass =
+                                       input_dialog_query_password
+                                               (ac_prefs->smtp_server,
+                                                smtp_session->user);
+                               if (!smtp_session->pass)
+                                       smtp_session->pass = g_strdup("");
+                               ac_prefs->tmp_smtp_pass =
+                                       g_strdup(smtp_session->pass);
+                       }
+               } else {
+                       smtp_session->user = g_strdup(ac_prefs->userid);
+                       if (ac_prefs->passwd)
+                               smtp_session->pass = g_strdup(ac_prefs->passwd);
+                       else if (ac_prefs->tmp_pass)
+                               smtp_session->pass =
+                                       g_strdup(ac_prefs->tmp_pass);
+                       else {
+                               smtp_session->pass =
+                                       input_dialog_query_password
+                                               (ac_prefs->smtp_server,
+                                                smtp_session->user);
+                               if (!smtp_session->pass)
+                                       smtp_session->pass = g_strdup("");
+                               ac_prefs->tmp_pass =
+                                       g_strdup(smtp_session->pass);
+                       }
+               }
+       } else {
+               smtp_session->user = NULL;
+               smtp_session->pass = NULL;
+       }
+
+       smtp_session->from = g_strdup(ac_prefs->address);
+       smtp_session->to_list = to_list;
+       smtp_session->cur_to = to_list;
+       smtp_session->send_data = get_outgoing_rfc2822_str(fp);
+       smtp_session->send_data_len = strlen(smtp_session->send_data);
+
+#if USE_SSL
+       port = ac_prefs->set_smtpport ? ac_prefs->smtpport :
+               ac_prefs->ssl_smtp == SSL_TUNNEL ? SSMTP_PORT : SMTP_PORT;
+       session->ssl_type = ac_prefs->ssl_smtp;
+#else
+       port = ac_prefs->set_smtpport ? ac_prefs->smtpport : SMTP_PORT;
+#endif
+
+       dialog = send_progress_dialog_create();
+       dialog->session = session;
+
+       text[0] = NULL;
+       text[1] = ac_prefs->smtp_server;
+       text[2] = _("Connecting");
+       clist = GTK_CLIST(dialog->dialog->clist);
+       gtk_clist_append(clist, (gchar **)text);
+
+       if (ac_prefs->pop_before_smtp
+           && (ac_prefs->protocol == A_APOP || ac_prefs->protocol == A_POP3)
+           && (time(NULL) - ac_prefs->last_pop_login_time) > (60 * ac_prefs->pop_before_smtp_timeout)) {
+               g_snprintf(buf, sizeof(buf), _("Doing POP before SMTP..."));
+               log_message(buf);
+               progress_dialog_set_label(dialog->dialog, buf);
+               gtk_clist_set_text(clist, 0, 2, _("POP before SMTP"));
+               GTK_EVENTS_FLUSH();
+               inc_pop_before_smtp(ac_prefs);
+       }
+       
+       g_snprintf(buf, sizeof(buf), _("Connecting to SMTP server: %s ..."),
+                  ac_prefs->smtp_server);
+       progress_dialog_set_label(dialog->dialog, buf);
+       log_message("%s\n", buf);
+
+       session_set_recv_message_notify(session, send_recv_message, dialog);
+       session_set_send_data_progressive_notify
+               (session, send_send_data_progressive, dialog);
+       session_set_send_data_notify(session, send_send_data_finished, dialog);
+
+       if (session_connect(session, ac_prefs->smtp_server, port) < 0) {
+               session_destroy(session);
+               send_progress_dialog_destroy(dialog);
+               return -1;
+       }
+
+       g_print("parent: begin event loop\n");
+
+       while (session->state != SESSION_DISCONNECTED &&
+              session->state != SESSION_ERROR)
+               gtk_main_iteration();
+
+       if (session->state == SESSION_ERROR ||
+           SMTP_SESSION(session)->state == SMTP_ERROR)
+               ret = -1;
+       else if (dialog->cancelled == TRUE)
+               ret = -1;
+
+       session_destroy(session);
+       send_progress_dialog_destroy(dialog);
+
+       statusbar_verbosity_set(FALSE);
+       return ret;
+}
+
+static gint send_recv_message(Session *session, const gchar *msg, gpointer data)
+{
+       SMTPSession *smtp_session = SMTP_SESSION(session);
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+       gchar buf[BUFFSIZE];
+       gchar *state_str = NULL;
+
+       switch (smtp_session->state) {
+       case SMTP_READY:
+       case SMTP_CONNECTED:
+               return 0;
+       case SMTP_HELO:
+               g_snprintf(buf, sizeof(buf), _("Sending HELO..."));
+               state_str = _("Authenticating");
+               break;
+       case SMTP_EHLO:
+               g_snprintf(buf, sizeof(buf), _("Sending EHLO..."));
+               state_str = _("Authenticating");
+               break;
+       case SMTP_AUTH:
+               g_snprintf(buf, sizeof(buf), _("Authenticating..."));
+               state_str = _("Authenticating");
+               break;
+       case SMTP_FROM:
+               g_snprintf(buf, sizeof(buf), _("Sending MAIL FROM..."));
+               state_str = _("Sending");
+               break;
+       case SMTP_RCPT:
+               g_snprintf(buf, sizeof(buf), _("Sending RCPT TO..."));
+               state_str = _("Sending");
+               break;
+       case SMTP_DATA:
+       case SMTP_EOM:
+               g_snprintf(buf, sizeof(buf), _("Sending DATA..."));
+               state_str = _("Sending");
+               break;
+       case SMTP_QUIT:
+               g_snprintf(buf, sizeof(buf), _("Quitting..."));
+               state_str = _("Quitting");
+               break;
+       case SMTP_ERROR:
+               g_warning("send: error: %s\n", msg);
+               return 0;
+       default:
+               return 0;
+       }
+
+       progress_dialog_set_label(dialog->dialog, buf);
+       gtk_clist_set_text(GTK_CLIST(dialog->dialog->clist), 0, 2, state_str);
+
+       return 0;
+}
+
+static gint send_send_data_progressive(Session *session, guint cur_len,
+                                      guint total_len, gpointer data)
+{
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+       gchar buf[BUFFSIZE];
+
+       g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
+                  cur_len, total_len);
+       progress_dialog_set_label(dialog->dialog, buf);
+       progress_dialog_set_percentage
+               (dialog->dialog, (gfloat)cur_len / (gfloat)total_len);
+
+       return 0;
+}
+
+static gint send_send_data_finished(Session *session, guint len, gpointer data)
+{
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+       gchar buf[BUFFSIZE];
+
+       g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
+                  len, len);
+       progress_dialog_set_label(dialog->dialog, buf);
+       progress_dialog_set_percentage(dialog->dialog, 1.0);
+
+       return 0;
+}
+
+static SendProgressDialog *send_progress_dialog_create(void)
+{
+       SendProgressDialog *dialog;
+       ProgressDialog *progress;
+
+       dialog = g_new0(SendProgressDialog, 1);
+
+       progress = progress_dialog_create();
+       gtk_window_set_title(GTK_WINDOW(progress->window),
+                            _("Sending message"));
+       gtk_signal_connect(GTK_OBJECT(progress->cancel_btn), "clicked",
+                          GTK_SIGNAL_FUNC(send_cancel_button_cb), dialog);
+       gtk_signal_connect(GTK_OBJECT(progress->window), "delete_event",
+                          GTK_SIGNAL_FUNC(gtk_true), NULL);
+       gtk_window_set_modal(GTK_WINDOW(progress->window), TRUE);
+       manage_window_set_transient(GTK_WINDOW(progress->window));
+
+       progress_dialog_set_value(progress, 0.0);
+
+       if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
+               gtk_widget_show_now(progress->window);
+       }
+       
+       dialog->dialog = progress;
+
+       return dialog;
+}
+
+static void send_progress_dialog_destroy(SendProgressDialog *dialog)
+{
+       g_return_if_fail(dialog != NULL);
+       if (prefs_common.send_dialog_mode == SEND_DIALOG_ALWAYS) {
+               progress_dialog_destroy(dialog->dialog);
+       }
+       g_free(dialog);
+}
+
+static void send_cancel_button_cb(GtkWidget *widget, gpointer data)
+{
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+       Session *session = dialog->session;
+
+       session->state = SESSION_DISCONNECTED;
+       dialog->cancelled = TRUE;
+}
diff --git a/src/send_message.h b/src/send_message.h
new file mode 100644 (file)
index 0000000..5bb4bef
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SEND_MESSAGE_H__
+#define __SEND_MESSAGE_H__
+
+#include <glib.h>
+
+#include "prefs_account.h"
+
+#define SMTP_PORT      25
+#if USE_OPENSSL
+#define SSMTP_PORT     465
+#endif
+
+gint send_message              (const gchar    *file,
+                                PrefsAccount   *ac_prefs,
+                                GSList         *to_list);
+#if 0
+gint send_message_queue                (const gchar    *file);
+#endif
+gint send_message_local                (const gchar *command,
+                                FILE *fp);
+gint send_message_smtp         (PrefsAccount *ac_prefs,
+                                GSList *to_list,
+                                FILE *fp);
+
+#endif /* __SEND_H__ */