/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 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.  

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

   mail fetching window
   
*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>

#include "ecurses.h"
#include "pop.h"
#include "error.h"
#include "select.h"
#include "xmalloc.h"
#include "wrapbox.h"
#include "misc.h"
#include "cmd.h"
#include "file.h"
#include "ask.h"
#include "fetch.h"
#include "gettext.h"
#include "mybox.h"
#include "eprintf.h"
#include "interface.h"
#include "color.h"
#include "label.h"
#include "mlex.h"
#include "procmail.h"

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

#define WINDOW_WIDTH COLS - 6

#define PREAMBLE do { if (fetch_select == NULL) return; } while (0)

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

struct list {
        struct list *next;
        int          index;
};

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

static struct {
        char *fname;            /* destination file name */
        FILE *fp;               /* destination file pointer */
        int   fetched;          /* total messages fetched */
        int   total_count;      /* total messages at the server */
        int   index;            /* index of the message to be fetched / deleted */

        struct list *to_fetch;  /* list of messages to be fetched */
} conn;

/* Fetch window consists of select_t object, and an optional label. */
static elabel_t *label        = NULL;
static select_t *fetch_select = NULL;

/* This is used to get account configuration. */
static ask_t *fetch_ask = NULL;

/* Format used when displaing messages in fetch window. */
static char *fetch_fmt = "%?%$  %D %016f (%-06S)  %s";

/* Color used in fetch window. */
static chtype text_color;

/* Used in draw_line. */
static str_t *line_str = NULL;

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/

int fetch_got_mail = 0;

/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/


static void 
cleanup (void)
{
        if (conn.fp)
                fclose (conn.fp);
        if (conn.fname){
                unlink (conn.fname);
                xfree (conn.fname);
        }
        if (fetch_ask)
                ask_destroy (fetch_ask);

        fetch_got_mail = 0;
        fetch_ask      = NULL;

        conn.fname       = NULL;
        conn.fp          = NULL;
        conn.fetched     = -1;
        conn.total_count = -1;

        if (fetch_select)
                window_hide (fetch_select->win);
}



static void
deliver_mail (void)
{
        char *box;
        
        if (conn.fname && conn.fp){
                rewind (conn.fp);
                yyin = conn.fp;
                mlex_scan_file (0);
                fclose (conn.fp);

                box = procmail_box (newmail);
                wrapbox_deliver_to (conn.fname, box);
                mail_destroy (newmail, BOX_INVALID);
                xfree (box);
                xfree (conn.fname);
        }
        conn.fname = NULL;
        conn.fp    = NULL;
}



static void
get_next (void)
{
        conn.fetched++;
        
        if (conn.fetched >= conn.total_count){
                deliver_mail ();
                pop_save_list ();
                pop_close (cleanup, cleanup);
                return;
        }

        deliver_mail ();
        
        while (1){
                conn.fname = wrapbox_fetch_where (1);
                conn.fp    = file_open (conn.fname, "w+",
                                        O_RDWR | O_CREAT | O_EXCL, 0600);
                if (conn.fp == NULL && errno == EEXIST)
                        xfree (conn.fname);
                else
                        break;
        }

        if (conn.fp == NULL){
                xfree (conn.fname);
                error_ (0, _("couldn't open file %s"), conn.fname);
                pop_close (cleanup, cleanup);
                return;
        }

        pop_retr (conn.fetched + 1, conn.fp, get_next, cleanup);
}



static void
merge_lists (void)
{
        pop_load_list ();
        pop_merge_lists ();
        get_next ();
}



static void
uidl_then_next (void)
{
        pop_uidl (merge_lists, cleanup);
}



static void
action_all (void)
{
        conn.fetched     = -1;
        conn.total_count = pop_maildrop_count ();

        pop_list (uidl_then_next, cleanup);
}



static void
open_window (void)
{
        if (pop_header_count () < 1){
                error_ (0, "%s", _("no new messages"));
                pop_close (cleanup, cleanup);
                return;
        }
        
        window_show (fetch_select->win);
        fetch_redraw ();
}



static void
get_infos (void)
{
        pop_load_list ();
        pop_merge_lists ();
        pop_get_infos (open_window, cleanup);
}



static void
uidl_then_infos (void)
{
        pop_uidl (get_infos, cleanup);
}



static void
action_win (void)
{
        pop_list (uidl_then_infos, cleanup);
}


static int
open_connection (void (*action)(void))
{
        int   port = 0;
        char *host;
        char *user;
        char *pass;
        int   method;
        int   secure;
        char *s_port;
        enum auth_method m;
        
        cleanup ();
        
        fetch_ask = ask_select ("pop_acc");

        if (fetch_ask == NULL)
                return 1;

        host   = ask_get_field (fetch_ask, "server");
        user   = ask_get_field (fetch_ask, "username");
        pass   = ask_get_field (fetch_ask, "password");
        s_port = ask_get_field (fetch_ask, "port");
        method = ask_get_field_int_default (fetch_ask, "use_apop", 0);
        secure = ask_get_field_int_default (fetch_ask, "ssl", 0);

        if (s_port)
                port = atoi (s_port);

        if (host == NULL){
                error_ (0, _("server field in pop_acc not defined"));
                ask_destroy (fetch_ask);
                fetch_ask = NULL;
                return 1;
        }

        if (user == NULL){
                error_ (0, _("username field in pop_acc not defined"));
                ask_destroy (fetch_ask);
                fetch_ask = NULL;
                return 1;
        }

        if (pass == NULL){
                error_ (0, _("password field in pop_acc not defined"));
                ask_destroy (fetch_ask);
                fetch_ask = NULL;
                return 1;
        }

        if (method)
                m = AUTH_APOP;
        else
                m = AUTH_PLAIN;

        return pop_open (host, port, user, pass, m, secure, action, cleanup);
}



static void
retr_succ (void)
{
        mail_t *mail = pop_header_info (conn.index);

        deliver_mail ();
        
        if (mail == NULL)
                return;

        mail->flags |= FLAG_FETCHED;
        fetch_redraw ();
}



static void
retr_fail (void)
{
        if (conn.fp)
                fclose (conn.fp);
        conn.fp = NULL;

        if (conn.fname){
                unlink (conn.fname);
                xfree (conn.fname);
        }
        conn.fname = NULL;
}


static void
dele_succ (void)
{
        mail_t *mail = pop_header_info (conn.index);

        mail->flags |= FLAG_TRASHED;
        fetch_redraw ();
}



static void
rset_succ (void)
{
        int     i;
        int     count = pop_header_count ();
        mail_t *mail;

        for (i = 0; i < count; i++){
                mail         = pop_header_info (i);
                mail->flags &= ~ FLAG_TRASHED;
        }
        fetch_redraw ();
}



static void
draw_line (WINDOW *win, int maxlen, int index, search_t *search)
{
        mail_t *mail = pop_header_info (index);

        if (line_str == NULL)
                line_str = str_create ();

        if (mail == NULL)
                str_clear (line_str);
        else
                eprintf_mail_str (fetch_fmt, mail, line_str);

        maxlen -= window_addnstr (win, line_str->str, maxlen);
        while (maxlen-- > 0)
                window_addch (win, ' ');
}



static int
count (select_t *nothing)
{
        return pop_header_count ();
}


/* This file is generated by interface.pl script from interface.desc,
   and inc.in. */
static WINDOW *interface_init (void);
#include "fetch.inc"


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


void
fetch_init (void)
{
        WINDOW *window;

        window       = interface_init ();
        fetch_select = select_open (window, 0, draw_line, count);

        window_set_functions (window, fetch_show, fetch_redraw,
                              fetch_set_focus, fetch_unset_focus);
}



void
fetch_free_resources (void)
{
        if (fetch_select)
                select_close (fetch_select);
        fetch_select = NULL;

        if (label)
                label_destroy (label);
        label = NULL;

        if (line_str)
                str_destroy (line_str);
        line_str = NULL;
}



void
fetch_all (void)
{
        open_connection (action_all);
}




void
fetch_get_rest (void)
{
        
}



void
fetch_show (void)
{
        select_show (fetch_select);
        label_show (label);
}



void
fetch_redraw (void)
{
        select_redraw (fetch_select);
        label_redraw (label);
}



void
fetch_set_focus (void)
{
        label_set_focus (label);
        cmd_state_push (CMD_FETCH);

        fetch_redraw ();
}



void
fetch_unset_focus (void)
{
        label_unset_focus (label);
        label_redraw (label);

        cmd_state_pop ();
}



void
fetch_open (void)
{
        open_connection (action_win);
}



void
fetch_open_all (void)
{

}



void
fetch_close (void)
{
        pop_save_list ();
        pop_close (cleanup, cleanup);
}



void
fetch_next (void)
{
        select_next (fetch_select);
}



void
fetch_prev (void)
{
        select_prev (fetch_select);
}



void
fetch_next_page (void)
{
        select_next_page (fetch_select);
}



void
fetch_prev_page (void)
{
        select_prev_page (fetch_select);
}



void
fetch_first (void)
{
        select_first (fetch_select);
}



void
fetch_last (void)
{
        select_last (fetch_select);
}



void
fetch_rset (void)
{
        pop_rset (rset_succ, NULL);
}



void
fetch_del_all (void)
{

}



void
fetch_del_mail (void)
{
        int num;

        conn.index = fetch_select->bar_pos;
        num        = pop_num (conn.index);
        
        pop_dele (num, dele_succ, NULL);
}



void
fetch_get_mail (void)
{
        int num;
        
        conn.index = fetch_select->bar_pos;
        num        = pop_num (conn.index);

        while (1){
                conn.fname = wrapbox_fetch_where (1);
                conn.fp    = file_open (conn.fname, "w+",
                                        O_RDWR | O_CREAT | O_EXCL, 0600);
                if (conn.fp == NULL && errno == EEXIST)
                        xfree (conn.fname);
                else
                        break;
        }

        if (conn.fp == NULL){
                error_ (0, _("couldn't open file %s"), conn.fname);
                xfree (conn.fname);
                conn.fname = NULL;
                pop_close (cleanup, cleanup);
                return;
        }
        
        pop_retr (num, conn.fp, retr_succ, retr_fail);
}


void
fetch_mark_mail (void)
{
        pop_mark_mail (fetch_select->bar_pos);
}



void
fetch_unmark_mail (void)
{

}



void
fetch_mark_all (void)
{

}



void
fetch_unmark_all (void)
{

}



void
fetch_remove_till_limit (void)
{
}



void
fetch_remove_till_count (void)
{
}

/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE fetch.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1