/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2002, 2003, 2004 rzyjontko

   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; version 2.

   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.  

   ----------------------------------------------------------------------

   This module implements RFC2821 and RFC821 (e)smtp client side protocol.

   Its implementation is based on the project stored in the diagram in
   smtp.dia.

*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

#include "smtp.h"
#include "networking.h"
#include "error.h"
#include "wrapbox.h"
#include "mail.h"
#include "mybox.h"
#include "xmalloc.h"
#include "ask.h"
#include "gettext.h"
#include "str.h"
#include "debug.h"
#include "file.h"
#include "hmac-md5.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#ifndef HOST_NAME_MAX
# define HOST_NAME_MAX 255
#endif

#define TERMINATOR_RE "[0-9]{3,3} [^\r\n]*\r\n$"

#define PICK_NEXT() do { sent++; pick_message (); return; } while (0)

enum state {
        SMTP_READY,             /* ready to flush - initial / final state */
        
        SMTP_DISCONNECTED,      /* no connection */
        SMTP_GREETING,          /* after welcome message (greeting) */
        SMTP_EHLO,              /* after response to ehlo */
        SMTP_HELO,              /* after response to helo */
        SMTP_AUTH,              /* after response to auth */
        SMTP_AUTH_INTER,        /* after response to sending a login */
        SMTP_AUTH_FINAL,        /* after response to sending a password or
                                   other credentials */

        SMTP_MAIL,              /* after response to mail from */
        SMTP_RCPT,              /* after response to rcpt to */
        SMTP_DATA,              /* after response to data */
        SMTP_SENT,              /* after response to message */

        SMTP_QUIT               /* after response to quit */
};

enum auth {
        AUTH_NONE,              /* authentication not supported */
        AUTH_CRAM_MD5,          /* CRAM-MD5 */
        AUTH_PLAIN,             /* PLAIN */
        AUTH_LOGIN              /* LOGIN */
};

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/

class Smtp : public Net {

private:
        enum state state;       /* connection state */
        
        mail_array_t *marray;   /* list of messages in outbox */

        int sent;               /* number of messages already sent */
        int tried;              /* number of recepients tried */
        int accepted;           /* number of recepients accepted */

        mail_t    *mail;        /* a message to be sent */
        address_t *recepient;   /* message's recepient */

        ask_t *ask;             /* smtp_acc data */
        str_t *send_buf;        /* data sent to server */
        str_t *error_message;   /* error message displayed to the user */

        enum auth auth;         /* authentication method supported */
        
        int ext_size;           /* if server supports size extension */
        int ext_pipeline;       /* if server supports pipelining */
        int ext_8bitmime;       /* if server supports BODY=... */
        int ext_auth;           /* if server supports AUTH */
        int max_size;           /* maximal message size */

        address_t *next_recepient (void);
        void after_newline (char **buf, int *header);
        void copy_buf (char *buf);
        bool load_file (const char *fname);
        void parse_extension (char *s);
        void parse_extensions (char *msg);
        bool parse_answer (char *msg, int len);
        void report_error (const char *str);

        void s_sent (char *msg, int len);
        void s_data (char *msg, int len);
        void s_rcpt_to (char *msg, int len);
        void s_mail_from (char *msg, int len);
        void s_ehlo (char *msg, int len);
        void s_helo (char *msg, int len);
        void s_auth_final (char *msg, int len);
        void s_auth_cram_md5 (char *msg, int len);
        void s_auth_plain (char *msg, int len);
        void s_auth_login_2 (char *msg, int len);
        void s_auth_login (char *msg, int len);
        void s_auth (char *msg, int len);
        void s_greeting (char *msg, int len);
        void s_disconnected (void);
        void s_quit (char *msg, int len);
        
        void init (void);
        void cleanup (void);
        void pick_recepient (void);
        void pick_message (void);
        void pick_server (void);

        void send_ehlo (void);
        void send_helo (void);
        void send_auth(void);
        void send_mail_from (void);
        void send_rcpt_to (void);
        void send_data (void);
        void send_quit (void);


protected:
        void recv_fun (char *buf, int size);
        void on_shutdown (void);


public:
        Smtp (void);
        ~Smtp (void);

        void run (void);
        void cancel (void);
        bool ready (void);
};

/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

static char *auth_str[4] = {
        NULL,
        "CRAM-MD5",
        "PLAIN",
        "LOGIN",
};

/* Here we store the result of gethostname(2). */
static char hostname[HOST_NAME_MAX + 1];

static Smtp *smtp = NULL;

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/

address_t *
Smtp::next_recepient (void)
{
        int n = tried;
        
        if (mail == NULL)
                return NULL;

        if (mail->to && n < mail->to->count){
                return mail->to->array[n];
        }
        else if (mail->to){
                n -= mail->to->count;
        }

        if (mail->cc && n < mail->cc->count){
                return mail->cc->array[n];
        }
        else if (mail->cc){
                n -= mail->cc->count;
        }

        if (mail->bcc && n < mail->bcc->count){
                return mail->bcc->array[n];
        }

        return NULL;
}


void
Smtp::after_newline (char **buf, int *header)
{
        switch (**buf){

                case '.':
                        str_put_string_len (send_buf, "..", 2);
                        break;

                case '\n':
                        *header = 0;
                        break;

                case 'B':
                        if (*header){
                                if (strstr (*buf, "Bcc") == *buf){
                                        while (**buf != '\n' && **buf)
                                                ++*buf;
                                }
                                if (**buf)
                                        ++*buf;
                        }
                        break;

                case 'X':
                        if (*header){
                                if (strstr (*buf, "X-Elmo-SMTP") == *buf){
                                        while (**buf != '\n' && **buf)
                                                ++*buf;
                                }
                                if (**buf)
                                        ++*buf;
                        }
                        break;
        }
}




void
Smtp::copy_buf (char *buf)
{
        int   header = 1;
        char *s      = buf;
        
        str_clear (send_buf);
        
        while (*s){

                switch (*s){

                        case '\n':
                                str_put_string_len (send_buf, "\r\n", 2);
                                s++;
                                after_newline (& s, & header);
                                break;
                        
                        default:
                                str_put_char (send_buf, *s);
                                s++;
                                break;
                }
        }
        str_put_string_len (send_buf, "\r\n.\r\n", 5);
}



bool
Smtp::load_file (const char *fname)
{
        char   *buf;
        size_t  size;
        FILE *fp = fopen (fname, "r");

        if (fp == NULL){
                error_ (errno, "%s", fname);
                return false;
        }

        if (file_whole (fp, & buf, & size)){
                fclose (fp);
                error_ (errno, "%s", fname);
                return false;
        }

        if (send_buf->size < size * 2){
                str_destroy (send_buf);
                send_buf = str_create_size (size * 2 + 5);
        }

        copy_buf (buf);
        xfree (buf);
        return true;
}



void
Smtp::parse_extension (char *s)
{
        char *seek;
        
        if (strstr (s, "SIZE") == s || strstr (s, "size") == s){
                ext_size = 1;
                seek = s + 4;
                while (*seek && isspace (*seek))
                        seek++;
                if (isdigit (*seek))
                        max_size = atoi (seek);
                return;
        }

        if (strcmp (s, "PIPELINING") == 0 || strcmp (s, "pipelining") == 0){
                ext_pipeline = 1;
                return;
        }

        if (strcmp (s, "8BITMIME") == 0 || strcmp (s, "8bitmime") == 0){
                ext_8bitmime = 1;
                return;
        }

        if (strstr (s, "AUTH") == s || strstr (s, "auth") == s){
                ext_auth = 1;

                if (strstr (s, "CRAM-MD5") || strstr (s, "cram-md5")){
                        auth = AUTH_CRAM_MD5;
                }
                else if (strstr (s, "LOGIN") || strstr (s, "login")){
                        auth = AUTH_LOGIN;
                }
                else if (strstr (s, "PLAIN") || strstr (s, "plain")){
                        auth = AUTH_PLAIN;
                }
                else {
                        auth = AUTH_NONE;
                }
                return;
        }
}



void
Smtp::parse_extensions (char *msg)
{
        int        i;
        rstring_t *exts;

        exts = rstring_split_re (msg, "\r\n([0-9]{3,3}[ \\-])?");

        if (exts == NULL)
                return;

        for (i = 1; i < exts->count; i++){
                parse_extension (exts->array[i]);
        }

        rstring_delete (exts);
}



bool
Smtp::parse_answer (char *msg, int d)
{
        char *seek;
        
        if (*msg == d)
                return true;

        if (error_message)
                str_destroy (error_message);

        seek = strchr (msg, '\r');
        if (seek)
                *seek = '\0';
        
        error_message = str_dup (msg + 4);

        if (seek)
                *seek = '\r';
        return false;
}


void
Smtp::report_error (const char *str)
{
        if (error_message){
                error_ (0, "%s (%s)", str, error_message->str);
        }
        else {
                error_ (0, "%s", str);
        }
}



void
Smtp::s_sent (char *msg, int len)
{
        str_t *str;
        char  *box_sent = mybox_sent ();
        
        if (! parse_answer (msg, '2')){
                str = str_create ();
                str_sprintf (str, "%s (%s)", _("Couldn't transmit message."),
                             mail->subject);
                report_error (str->str);
                str_destroy (str);
        }

        mail->flags &= ~ FLAG_READ;
        if (wrapbox_move_mail_to (mail, box_sent)){
                str = str_create ();
                str_sprintf (str, _("Couldn't move message to %s. (%s)"),
                             box_sent, mail->subject);
                error_ (errno, str->str);
                str_destroy (str);
        }

        xfree (box_sent);
        
        PICK_NEXT ();
}



void
Smtp::s_data (char *msg, int len)
{
        char  *fname;
        str_t *str;
        
        if (! parse_answer (msg, '3')){
                str = str_create ();
                str_sprintf (str, "%s (%s)", _("Couldn't transmit message"),
                             mail->subject);
                report_error (str->str);
                str_destroy (str);
                PICK_NEXT ();
        }

        fname = wrapbox_fetch_single (mail);
        if (! load_file (fname)){
                xfree (fname);
                PICK_NEXT ();
        }

        xfree (fname);

        state = SMTP_SENT;

        send_progress (_("sending message %d"), sent + 1);
        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::s_rcpt_to (char *msg, int len)
{
        str_t *str;
        
        if (! parse_answer (msg, '2')){
                str = str_create ();
                str_sprintf (str, _("This address has been rejected "
                                    "by server: %s."), recepient->email);
                report_error (str->str);
                str_destroy (str);
        }
        else {
                accepted++;
        }

        tried++;
        pick_recepient ();
}


void
Smtp::s_mail_from (char *msg, int len)
{
        if (! parse_answer (msg, '2')){
                report_error (_("Your email address has been rejected. "
                                "Message not sent."));
                PICK_NEXT ();
        }

        pick_recepient ();
}


void
Smtp::s_ehlo (char *msg, int len)
{
        char *user;
        char *pass;
        
        if (! parse_answer (msg, '2')){
                send_helo ();
                return;
        }

        parse_extensions (msg);

        if (ext_auth && auth != AUTH_NONE){
                user = ask_get_field (ask, "username");
                pass = ask_get_field (ask, "password");

                if (user && pass){
                        send_auth ();
                        return;
                }
        }

        send_mail_from ();
}


void
Smtp::s_helo (char *msg, int len)
{
        if (! parse_answer (msg, '2')){
                PICK_NEXT ();
        }

        send_mail_from ();
}


void
Smtp::s_auth_final (char *msg, int len)
{
        if (! parse_answer (msg, '2')){
                report_error (_("Authorization has failed."));
                PICK_NEXT ();
        }

        send_mail_from ();
}



void
Smtp::s_auth_cram_md5 (char *msg, int len)
{
        int     tmp_len;
        char   *tmp;
        char   *user;
        char   *pass;
        char   *seek;
        str_t  *challenge;
        str_t  *answer;
        str_t  *result;
        mime_t  mime;
        int     pass_len;
        int     user_len;
        int     i;

        unsigned char digest[16];
        
        seek = strchr (msg, ' ');
        if (seek == NULL){
                error_ (0, "%s", _("Server has sent an invalid "
                                   "authorization challenge."));
                PICK_NEXT ();
        }
        else
                seek++;

        mime.off_start = 0;
        mime.off_end   = len - (seek - msg);
        mime.encoding  = MENC_BASE64;
        mime.charset   = NULL;
        
        challenge = mime_decode (& mime, seek, 0);
        user      = ask_get_field (ask, "username");
        pass      = ask_get_field (ask, "password");
        pass_len  = strlen (pass);
        user_len  = strlen (user);

        hmac_md5 ((unsigned char *) challenge->str, challenge->len,
                  (unsigned char *) pass, pass_len, digest);

        answer = str_create_size (user_len + 1 + 32 + 1);
        str_sprintf (answer, "%s ", user);
        for (i = 0; i < 16; i++)
                str_sprintf (answer, "%02x", (unsigned char) digest[i]);

        tmp_len = answer->len;
        tmp     = str_finished (answer);
        result  = mime_encode (& mime, tmp, tmp_len);

        str_clear (send_buf);
        str_sprintf (send_buf, "%s\r\n", result->str);

        str_destroy (result);
        str_destroy (challenge);
        
        state = SMTP_AUTH_FINAL;
        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}



void
Smtp::s_auth_plain (char *msg, int len)
{
        char  *user;
        char  *pass;
        char  *answer;
        str_t *encoded;
        mime_t mime;
        int    pass_len;
        int    user_len;
        int    s_len;

        user     = ask_get_field (ask, "username");
        pass     = ask_get_field (ask, "password");
        user_len = strlen (user);
        pass_len = strlen (pass);
        s_len    = 1 + user_len + 1 + pass_len + 1;
        
        answer   = (char *) xmalloc (s_len);
        sprintf (answer, "%c%s%c%s", '\0', user, '\0', pass);

        mime.encoding = MENC_BASE64;
        encoded       = mime_encode (& mime, answer, s_len - 1);

        str_clear (send_buf);
        str_sprintf (send_buf, "%s\r\n", encoded->str);

        str_destroy (encoded);

        state = SMTP_AUTH_FINAL;
        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}



void
Smtp::s_auth_login_2 (char *msg, int len)
{
        char   *pass;
        str_t  *encoded;
        mime_t  mime;
        int     pass_len;

        if (! parse_answer (msg, '3')){
                report_error (_("Authorization has failed."));
                PICK_NEXT ();
        }
        
        pass          = xstrdup (ask_get_field (ask, "password"));
        pass_len      = strlen (pass);
        mime.encoding = MENC_BASE64;

        encoded = mime_encode (& mime, pass, pass_len);

        str_clear (send_buf);
        str_sprintf (send_buf, "%s\r\n", encoded->str);

        str_destroy (encoded);

        state = SMTP_AUTH_FINAL;
        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}



void
Smtp::s_auth_login (char *msg, int len)
{
        char   *user;
        str_t  *encoded;
        mime_t  mime;
        int     user_len;

        user          = xstrdup (ask_get_field (ask, "username"));
        user_len      = strlen (user);
        mime.encoding = MENC_BASE64;

        encoded = mime_encode (& mime, user, user_len);

        str_clear (send_buf);
        str_sprintf (send_buf, "%s\r\n", encoded->str);

        str_destroy (encoded);

        state = SMTP_AUTH_INTER;
        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}



void
Smtp::s_auth (char *msg, int len)
{
        if (! parse_answer (msg, '3')){
                report_error (_("Authorization has failed."));
                PICK_NEXT ();
        }

        switch (auth){

                case AUTH_NONE:
                        break;

                case AUTH_CRAM_MD5:
                        s_auth_cram_md5 (msg, len);
                        break;

                case AUTH_PLAIN:
                        s_auth_plain (msg, len);
                        break;

                case AUTH_LOGIN:
                        s_auth_login (msg, len);
                        break;
        }
}


void
Smtp::s_greeting (char *msg, int len)
{
        if (! parse_answer (msg, '2')){
                report_error (_("Connection has been rejected."));
                PICK_NEXT ();
        }

        send_ehlo ();
}


void
Smtp::s_disconnected (void)
{
        int   secure;
        int   port;
        char *host;
        
        if (mail == NULL){
                state = SMTP_READY;
                return;
        }

        host   = ask_get_field (ask, "server");
        secure = ask_get_field_int_default (ask, "ssl", 0);
        port   = ask_get_field_int_default (ask, "port", (secure) ? 465 : 25);

        if (host == NULL){
                error_ (0, "%s", _("Server field in smtp_acc is "
                                   "not defined."));
                PICK_NEXT ();
        }

        if (! open (host, port, secure)){
                PICK_NEXT ();
        }

        state = SMTP_GREETING;
        net_recv (TERMINATOR_RE);
}


void
Smtp::s_quit (char *msg, int len)
{
        if (! parse_answer (msg, '2')){
                report_error (_("Does your server love you so much?"));
        }

        close ();
}


void
Smtp::pick_recepient (void)
{
        recepient = next_recepient ();

        if (recepient)
                send_rcpt_to ();
        else if (accepted > 0)
                send_data ();
        else
                PICK_NEXT ();
}


void
Smtp::pick_server (void)
{
        char *name;
        
        if (ask == NULL){
                error_ (0, "%s", _("No SMTP account has been defined."));
                cleanup ();
                return;
        }

        name = ask_get_field (ask, "name");
        if (name == NULL){
                error_ (0, "%s", _("The name field in smtp_acc is "
                                   "not defined."));
                PICK_NEXT ();
        }
        if (mail->smtp == NULL){
                if (mail->subject)
                        error_ (0, _("No smtp for message %d (subject: %s)."),
                                sent + 1, mail->subject);
                else
                        error_ (0, _("No smtp for message %d."),
                                sent + 1);
                PICK_NEXT ();
        }
        
        if (! is_connected ()){
                ask_change_where (ask, "name", mail->smtp);
                state = SMTP_DISCONNECTED;
                s_disconnected ();
                return;
        }

        if (strcmp (mail->smtp, name) == 0){
                send_mail_from ();
                return;
        }

        send_quit ();
}


void
Smtp::pick_message (void)
{
        tried     = 0;
        accepted  = 0;
        recepient = NULL;
        mail      = mail_array_get (marray, sent);

        if (mail == NULL && ! is_connected ()){
                cleanup ();
                return;
        }

        if (mail == NULL){
                send_quit ();
                return;
        }

        pick_server ();
}


void
Smtp::send_ehlo (void)
{
        state = SMTP_EHLO;
        
        str_clear (send_buf);
        str_sprintf (send_buf, "EHLO %s\r\n", hostname);

        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::send_helo (void)
{
        state = SMTP_HELO;
        
        str_clear (send_buf);
        str_sprintf (send_buf, "HELO %s\r\n", hostname);

        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::send_auth (void)
{
        state = SMTP_AUTH;

        str_clear (send_buf);
        str_sprintf (send_buf, "AUTH %s\r\n", auth_str [auth]);

        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::send_mail_from (void)
{
        char *email;
        
        email = ask_get_field (ask, "email");
        if (email == NULL){
                error_ (0, "%s", _("The email field in smtp_acc is"
                                   "not defined."));
                send_quit ();
                return;
        }

        state = SMTP_MAIL;

        str_clear (send_buf);
        str_sprintf (send_buf, "MAIL FROM:<%s>\r\n", email);

        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::send_rcpt_to (void)
{
        state = SMTP_RCPT;

        str_clear (send_buf);
        str_sprintf (send_buf, "RCPT TO:<%s>\r\n", recepient->email);

        combo (send_buf->str, send_buf->len, TERMINATOR_RE);
}


void
Smtp::send_data (void)
{
        state = SMTP_DATA;
        combo ("DATA\r\n", 6, TERMINATOR_RE);
}


void
Smtp::send_quit (void)
{
        state = SMTP_QUIT;
        combo ("QUIT\r\n", 6, TERMINATOR_RE);
}


void
Smtp::recv_fun (char *msg, int len)
{
        switch (state){

                case SMTP_QUIT:
                        s_quit (msg, len);
                        break;

                case SMTP_SENT:
                        s_sent (msg, len);
                        break;
                
                case SMTP_DATA:
                        s_data (msg, len);
                        break;

                case SMTP_RCPT:
                        s_rcpt_to (msg, len);
                        break;

                case SMTP_MAIL:
                        s_mail_from (msg, len);
                        break;

                case SMTP_AUTH:
                        s_auth (msg, len);
                        break;

                case SMTP_AUTH_INTER:
                        s_auth_login_2 (msg, len);
                        break;

                case SMTP_AUTH_FINAL:
                        s_auth_final (msg, len);
                        break;

                case SMTP_HELO:
                        s_helo (msg, len);
                        break;

                case SMTP_EHLO:
                        s_ehlo (msg, len);
                        break;

                case SMTP_DISCONNECTED:
                        s_disconnected ();
                        break;

                case SMTP_GREETING:
                        s_greeting (msg, len);
                        break;
        }
}


void
Smtp::cleanup (void)
{
        if (ask)
                ask_destroy (ask);
        ask = NULL;

        if (send_buf)
                str_destroy (send_buf);
        send_buf = NULL;

        if (error_message)
                str_destroy (error_message);
        error_message = NULL;

        if (marray)
                mail_array_destroy (marray);
        marray = NULL;
}


void
Smtp::init (void)
{
        state         = SMTP_READY;
        marray        = NULL;

        sent          = 0;
        tried         = 0;
        accepted      = 0;

        mail          = NULL;
        recepient     = NULL;

        ask           = NULL;
        send_buf      = str_create ();
        error_message = NULL;

        auth          = AUTH_NONE;
        
        ext_auth      = 0;
        ext_size      = 0;
        ext_pipeline  = 0;
        ext_8bitmime  = 0;
        max_size      = 0;
}


void
Smtp::on_shutdown (void)
{
        state = SMTP_DISCONNECTED;

        s_disconnected ();
}

/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


void
smtp_init (void)
{
        gethostname (hostname, HOST_NAME_MAX);
        hostname[HOST_NAME_MAX] = '\0';

        smtp = new Smtp ();
}



void
smtp_free_resources (void)
{
        if (smtp)
                delete (smtp);

        smtp = NULL;
}


void
smtp_flush_outbox (void)
{
        if (smtp == NULL)
                return;
        
        if (! smtp->ready ()){
                error_ (0, "%s", _("Connection in progress."));
                return;
        }

        smtp->run ();
}


void
smtp_cancel (void)
{
        if (smtp == NULL || smtp->ready ())
                return;

        smtp->cancel ();
}


/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/

Smtp::Smtp (void) : Net ()
{
        init ();
}


Smtp::~Smtp (void)
{
        cleanup ();
}


void
Smtp::run (void)
{
        char *outbox;

        cleanup ();
        init ();

        ask    = ask_select_default ("smtp_acc");
        outbox = mybox_outbox ();
        if (outbox == NULL)
                return;

        marray = wrapbox_open_box (outbox);

        if (marray == NULL){
                error_ (0, _("Couldn't open folder %s."), outbox);
                xfree (outbox);
                return;
        }
        xfree (outbox);

        mail_array_sort_smtp (marray);

        pick_message ();
}


void
Smtp::cancel (void)
{
        close ();
        state = SMTP_READY;
}


bool
Smtp::ready (void)
{
        return state == SMTP_READY;
}

/****************************************************************************
 *
 *    END MODULE smtp.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1