static char rcsid[] = "@(#)$Id: canceled_mail.c,v 1.16 2006/07/23 08:47:23 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.16 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
*****************************************************************************/
#include "def_messages.h"
#include "s_elm.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"messages");
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static struct MailboxView *canceled_mail_view = NULL;
struct mv_canceldir {
char * dirname;
char * indexname;
FILE * index_F;
charset_t cs;
time_t last_scan;
time_t last_mtime;
struct message_list {
char * filename;
struct header_rec REC;
} * message_list;
int message_list_len;
int last_open_index;
FILE * last_open_file;
};
S_(mt_init_mailbox mt_init_canceldir)
static void mt_init_canceldir P_((struct MailboxView *mbx));
static void mt_init_canceldir(mbx)
struct MailboxView *mbx;
{
mbx->u.canceldir = safe_malloc(sizeof (* (mbx->u.canceldir)));
/* bzero is defined hdrs/defs.h */
bzero((void *)mbx->u.canceldir, sizeof (* (mbx->u.canceldir)));
mbx->u.canceldir->dirname = NULL;
mbx->u.canceldir->indexname = NULL;
mbx->u.canceldir->index_F = NULL;
mbx->u.canceldir->cs = NULL;
mbx->u.canceldir->last_scan = 0;
mbx->u.canceldir->last_mtime = 0;
mbx->u.canceldir->message_list = NULL;
mbx->u.canceldir->message_list_len = 0;
mbx->u.canceldir->last_open_index = -1;
mbx->u.canceldir->last_open_file = NULL;
}
S_(mt_free_mailbox mt_free_canceldir)
static void mt_free_canceldir P_((struct MailboxView *mbx));
static void mt_free_canceldir(mbx)
struct MailboxView *mbx;
{
if (mbx->u.canceldir->dirname) {
free(mbx->u.canceldir->dirname);
mbx->u.canceldir->dirname = NULL;
}
if (mbx->u.canceldir->indexname) {
free(mbx->u.canceldir->indexname);
mbx->u.canceldir->indexname = NULL;
}
if (mbx->u.canceldir->index_F) {
fflush(mbx->u.canceldir->index_F);
Release_the_file(fileno(mbx->u.canceldir->index_F));
fclose(mbx->u.canceldir->index_F);
mbx->u.canceldir->index_F = NULL;
}
mbx->u.canceldir->cs = NULL;
if (mbx->u.canceldir->message_list) {
int i;
for (i = 0; i < mbx->u.canceldir->message_list_len; i++) {
if (mbx->u.canceldir->message_list[i].filename) {
free (mbx->u.canceldir->message_list[i].filename);
mbx->u.canceldir->message_list[i].filename = NULL;
}
header_clear ( & ( mbx->u.canceldir->message_list[i].REC) );
}
free(mbx->u.canceldir->message_list);
mbx->u.canceldir->message_list = NULL;
}
mbx->u.canceldir->message_list_len = 0;
mbx->u.canceldir->last_open_index = -1;
if (mbx->u.canceldir->last_open_file) {
fclose(mbx->u.canceldir->last_open_file);
mbx->u.canceldir->last_open_file = NULL;
}
free(mbx->u.canceldir);
mbx->u.canceldir = NULL;
/* Reset canceled_mail_view -pointer if we are going erase it */
if (canceled_mail_view == mbx)
canceled_mail_view = NULL;
}
static void mt_make_canceldir_view P_((struct MailboxView *mailbox));
S_(mt_add_mailbox_storage mt_add_canceldir_storage)
static void mt_add_canceldir_storage P_((struct MailboxView *mailbox,
struct current_storage *storage));
static void mt_add_canceldir_storage(mailbox,storage)
struct MailboxView *mailbox;
struct current_storage *storage;
{
panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_add_canceldir_storage",
"mt_add_canceldir_storage called",0);
}
static int process_index P_((struct MailboxView *view));
static void unlock_index P_((struct MailboxView *view));
static void unlock_index(view)
struct MailboxView *view;
{
if (!view->u.canceldir->index_F)
return;
fflush(view->u.canceldir->index_F);
Release_the_file(fileno(view->u.canceldir->index_F));
fclose(view->u.canceldir->index_F);
view->u.canceldir->index_F = NULL; /* Mark -- no locked */
}
static void update_index P_((struct MailboxView *v));
static void add_canceled_mail1 P_((char *filename,
struct mailing_headers * headers,
struct MailboxView *view,
time_t X,
int lines,
header_list_ptr h,
long body_offset));
static void move_olds P_((struct MailboxView *v));
#ifdef DIROPS
#if DIROPS == USE_DIRENT
#include <dirent.h>
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
#include <sys/dir.h>
#endif /* DIROPS == USE_SYSDIR */
static void update_index(v)
struct MailboxView *v;
{
DIR * handle;
struct stat dstat;
time_t now = time(NULL);
int unlock_it = 0;
#if DIROPS == USE_DIRENT
struct dirent * Xptr;
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
struct direct * Xptr;
#endif /* DIROPS == USE_SYSDIR */
if (0 != stat(v->u.canceldir->dirname,&dstat)) {
DPRINT(Debug,1,(&Debug,"stat %s failed!\n",
v->u.canceldir->dirname));
dstat.st_mtime = now;
}
if (dstat.st_mtime == v->u.canceldir->last_mtime &&
now < v->u.canceldir->last_scan + 60) {
DPRINT(Debug,7,(&Debug,"scan %s skipped\n",
v->u.canceldir->dirname));
return;
}
if (!v->u.canceldir->index_F) {
if (! process_index(v))
return;
unlock_it++;
}
v->u.canceldir->last_mtime = dstat.st_mtime;
v->u.canceldir->last_scan = now;
handle = opendir(v->u.canceldir->dirname);
if (!handle)
goto fail2;
while (NULL != (Xptr = readdir(handle))) {
if ('.' != Xptr->d_name[0]) {
struct stat X;
char *fullname;
int fd;
FILE *f1 = NULL;
header_list_ptr h = NULL;
long b;
int lines = 0;
int i,c;
#if DIROPS == USE_DIRENT
char * entryname = safe_strdup(Xptr->d_name);
#endif /* DIROPS == USE_DIRENT */
#if DIROPS == USE_SYSDIR
char * entryname = safe_malloc(Xptr->d_namlen+1);
strncpy(entryname,Xptr->d_name,Xptr->d_namlen);
entryname[Xptr->d_namlen] = '\0';
#endif /* DIROPS == USE_SYSDIR */
fullname = safe_strdup(v->u.canceldir->dirname);
fullname = strmcat(fullname,"/");
fullname = strmcat(fullname,entryname);
for (i = 0; i < v->u.canceldir->message_list_len; i++)
if ( 0 == strcmp(entryname,
v->u.canceldir->message_list[i].filename))
goto found;
fd = open(fullname,O_RDONLY);
if (fd < 0)
goto fail1;
if (-1 == fstat(fd,&X)) {
close(fd);
goto fail1;
}
if (X.st_uid != userid) {
/* Wrong owner */
close(fd);
goto fail1;
}
f1 = fdopen(fd,"r");
if (!f1) {
close(fd);
goto fail1;
}
h = file_read_headers(f1,RHL_CHECK_HEADER);
b = ftell(f1);
while (EOF != (c = getc(f1))) {
if ('\n' == c)
lines++;
}
add_canceled_mail1(entryname,
NULL,v,X.st_mtime,lines,h,b);
fail1:
if (h)
delete_headers(&h);
if (f1)
fclose(f1);;
found:
free(entryname);
free(fullname);
}
}
closedir(handle);
if (v == canceled_mail_view)
move_olds(v);
fail2:
if (unlock_it)
unlock_index(v);
}
#else
static void update_index(v)
struct MailboxView *v;
{
/* EMPTY */
}
#endif
/* Return 1 if redraw required */
S_(mt_update_view_mailbox mt_update_view_canceldir)
/* Return 1 if redraw required */
static int mt_update_view_canceldir P_((struct MailboxView *mailbox));
static int mt_update_view_canceldir(mailbox)
struct MailboxView *mailbox;
{
int count;
int i,x;
update_index(mailbox);
count = mailbox->u.canceldir->message_list_len;
if (count != mailbox->view_len) {
mt_make_canceldir_view(mailbox);
DPRINT(Debug,7,(&Debug,
"mt_update_view_canceldir=1 (%d messages)\n",
mailbox->view_len));
return 1;
}
DPRINT(Debug,7,(&Debug,
"mt_update_view_canceldir=0\n"));
return 0;
}
S_(mt_get_main_mailbox_folder mt_get_main_canceldir_folder)
static struct folder_info * mt_get_main_canceldir_folder P_((struct MailboxView *mailbox));
static struct folder_info * mt_get_main_canceldir_folder(mailbox)
struct MailboxView *mailbox;
{
return NULL;
}
/* Can be called from signal handler */
S_(mt_get_mailbox_storage mt_get_canceldir_storage)
/* Can be called from signal handler */
static struct current_storage * mt_get_canceldir_storage P_((struct MailboxView *mailbox,
int i));
/* Can be called from signal handler */
static struct current_storage * mt_get_canceldir_storage(mailbox,i)
struct MailboxView *mailbox;
int i;
{
return NULL;
}
/* Can be called from signal handler */
S_(mt_get_mailbox_storage_count mt_get_canceldir_storage_count)
/* Can be called from signal handler */
static int mt_get_canceldir_storage_count P_((struct MailboxView *mailbox));
/* Can be called from signal handler */
static int mt_get_canceldir_storage_count(mailbox)
struct MailboxView *mailbox;
{
return 1;
}
static int update_open P_((struct mv_canceldir *d, int idx));
static int update_open(d,idx)
struct mv_canceldir *d;
int idx;
{
if (d->last_open_index != idx &&
d->last_open_file) {
fclose(d->last_open_file);
d->last_open_file = NULL;
}
if (!d->last_open_file) {
char * filename = elm_message(FRM("%s/%s"),
d->dirname,
d->message_list[idx].
filename);
int err = can_open(filename,"r");
if (err) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
"Can't open %s!"),
filename);
free(filename);
return 0;
}
d->last_open_file = fopen(filename,"r");
if (!d->last_open_file) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
"Can't open %s!"),
filename);
free(filename);
return 0;
}
d->last_open_index = idx;
free(filename);
} else
rewind(d->last_open_file);
return 1;
}
static int update_header P_((struct mv_canceldir *d, int idx));
static int update_header(d,idx)
struct mv_canceldir *d;
int idx;
{
struct header_rec *hdr = & (d->message_list[idx].REC);
if (!update_open(d,idx)) {
DPRINT(Debug,10,(&Debug,"update_header: %d -- failed\n",
idx));
return 0;
}
if (! hdr->body_parsed) {
header_list_ptr parsed_headers =
file_read_headers(d->last_open_file,0);
long content_start;
if (!parsed_headers) {
DPRINT(Debug,3,(&Debug,
"update_header: No headers parsed! \n"));
}
read_folder_headers_helper(hdr,parsed_headers);
header_parse_helper(hdr,parsed_headers);
content_start = ftell(d->last_open_file);
start_body_helper(hdr,
content_start,parsed_headers);
delete_headers(&parsed_headers);
/* start_body_helper is called */
hdr->body_parsed = 1;
}
DPRINT(Debug,10,(&Debug,"update_header: %d -- OK\n",
idx));
return 1;
}
S_(mt_give_header_mailbox mt_give_header_canceldir)
static struct header_rec * mt_give_header_canceldir P_((struct MailboxView *mailbox,
int index,
struct folder_view *v));
static struct header_rec * mt_give_header_canceldir(mailbox,index,v)
struct MailboxView *mailbox;
int index;
struct folder_view *v;
{
int mbx,idx;
mbx = v->mailbox_number;
if (mbx != 0)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"mt_give_header_canceldir",
"Bad mailbox number",0);
idx = v->index;
if (idx < 0 || idx >= mailbox->u.canceldir->message_list_len)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"mt_give_header_canceldir",
"Bad internal index",0);
if (-1 == mailbox->u.canceldir->message_list[idx].
REC.mime_rec.begin_offset)
update_header(mailbox->u.canceldir,idx);
return & (mailbox->u.canceldir->message_list[idx].REC);
}
S_(sdt_give_header_s sdt_give_header_cm)
static struct header_rec * sdt_give_header_cm P_((struct sort_data *s,
struct folder_view *v));
static struct header_rec * sdt_give_header_cm(s,v)
struct sort_data *s;
struct folder_view *v;
{
return & (s->u.canceldir->message_list[v->index].REC);
}
static struct sort_data_type cm_sort = {
SORTDATATYPE_magic,
sdt_give_header_cm
};
S_(mt_sort_mailbox_view mt_sort_canceldir_view)
static void mt_sort_canceldir_view P_((struct MailboxView *mailbox,
hdr_compare_func *func));
static void mt_sort_canceldir_view(mailbox,func)
struct MailboxView *mailbox;
hdr_compare_func *func;
{
int i;
struct sort_data * array;
/* Little dirty ... */
typedef int (*compar) P_((const void *, const void *));
compar X = (compar) func;
array = safe_malloc(mailbox->view_len * sizeof (array[0]));
for (i = 0; i < mailbox->view_len; i++) {
int mbx = mailbox->view[i].mailbox_number;
array[i].w = mailbox->view[i];
array[i].t = mailbox->thread_view; /* For thread sorting */
array[i].sort_data_type = &cm_sort;
array[i].u.canceldir = mailbox->u.canceldir;
}
qsort(array,mailbox->view_len,sizeof (array[0]), X);
for (i = 0; i < mailbox->view_len; i++) {
mailbox->view[i] = array[i].w;
}
free(array);
}
/* XXX not good .... */
S_(mt_give_message_data_mailbox mt_give_message_data_canceldir)
static int mt_give_message_data_canceldir P_((struct MailboxView *mailbox,
int index,
struct header_rec **ret_header,
FILE **ret_F,
struct counter_data *counter,
parse_mime_callback *parse_mime,
struct folder_view *v));
static int mt_give_message_data_canceldir(mailbox,index,ret_header,ret_F,
counter,parse_mime,v)
struct MailboxView *mailbox;
int index;
struct header_rec **ret_header;
FILE **ret_F;
struct counter_data *counter;
parse_mime_callback *parse_mime;
struct folder_view *v;
{
struct header_rec *hdr;
int mbx,idx;
mbx = v->mailbox_number;
if (mbx != 0) {
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"mt_give_message_data_canceldir",
"Bad mailbox number",0);
return 0;
}
idx = v->index;
if (idx < 0 || idx >= mailbox->u.canceldir->message_list_len) {
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"mt_give_message_data_canceldir",
"Bad internal index",0);
return 0;
}
hdr = & (mailbox->u.canceldir->message_list[idx].REC);
/* hdr is also needed on error messages ... */
if (ret_header) {
if (-1 == hdr->mime_rec.begin_offset)
update_header(mailbox->u.canceldir,idx);
*ret_header = hdr;
DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- giving header\n",
idx));
}
if (ret_F) {
if (!update_header(mailbox->u.canceldir,idx)) {
DPRINT(Debug,6,(&Debug,"mt_give_message_data_canceldir: %d failed\n",
idx));
return 0;
}
/* Simulate prepare_message_access */
if (! hdr->mime_parsed &&
parse_mime == NO_mime_parse) {
DPRINT(Debug,10,(&Debug,
"mt_give_message_data_canceldir: mime structure not needed\n"));
} else if (! hdr->mime_parsed) {
int status;
DPRINT(Debug,10,(&Debug,
"mt_give_message_data_canceldir: Need parsing of mime structure (offset %ld)\n",
hdr->offset
));
if (0 != fseek(mailbox->u.canceldir->last_open_file,
hdr->offset,
SEEK_SET)) {
DPRINT(Debug,10,(&Debug,
"mt_give_message_data_canceldir: seek to %ld failed\n",
hdr->offset));
return 0;
}
status = parse_mime(NULL,hdr,
mailbox->u.canceldir->last_open_file);
if (status <= 0) {
DPRINT(Debug,10,(&Debug,
"mt_give_message_data_canceldir: parse_mime callback failed (%d)\n",
status));
}
}
rewind(mailbox->u.canceldir->last_open_file);
*ret_F = mailbox->u.canceldir->last_open_file;
DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- giving file\n",
idx));
}
DPRINT(Debug,10,(&Debug,"mt_give_message_data_canceldir: %d -- succeed\n",
idx));
return 1;
}
S_(mt_write_mailbox_info mt_write_canceldir_info)
static void mt_write_canceldir_info P_((FILE *fp, struct MailboxView *mailbox,
int s, int cur_idx));
static void mt_write_canceldir_info(fp,mailbox,s, cur_idx)
FILE *fp;
struct MailboxView *mailbox;
int s;
int cur_idx;
{
/* EMPTY */
}
S_(mt_mailbox_title mt_canceldir_title)
static struct string * mt_canceldir_title P_((struct MailboxView *mailbox));
static struct string * mt_canceldir_title(mailbox)
struct MailboxView *mailbox;
{
if (canceled_mail_view == mailbox) {
if (*hostname && menu_display_host)
return format_string(CATGETS(elm_msg_cat, ElmSet,
ElmCanceledMailsOn,
"Canceled mails on %s"),
hostname);
return format_string(CATGETS(elm_msg_cat, ElmSet,
ElmCanceledMails,
"Canceled mails"));
}
/* These two should not really be used ... */
if (*hostname && menu_display_host)
return format_string(CATGETS(elm_msg_cat, ElmSet,
ElmMDirectoryOn,
"Message directory %s on %s"),
mailbox->u.canceldir->dirname,
hostname);
return format_string(CATGETS(elm_msg_cat, ElmSet,
ElmMDirectory,
"Message directory %s"),
mailbox->u.canceldir->dirname);
}
S_(mt_make_mailbox_view mt_make_canceldir_view)
static void mt_make_canceldir_view (mailbox)
struct MailboxView *mailbox;
{
int count = mailbox->u.canceldir->message_list_len;
int i,x;
if (count < 1) {
if (mailbox->view)
free(mailbox->view);
mailbox->view = NULL;
mailbox->view_len = 0;
return;
}
mailbox->view =
safe_realloc(mailbox->view,
count * (sizeof ( mailbox->view[0])));
for (x = 0; x < count; x++) {
zero_folder_view(& (mailbox->view[x]));
mailbox->view[x].mailbox_number = 0;
mailbox->view[x].index = x;
}
mailbox->view_len = count;
}
S_(mt_add_mailbox_digest mt_add_canceldir_digest)
static void mt_add_canceldir_digest P_((struct MailboxView *mailbox,
mime_t *list,
time_t received_time,
char *env_from,
FILE *F,
charset_t defcharset
));
static void mt_add_canceldir_digest(mailbox, list, received_time, env_from, F,
defcharset
)
struct MailboxView *mailbox;
mime_t *list;
time_t received_time;
char *env_from;
FILE *F;
charset_t defcharset;
{
panic("MBX VIEW PANIC",__FILE__,__LINE__,"mt_add_canceldir_digest",
"mt_add_canceldir_digest called",0);
}
static struct mailbox_type mt_canceldir = {
MAILBOXTYPE_magic,
mt_init_canceldir,
mt_free_canceldir,
mt_add_canceldir_storage,
mt_update_view_canceldir,
mt_get_main_canceldir_folder,
mt_get_canceldir_storage,
mt_get_canceldir_storage_count,
mt_give_header_canceldir,
mt_sort_canceldir_view,
mt_give_message_data_canceldir,
mt_write_canceldir_info,
mt_canceldir_title,
mt_make_canceldir_view,
mt_add_canceldir_digest
};
/* ------------------------------------------------------------------------ */
static void index_initialize P_((struct MailboxView *view));
/* 1 == readed and locked, 0 = failure */
static int process_index(view)
struct MailboxView *view;
{
int count = 0;
int err = can_open(view->u.canceldir->indexname, "a");
int ret;
char buffer[20];
if (err) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
"Can't open %s!"),
view->u.canceldir->indexname);
return 0;
}
view->u.canceldir->index_F =
open_or_create(view->u.canceldir->indexname);
if (!view->u.canceldir->index_F) {
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmCantOpenFile,
"Can't open %s!"),
view->u.canceldir->indexname);
return 0;
}
ret = Grab_the_file(fileno(view->u.canceldir->index_F));
if (FLOCKING_RETRY == ret) {
lib_transient(CATGETS(elm_msg_cat, MeSet, MeLockingFile,
"Locking %s..."),
view->u.canceldir->indexname);
while (FLOCKING_RETRY == ret && count++ < 3) {
#if POLL_METHOD
wait_for_timeout(1);
#else
sleep(1);
#endif
ret = Grab_the_file(fileno(view->u.canceldir->index_F));
}
if (FLOCKING_OK == ret)
lib_transient(CATGETS(elm_msg_cat, MeSet, MeLockingFileOK,
"Locking %s... OK."),
view->u.canceldir->indexname);
if (FLOCKING_RETRY == ret) {
fclose(view->u.canceldir->index_F);
view->u.canceldir->index_F = NULL;
return 0;
}
}
if (FLOCKING_FAIL == ret) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeLockingFileFAIL,
"Locking %s... Failed."),
view->u.canceldir->indexname);
fclose(view->u.canceldir->index_F);
view->u.canceldir->index_F = NULL;
return 0;
}
if ((ret = mail_gets(buffer, sizeof buffer,
view->u.canceldir->index_F)) > 0) {
struct message_list * current = NULL; /* current index */
if (ret != 12 || 0 != memcmp(buffer,"ELMME+ MIDX\n",12)) {
DPRINT(Debug,7,(&Debug,
"process_index: Bad bagic (len %d): %.*s\n",
ret,ret,buffer));
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
"File %s is corrupted."),
view->u.canceldir->indexname);
Release_the_file(fileno(view->u.canceldir->index_F));
fclose(view->u.canceldir->index_F);
view->u.canceldir->index_F = NULL;
return 0;
}
/* malloc_gets reallocates buffer1 and do not return \n.
It returns -1 if line is longer than given limit (32000)
and -2 is returned on error (buffer may still be alloced)
*/
while (!feof(view->u.canceldir->index_F) &&
!ferror(view->u.canceldir->index_F) &&
ret >= 0) {
char * buffer1 = NULL;
ret = malloc_gets(&buffer1, 32000, view->u.canceldir->index_F);
if (ret < 0 || !buffer1)
goto fail;
if (ret >= 2) {
if (strcmp("--END",buffer1) == 0) {
/* Temporary terminator */
ret = -2;
goto fail;
}
if (0 == strncmp(buffer1,"C ",2)) {
view->u.canceldir->cs =
MIME_name_to_charset(buffer1+2,0);
goto next_line;
}
if (!view->u.canceldir->cs ||
' ' != buffer1[1]) {
DPRINT(Debug,7,(&Debug,
"process_index: Bad line (len %d): %.*s\n",
ret,ret,buffer1));
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
"File %s is corrupted."),
view->u.canceldir->indexname);
ret = -1;
goto fail;
}
switch (buffer1[0]) {
case 'F': {
char * fname = buffer1+2;
int i;
current = NULL;
for (i = 0; i < view->u.canceldir->message_list_len; i++)
if (0 == strcmp(view->u.canceldir->message_list[i].
filename,fname)) {
current = & (view->u.canceldir->
message_list[i]);
DPRINT(Debug,7,(&Debug,
"process_index: File %s already on index (%d)\n",
fname,i));
}
if (!current) {
DPRINT(Debug,7,(&Debug,
"process_index: Adding file %s to index\n",
fname));
view->u.canceldir->message_list =
safe_realloc(view->u.canceldir->message_list,
(view->u.canceldir->message_list_len+1) *
sizeof (view->u.canceldir->message_list[0]));
current = & (view->u.canceldir->
message_list[view->u.canceldir->message_list_len++]);
header_zero( & (current->REC));
current->filename = safe_strdup(buffer1+2);
/* Charset used by index writing code... */
current->REC.header_charset = view->u.canceldir->cs;
current->REC.offset = 0;
/* Default envelope sender */
if (view == canceled_mail_view)
strfcpy(current->REC.env_from,username,
sizeof (current->REC.env_from));
}
}
break;
case 'L':
if (!current) goto bad0;
current->REC.lines = atoi(buffer1+2);
break;
case 'T':
if (!current) goto bad0;
current->REC.received_time = atol(buffer1+2);
break;
case 'E':
if (!current) goto bad0;
strfcpy(current->REC.env_from,buffer1+2,
sizeof (current->REC.env_from));
break;
case 'f':
if (!current) goto bad0;
if (current->REC.from)
break;
current->REC.from = break_down_address(buffer1+2,0,view->u.canceldir->cs);
break;
case 't':
if (!current) goto bad0;
if (current->REC.to)
break;
current->REC.to = break_down_address(buffer1+2,0,view->u.canceldir->cs);
break;
case 'c':
if (!current) goto bad0;
if (current->REC.cc)
break;
current->REC.cc = break_down_address(buffer1+2,0,view->u.canceldir->cs);
break;
case 'M':
if (!current) goto bad0;
strfcpy(current->REC.messageid,buffer1+2,
sizeof (current->REC.messageid));
break;
case 'd':
if (!current) goto bad0;
current->REC.time_sent = atol(buffer1+2);
break;
case 'S':
if (!current) goto bad0;
if (current->REC.subject)
break;
current->REC.subject = hdr_to_string(HDR_TEXT,
buffer1+2,
view->u.canceldir->cs,
0);
break;
default:
bad0:
DPRINT(Debug,7,(&Debug,
"process_index: Bad line or token (len %d): %.*s\n",
ret,ret,buffer1));
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
"File %s is corrupted."),
view->u.canceldir->indexname);
ret = -1;
goto fail;
}
} else if (0 != ret) {
DPRINT(Debug,7,(&Debug,
"process_index: short line (len %d): %.*s\n",
ret,ret,buffer1));
lib_error(CATGETS(elm_msg_cat, MeSet, MeFileCorrupted,
"File %s is corrupted."),
view->u.canceldir->indexname);
ret = -1;
} else
current = NULL;
next_line:
fail:
if (buffer1) {
free(buffer1);
buffer1 = NULL;
}
}
} else {
/* Initialize file */
index_initialize(view);
}
return 1;
}
static void setup_canceldir P_((struct MailboxView *view, char *dir));
static void setup_canceldir(view,dir)
struct MailboxView *view;
char *dir;
{
if (&mt_canceldir!= view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"setup_canceldir",
"Bad type for canceldir view",0);
if (view->u.canceldir->dirname ||
view->u.canceldir->indexname ||
view->u.canceldir->index_F)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"setup_canceldir",
"canceldir view already set up",0);
DPRINT(Debug,8,(&Debug,
"setup_canceldir(view=%p,dir=%s)\n",
view,dir));
if (dir[0]) {
int err,ret;
char buffer[30];
view->u.canceldir->dirname = safe_strdup(dir);
view->u.canceldir->indexname =
elm_message(FRM("%s/.index"),dir);
/* Is directory created yet ? */
if (access(dir, WRITE_ACCESS) < 0) {
int err = errno;
if (ENOENT == err)
return;
lib_error(CATGETS(elm_msg_cat, ElmSet,ElmErrorAccess,
"%.45s: %.33s"),
dir,error_description(err));
return;
}
process_index(view);
}
}
static struct addr_item *dup_addr_list P_((struct addr_item *list));
static struct addr_item *dup_addr_list(list)
struct addr_item *list;
{
int L = 0;
struct addr_item *ptr;
int i;
for (ptr=list; ptr->addr && ptr->fullname; ptr++)
L++;
ptr = safe_malloc((L+1) * sizeof (ptr[0]));
for (i = 0; i < L; i++) {
ptr[i].addr = safe_strdup(list[i].addr);
ptr[i].fullname = dup_string(list[i].fullname);
ptr[i].comment = NULL;
if (list[i].comment)
ptr[i].comment = dup_string(list[i].comment);
}
ptr[i].addr = NULL;
ptr[i].fullname = NULL;
ptr[i].comment = NULL;
return ptr;
}
static void write_addr_list P_((FILE *F, struct addr_item *list,
charset_t cs, int letter));
static void write_addr_list(F,list,cs,letter)
FILE *F;
struct addr_item *list;
charset_t cs;
int letter;
{
struct addr_item *ptr;
putc(letter,F);
putc(' ',F);
for (ptr=list; ptr->addr && ptr->fullname; ptr++) {
char * buffer;
if (ptr != list) {
putc(',',F);
putc(' ',F);
}
buffer = string_to_hdr(HDR_PHRASE, ptr->fullname,
cs, 0, NULL);
if (buffer) {
fputs(buffer,F);
putc(' ',F);
free(buffer);
}
putc('<',F);
fputs(ptr->addr,F);
putc('>',F);
if (ptr->comment) {
buffer = string_to_hdr(HDR_COMMENT, ptr->comment,
cs, 0, NULL);
if (buffer) {
putc(' ',F);
putc('(',F);
fputs(buffer,F);
putc(')',F);
free(buffer);
}
}
}
putc('\n',F);
}
static void write_index_rec P_((struct MailboxView *view,
struct message_list * current));
static void write_index_rec(view,current)
struct MailboxView *view;
struct message_list * current;
{
fprintf(view->u.canceldir->index_F,
"F %s\n",
current->filename);
if (current->REC.lines >= 0) {
fprintf(view->u.canceldir->index_F,"L %d\n",
current->REC.lines);
}
fprintf(view->u.canceldir->index_F,
"T %ld\n",
(long int) current->REC.received_time);
fprintf(view->u.canceldir->index_F,
"d %ld\n",
(long int) current->REC.time_sent);
if (current->REC.env_from[0]) {
fprintf(view->u.canceldir->index_F,
"E %s\n",
current->REC.env_from);
}
if (current->REC.from) {
write_addr_list(view->u.canceldir->index_F,
current->REC.from,
view->u.canceldir->cs,'f');
}
if (current->REC.to) {
write_addr_list(view->u.canceldir->index_F,
current->REC.to,
view->u.canceldir->cs,'t');
}
if (current->REC.cc) {
write_addr_list(view->u.canceldir->index_F,
current->REC.cc,
view->u.canceldir->cs,'c');
}
if (current->REC.messageid[0]) {
fprintf(view->u.canceldir->index_F,
"M %s\n",
current->REC.messageid);
}
if (current->REC.subject) {
char * s = string_to_hdr(HDR_TEXT,current->REC.subject,
view->u.canceldir->cs,0, NULL);
fprintf(view->u.canceldir->index_F,
"S %s\n",
s);
free(s);
}
}
static void add_canceled_mail1(filename,headers,view,X,lines,h,
body_offset)
char *filename;
struct mailing_headers * headers;
struct MailboxView *view;
time_t X;
int lines;
header_list_ptr h;
long body_offset;
{
struct message_list * current = NULL; /* current index */
view->u.canceldir->message_list =
safe_realloc(view->u.canceldir->message_list,
(view->u.canceldir->message_list_len+1) *
sizeof (view->u.canceldir->message_list[0]));
current = & (view->u.canceldir->
message_list[view->u.canceldir->message_list_len++]);
current->filename = safe_strdup(filename);
header_zero( & (current->REC));
/* Dummy default ... */
current->REC.header_charset = view->u.canceldir->cs;
/* read_folder_headers_helper() will re-set header_charset
if it sees X-ELM-OSV header with parameter
hdr-charset
*/
/* Start of headers */
current->REC.offset = 0;
current->REC.mime_rec.begin_offset = 0;
/* Start of body */
if (body_offset >= 0L)
current->REC.mime_rec.begin_offset = body_offset;
if (lines >= 0)
current->REC.lines = lines;
current->REC.received_time = X;
current->REC.time_sent = X;
if (h) {
/* Parses Return-Path, Message-Id, Content-Length,
Date, MIME-Version, X-ELM-OSV
*/
read_folder_headers_helper(& (current->REC), h);
/* Parses Sensitivity, Importance, Priority,
Action, Content-Type, Status,
Subject, From, To, Cc
And X-IMAP is used on message-hide-hack
*/
header_parse_helper(& (current->REC), h);
}
if (headers && headers->env_from &&
! current->REC.env_from[0]) {
int x;
CONST char * t = mailer_env_from_value(headers->env_from,&x);
/* Assurance */
if (t)
strfcpy(current->REC.env_from,t,
sizeof (current->REC.env_from));
}
/* Adds env_from, if not set */
if (view == canceled_mail_view &&
!current->REC.env_from[0]) {
strfcpy(current->REC.env_from,username,
sizeof (current->REC.env_from));
}
if (headers && headers->from.addrs &&
! current->REC.from) {
current->REC.from = dup_addr_list(headers->from.addrs);
}
if (headers && headers->to.addrs &&
! current->REC.to) {
current->REC.to = dup_addr_list(headers->to.addrs);
}
if (headers && headers->cc.addrs &&
! current->REC.cc) {
current->REC.cc = dup_addr_list(headers->cc.addrs);
}
if (headers && headers->subject &&
! current->REC.subject)
current->REC.subject = dup_string(headers->subject);
write_index_rec(view,current);
}
void delete_marked_canceled_mails(view)
struct MailboxView *view;
{
int i;
struct mv_canceldir *d;
if (&mt_canceldir!= view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"delete_marked_canceled_mails",
"Bad type for canceldir view",0);
d = view->u.canceldir;
/* DO not remove data from index on here!
because it confuses canceled mail selection
*/
if (! d->dirname)
return;
for (i = 0; i < d->message_list_len; i++) {
if (ison(d->message_list[i].REC.status,
DELETED)) {
char * filename = elm_message(FRM("%s/%s"),
d->dirname,
d->message_list[i].
filename);
if (0 == unlink(filename)) {
DPRINT(Debug,7,(&Debug,
"Removed canceled mail [%d]: %s\n",
i,filename));
}
free(filename);
}
}
}
static void index_initialize(view)
struct MailboxView *view;
{
/* Initialize file */
rewind(view->u.canceldir->index_F);
#ifdef FTRUNCATE
ftruncate(fileno(view->u.canceldir->index_F),0);
#endif
fprintf(view->u.canceldir->index_F,
"ELMME+ MIDX\n");
view->u.canceldir->cs =
MIME_name_to_charset("UTF-8",0);
if (view->u.canceldir->cs &&
view->u.canceldir->cs->MIME_name)
fprintf(view->u.canceldir->index_F,
"C %s\n",
view->u.canceldir->cs->MIME_name);
fflush(view->u.canceldir->index_F);
}
void sync_canceled_mails(view)
struct MailboxView *view;
{
/* Rewrites index if needed */
int i,X;
int unlock_it = 0;
struct mv_canceldir *d;
if (&mt_canceldir!= view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"sync_canceled_mails",
"Bad type for canceldir view",0);
d = view->u.canceldir;
if (! d->dirname ||
! d->indexname) {
return;
}
if (!view->u.canceldir->index_F) {
if (! process_index(view))
return;
unlock_it++;
}
for (i = 0, X=0; i < d->message_list_len; i++) {
char * filename = elm_message(FRM("%s/%s"),
d->dirname,
d->message_list[i].
filename);
if (0 != access(filename,ACCESS_EXISTS)) {
DPRINT(Debug,7,(&Debug,
"[%d] not exists, removing from index: %s\n",
i,filename));
header_clear(& (d->message_list[i].REC));
free(d->message_list[i].filename);
d->message_list[i].filename = NULL;
} else {
if (X < i) {
d->message_list[X] = d->message_list[i];
/* Avoid double pintters */
header_zero(& (d->message_list[i].REC));
d->message_list[i].filename = NULL;
}
X++;
}
free(filename);
}
if (X < d->message_list_len) {
long pos;
DPRINT(Debug,7,(&Debug,
"Canceled mails reduced %d => %d\n",
d->message_list_len,X));
d->message_list_len = X;
index_initialize(view);
/* Write records */
for (i = 0; i < d->message_list_len; i++) {
write_index_rec(view,& (d->message_list[i]));
}
mt_make_canceldir_view(view);
pos = ftell(view->u.canceldir->index_F);
/* Temporary terminator */
fprintf(view->u.canceldir->index_F,"--END\n");
/* Set position so that next appended index overwrites this */
fseek(view->u.canceldir->index_F,pos,SEEK_SET);
}
if (unlock_it)
unlock_index(view);
}
FILE * add_canceled_mail P_((char **outfile,
struct mailing_headers * headers,
struct MailboxView *view,
time_t X,
int lines,
header_list_ptr h,
long body_offset));
FILE * add_canceled_mail(outfile,headers,view, X, lines,h,body_offset)
char **outfile;
struct mailing_headers * headers;
struct MailboxView *view;
time_t X;
int lines;
long body_offset;
header_list_ptr h;
{
int i;
FILE *ret = NULL;
int unlock_it = 0;
if (&mt_canceldir!= view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"add_canceled_mail",
"Bad type for canceldir view",0);
if (!view->u.canceldir->dirname ||
!view->u.canceldir->indexname ||
!view->u.canceldir->cs){
DPRINT(Debug,7,(&Debug,
"add_canceled_mail=NULL -- not setup\n"));
return NULL;
}
if (!view->u.canceldir->index_F) {
if (! process_index(view))
return NULL;
unlock_it++;
}
for (i = view->u.canceldir->message_list_len;
i < view->u.canceldir->message_list_len+100;
i++) {
int fd;
if (*outfile)
free(*outfile);
*outfile = elm_message(FRM("%s/%05d-%02d.%s"),
view->u.canceldir->dirname,
(int)(X/(24*60*60)),
i,
dead_letter);;
fd = open(*outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) {
DPRINT(Debug,7,(&Debug,
"add_canceled_mail: %d -- %s creation failed\n",
i,*outfile));
continue;
}
ret = fdopen(fd, "w");
if (!ret) {
close(fd);
goto fail;
}
DPRINT(Debug,7,(&Debug,
"add_canceled_mail: Created %s\n",
*outfile));
break;
}
if (ret) {
char *x = strrchr(*outfile,'/');
if (!x)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"add_canceled_mail",
"NO / on generated name",0);
add_canceled_mail1(x+1,headers,view,X,lines,h,body_offset);
} else {
DPRINT(Debug,7,(&Debug,
"add_canceled_mail: failed to create mail\n"));
}
fail:
if (!ret) {
if (*outfile)
free(*outfile);
*outfile = NULL;
}
if (unlock_it)
unlock_index(view);
DPRINT(Debug,7,(&Debug,
"add_canceled_mail=%p\n",ret));
return ret;
}
static void move_olds(view)
struct MailboxView *view;
{
int i;
for (i = 0; i < 100; i++) {
char *lbuf1;
long b;
int fd;
struct stat stat_buf;
FILE *f1,*f2;
header_list_ptr h = NULL;
int lines = 0,c;
char *newname = NULL;
if (0 == i)
lbuf1 = elm_message(FRM("%s/%s"),
home,dead_letter);
else
lbuf1 = elm_message(FRM("%s/%02d.%s"),
home,i,dead_letter);
fd = open(lbuf1,O_RDONLY);
if (fd < 0) {
DPRINT(Debug,7,(&Debug,
"move_olds - copy %d: no file %s\n",
i,lbuf1));
free(lbuf1);
if (i > 1)
break;
continue;
}
if (-1 == fstat(fd,&stat_buf)) {
close(fd);
free(lbuf1);
continue;
}
if (stat_buf.st_uid != userid) {
/* Wrong owner */
close(fd);
free(lbuf1);
continue;
}
if (
#ifdef S_ISREG
! S_ISREG(stat_buf.st_mode)
#else
S_IFREG != (stat_buf.st_mode & S_IFMT)
#endif
) {
/* Wrong type */
close(fd);
free(lbuf1);
continue;
}
f1 = fdopen(fd,"r");
if (!f1) {
close(fd);
free(lbuf1);
continue;
}
h = file_read_headers(f1,RHL_CHECK_HEADER);
b = ftell(f1);
while (EOF != (c = getc(f1))) {
if ('\n' == c)
lines++;
}
f2 = add_canceled_mail(&newname,NULL,
view,
stat_buf.st_mtime,lines,h,b);
if (f2) {
rewind(f1);
if (0 != rename(lbuf1,newname)) {
while (EOF != (c = getc(f1))) {
putc(c,f2);
}
if (0 == fflush(f2) &&
!ferror(f1) &&
!ferror(f1)) {
DPRINT(Debug,7,(&Debug,
"give_canceled_mail - copy %d: copied %s to %s\n",
i,lbuf1,newname));
unlink(lbuf1);
}
} else {
DPRINT(Debug,7,(&Debug,
"give_canceled_mail - copy %d: renamed %s to %s\n",
i,lbuf1,newname));
}
fclose(f2);
}
if (h)
delete_headers(&h);
if (newname)
free(newname);
fclose(f1);
free(lbuf1);
}
}
struct MailboxView *give_canceled_mail()
{
char *t = give_dt_estr_as_str(&dead_letter_dir_e,"dead-letter-dir");
if (!canceled_mail_view) {
if (!t) {
DPRINT(Debug,7,(&Debug,
"give_canceled_mail=NULL: no dead-letter-dir\n"));
return NULL;
}
canceled_mail_view = give_canceldir();
setup_canceldir(canceled_mail_view,t);
}
if (&mt_canceldir!= canceled_mail_view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"give_canceled_mail",
"Bad type for canceled_mail_view",0);
if (t && 0 == mkdir(t,0700)) {
int i;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmDeadLetterDirCreated,
"\"dead-letter-dir\" %s created."),
t);
/* Try again create index file .... */
if (canceled_mail_view->u.canceldir->indexname &&
! canceled_mail_view->u.canceldir->index_F) {
if (!process_index(canceled_mail_view))
goto XX;
}
move_olds(canceled_mail_view);
} else if (EEXIST == errno) {
DPRINT(Debug,7,(&Debug,
"give_canceled_mail: %s exists already\n",
t));
move_olds(canceled_mail_view);
}
update_index(canceled_mail_view);
XX:
mt_make_canceldir_view(canceled_mail_view);
unlock_index(canceled_mail_view);
DPRINT(Debug,7,(&Debug,
"give_canceled_mail=%p\n",
canceled_mail_view));
return canceled_mail_view;
}
void close_canceled_mail()
{
if (canceled_mail_view) {
/* NOTE: Can not call
free_mailbox(& (canceled_mail_view)));
because
mt_free_canceldir
will reset canceled_mail_view
*/
struct MailboxView *a = canceled_mail_view;
sync_canceled_mails(a);
free_mailbox (&a);
if (canceled_mail_view)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"close_canceled_mail",
"canceled_mail_view not resetted",0);
}
}
/* HACK -- return 1 on succeed, 0 on failure */
int cancel_set_current(cancel_view,last_canceled_mail)
struct MailboxView * cancel_view;
char *last_canceled_mail;
{
int x;
char * D = last_canceled_mail;
if (&mt_canceldir!= cancel_view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
"Bad type for cancel_view",0);
if (cancel_view->u.canceldir->dirname) {
int L = strlen(cancel_view->u.canceldir->dirname);
if (0 == strncmp(D,cancel_view->u.canceldir->dirname,L) &&
'/' == D[L]) {
DPRINT(Debug,7,(&Debug,
"cancel_set_current: Filename %s have dirname as prefix, good ",
D));
D += L+1;
DPRINT(Debug,7,(&Debug,"=> %s\n",
D));
}
}
for (x = 0; x < cancel_view->view_len; x++) {
int n;
if (0 != cancel_view->view[x].mailbox_number)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
"Bad internal mailbox number",0);
n = cancel_view->view[x].index;
if (n < 0 || n >= cancel_view->u.canceldir->message_list_len)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
"Bad internal index",0);
if (0 == strcmp(cancel_view->u.canceldir->message_list[n].filename,
D)) {
DPRINT(Debug,7,(&Debug," Found filename %s internal index %d view index %d\n",
D,n,x));
/* NOTE: Caller uses current == view_index +1 */
cancel_view->current = x+1;
return 1;
}
}
DPRINT(Debug,7,(&Debug,"cancel_set_current: Filename %s not found\n",
D));
return 0;
}
/* HACK -- delete curently open file */
void delete_current_cancel(cancel_view,ref_file)
struct MailboxView * cancel_view;
FILE *ref_file;
{
int idx;
char *filename = NULL;
if (&mt_canceldir!= cancel_view->mailbox_type)
panic("MBX VIEW PANIC",__FILE__,__LINE__,"cancel_set_current",
"delete_current_cancel",0);
if (! cancel_view->u.canceldir->last_open_file
|| ref_file != cancel_view->u.canceldir->last_open_file) {
DPRINT(Debug,3,(&Debug,
"delete_current_cancel: referenced file not currently open\n"));
return;
}
idx = cancel_view->u.canceldir->last_open_index;
if (idx < 0 || idx >= cancel_view->u.canceldir->message_list_len)
panic("MBX VIEW PANIC",__FILE__,__LINE__,
"delete_current_cancel",
"Bad internal index",0);
filename = elm_message(FRM("%s/%s"),
cancel_view->u.canceldir->dirname,
cancel_view->u.canceldir->message_list[idx].
filename);
if (0 == unlink(filename)) {
DPRINT(Debug,3,(&Debug,
"delete_current_cancel: [%d] %s deleted\n",
idx,filename));
}
free(filename);
}
struct MailboxView *give_canceldir()
{
struct MailboxView *ret = malloc_view(&mt_canceldir);
return ret;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1