/* 
   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 is very simple module used to get full list of messages from
   file in mbox format.

*/

#define _GNU_SOURCE 1


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

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>

#include "xmalloc.h"
#include "mail.h"
#include "mbox.h"
#include "hash.h"
#include "mlex.h"
#include "file.h"
#include "error.h"
#include "gettext.h"
#include "clock.h"
#include "maildir.h"
#include "misc.h"

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

#ifndef P_tmpdir
# define P_tmpdir "/tmp"
#endif


#define MAIL_BEG_RE "^From "

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/
/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


int
mbox_may_be_valid (const char *fname)
{
        struct stat st;

        if (stat (fname, &st)){
                error_ (errno, "%s", fname);
                return 0;
        }

        if (S_ISREG (st.st_mode))
                return 1;
        return 0;
}



int
mbox_mail_size (mail_t *mail)
{
        mime_t *mime = mail->mime->mime;

        return mime->off_bound - mime->off_header;
}
    


mail_array_t *
mbox_read_file (const char *file)
{
        struct stat   st;
        int           ret = 0;
        mail_array_t *result;

        if (stat (file, &st)){
                error_ (errno, "%s", file);
                return NULL;
        }

        if (! S_ISREG (st.st_mode) || st.st_size == 0)
                return NULL;
  
        yyin = fopen (file, "r");
        if (!yyin){
                error_ (errno, "%s", file);
                return NULL;
        }
  
        /* first invocation of mbox_scan tells us only if we are reading
           a mailbox; it does not bring any information yet */
        if (mlex_mbox_scan_start () != NEXT_MAIL){
                fclose (yyin);
                return NULL;
        }

        result = mail_array_create (BOX_MBOX, file);

        while (ret != END_OF_FILE){
    
                ret = mlex_scan ();

                switch (ret){

                        case NEXT_MAIL:
                                newmail->type       = BOX_MBOX;
                                newmail->mime->file = result->path;
                                mail_array_insert (result, newmail);
                                break;

                        case BROKEN_MAIL:
                                fclose (yyin);
                                mail_array_destroy (result);
                                return NULL;
                }
        }
        fclose (yyin);
        return result;
}



int
mbox_mail_header (mail_t *mail, char **place, const char *fname)
{
        mime_t *mime = mail->mime->mime;
        
        if (file_part (fname, mime->off_header, mime->off_start, place)){
                *place = NULL;
                return 1;
        }
        return 0;
}



int
mbox_mail_body (mail_t *mail, char **place, mime_t *mime, const char *fname)
{
        if (file_part (fname, mime->off_start, mime->off_end, place)){
                *place = NULL;
                return 1;
        }
        return 0;
}



char *
mbox_fetch_single (const char *mbox, mail_t *mail)
{
        int     size;
        char   *dir = P_tmpdir;
        char   *path;
        char   *fname;
        char   *body;
        mime_t *mime;
        FILE   *fp;

        if (mbox == NULL || mail == NULL || mail->mime == NULL)
                return NULL;

        mime = mail->mime->mime;
        size = mime->off_bound - mail->place.offset_header;

        if (file_part (mbox, mail->place.offset_header, mime->off_bound,
                       & body))
                return NULL;

        fname = maildir_valid_file_name ();
        path  = file_with_dir (dir, fname);

        xfree (fname);

        fp = file_open (path, "w", O_WRONLY | O_CREAT | O_EXCL, 0600);
        if (fp == NULL){
                xfree (body);
                xfree (path);
                return NULL;
        }

        if (fwrite (body, 1, size, fp) != size){
                fclose (fp);
                xfree (body);
                xfree (path);
                return NULL;
        }

        fclose (fp);
        xfree (body);
        return path;
}



int
mbox_box_mail_count (const char *box, int *unread)
{
        FILE       *fp;
        int         ret;
        int         size;
        int         count;
        char       *body;
        char       *seek;
        regmatch_t  matches[1];

        if (! mbox_may_be_valid (box))
                return -1;
        
        fp = fopen (box, "r");
        if (fp == NULL)
                return -1;

        if (file_whole (fp, & body, & size)){
                fclose (fp);
                return -1;
        }

        fclose (fp);

        if (unread)
                *unread = 0;
        count = 0;
        seek  = body;
        while (1){
                ret = misc_regex (MAIL_BEG_RE, seek, matches);
                if (ret == 0)
                        break;
                seek = seek + matches[0].rm_eo;
                count++;
        }

        xfree (body);
        return count;
}


void
mbox_free_resources (void)
{

}

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


syntax highlighted by Code2HTML, v. 0.9.1