Commit d4627cb0 d4627cb03d501d30fba4fb85ec2b4cbd64372e53 by Sergey Poznyakoff

To avoid confusion, pruned libmailbox directory

1 parent f167317c
# Use automake to process this file -*-Makefile-*-
AUTOMAKE_OPTIONS = ../lib/ansi2knr
CFLAGS = -Wall -pedantic -g -DTESTING
include_HEADERS = mailbox.h
lib_LTLIBRARIES = libmailbox.la
libmailbox_la_SOURCES = mailbox.c unixmbox.c unixmbox.h
libmailbox_la_LDFLAGS = -version-info 0:0:0
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mailbox.h"
#include "unixmbox.h"
#ifdef _HAVE_ERRNO_H
#include <errno.h>
#endif
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
int _mbox_dummy1 (mailbox * mbox);
int _mbox_dummy2 (mailbox * mbox, unsigned int num);
int _mbox_dummy3 (mailbox * mbox, char *c);
char *_mbox_dummy4 (mailbox * mbox, unsigned int num);
mailbox *
mbox_open (const char *name)
{
mailbox *mbox;
struct stat st;
if ( name == NULL )
{
errno = EINVAL;
return NULL;
}
mbox = malloc (sizeof (mailbox));
if (mbox == NULL)
{
errno = ENOMEM;
return NULL;
}
/* Set up with default data and dummy functions */
mbox->name = strdup (name);
if (mbox->name == NULL)
{
errno = ENOMEM;
free (mbox);
return NULL;
}
/* check if we can look at file, prep for checks later in function */
if (stat (mbox->name, &st) == -1)
{
free (mbox->name);
free (mbox);
return NULL; /* errno set by stat() */
}
mbox->messages = 0;
mbox->num_deleted = 0;
mbox->sizes = NULL;
mbox->_data = NULL;
mbox->_close = _mbox_dummy1;
mbox->_delete = _mbox_dummy2;
mbox->_undelete = _mbox_dummy2;
mbox->_expunge = _mbox_dummy1;
mbox->_scan = _mbox_dummy1;
mbox->_add_message = _mbox_dummy3;
mbox->_is_deleted = _mbox_dummy2;
mbox->_is_updated = _mbox_dummy1;
mbox->_lock = _mbox_dummy2;
mbox->_get_body = _mbox_dummy4;
mbox->_get_header = _mbox_dummy4;
#ifdef TESTING
mbox->_tester = _mbox_dummy2;
#endif
if (S_ISREG (st.st_mode))
{
if (unixmbox_open (mbox) == 0)
return mbox;
else
{
/*
* Check errno to find out why it failed, if it's simply not a
* unix mbox format message, then try other mailbox types,
* otherwise, leave errno set and return NULL
*/
if (errno == EBADMSG)
errno = ENOSYS; /* no other mailboxes supported right now */
}
}
else if (S_ISDIR (st.st_mode))
{
/* for example...
if (maildir_open (mbox, name) == 1)
return mbox;
*/
errno = ENOSYS;
}
else
errno = EINVAL; /* neither directory nor file, so bomb */
free (mbox->name);
free (mbox);
return NULL;
}
/*
* Gets the contents of a header field
*/
char *
mbox_header_line (mailbox *mbox, unsigned int num, const char *header)
{
char *full, *tmp, *line;
int try = 1;
size_t i = 0, j = 0;
size_t len, lh;
if ( mbox == NULL || header == NULL )
{
errno = EINVAL;
return NULL;
}
full = mbox_get_header (mbox, num);
if (full == NULL)
return NULL;
lh = strlen (header);
len = strlen (full);
tmp = NULL;
/* First get the appropriate line at the beginning */
for (i=0; i < len-(lh+2); i++)
{
if (try == 1)
{
if (!strncasecmp(&full[i], header, lh) && full[i+lh] == ':')
{
tmp = strdup (&full[i+lh+2]);
if (tmp == NULL)
{
free(full);
return NULL;
}
break;
}
else
try = 0;
}
else if (full[i] == '\n')
try = 1;
else
try = 0;
}
/* FIXME: hmm, no valid header found, what should errno be? */
if (tmp == NULL)
{
free(full);
return NULL;
}
/* Now trim the fat */
len = strlen (tmp);
for (i = 0; i < len; i++)
{
if (tmp[i] == '\n' && i < (len - 1) && isspace (tmp[i+1]))
{
if (tmp[i+1] == '\t')
tmp[i + 1] = ' ';
for (j = i; j < len; j++)
tmp[j] = tmp[j+1];
}
else if (tmp[i] == '\n')
{
tmp[i] = '\0';
break;
}
}
line = strdup (tmp);
free (tmp);
free (full);
return line;
}
/*
* Gets first LINES lines from message body
*/
char *
mbox_body_lines (mailbox *mbox, unsigned int num, unsigned int lines)
{
char *full, *buf = NULL;
int i=0, line = 0, len;
if (mbox == NULL)
{
errno = EINVAL;
return NULL;
}
if (lines == 0)
return strdup ("");
full = mbox_get_body (mbox, num);
if (full == NULL)
return NULL;
len = strlen (full);
for (i=0; i < len && line < lines; i++)
{
if (full[i] == '\n')
{
line++;
if (line >= lines)
{
full[i+1] = '\0';
buf = strdup (full);
break;
}
}
}
if (buf == NULL)
buf = strdup (full);
free (full);
return buf;
}
/*
* Bogus functions for unimplemented functions that return int
*/
int
_mbox_dummy1 (mailbox * mbox)
{
errno = ENOSYS;
return -1;
}
int
_mbox_dummy2 (mailbox * mbox, unsigned int num)
{
return _mbox_dummy1 (mbox);
}
int
_mbox_dummy3 (mailbox * mbox, char *c)
{
return _mbox_dummy1 (mbox);
}
/*
* Bogus function for unimplemented functions that return char *
*/
char *
_mbox_dummy4 (mailbox * mbox, unsigned int num)
{
errno = ENOSYS;
return NULL;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILBOX_H
#define _MAILBOX_H 1
#ifndef __P
#if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*!__P */
/* These need to be documented */
#define mbox_close(m) m->_close(m)
#define mbox_delete(m,n) m->_delete(m,n)
#define mbox_undelete(m,n) m->_undelete(m,n)
#define mbox_expunge(m) m->_expunge(m)
#define mbox_scan(m) m->_scan(m)
#define mbox_is_deleted(m,n) m->_is_deleted(m,n)
#define mbox_is_updated(m) m->_is_updated(m)
#define mbox_add_message(m,s) m->_add_message(m,s)
#define mbox_get_body(m,n) m->_get_body(m,n)
#define mbox_get_header(m,n) m->_get_header(m,n)
#define mbox_lock(m,n) m->_lock(m,n)
#ifdef TESTING
#define mbox_tester(m,n) m->_tester(m,n)
#endif
#include <stdlib.h>
/* Lock settings */
/* define this way so that it is opaque and can later become a struct w/o
* people noticing (-:
*/
enum _mailbox_lock_t {MO_ULOCK, MO_RLOCK, MO_WLOCK}; /* new type */
typedef enum _mailbox_lock_t mailbox_lock_t;
typedef struct _mailbox
{
/* Data */
char *name;
unsigned int messages;
unsigned int num_deleted;
size_t *sizes;
void *_data;
/* Functions */
int (*_close) __P ((struct _mailbox *));
int (*_delete) __P ((struct _mailbox *, unsigned int));
int (*_undelete) __P ((struct _mailbox *, unsigned int));
int (*_expunge) __P ((struct _mailbox *));
int (*_add_message) __P ((struct _mailbox *, char *));
int (*_scan) __P ((struct _mailbox *));
int (*_is_deleted) __P ((struct _mailbox *, unsigned int));
int (*_is_updated) __P ((struct _mailbox *));
int (*_lock) __P((struct _mailbox *, mailbox_lock_t));
char *(*_get_body) __P ((struct _mailbox *, unsigned int));
char *(*_get_header) __P ((struct _mailbox *, unsigned int));
#ifdef TESTING
void (*_tester) __P ((struct _mailbox *, unsigned int));
#endif
}
mailbox;
mailbox *mbox_open __P ((const char *name));
char *mbox_header_line __P ((mailbox *mbox, unsigned int num, const char *header));
char *mbox_body_lines __P ((mailbox *mbox, unsigned int num, unsigned int lines));
#endif
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "maildir.h"
/*
* Opens a mailbox
*/
int
maildir_open (mailbox * mbox)
{
int i;
int alloced = 0;
maildir_data *data;
struct dirent *entry;
char old_dir[PATH_MAX];
struct utsname *utsinfo;
uname (utsinfo);
getcwd (old_dir, PATH_MAX);
chdir (mbox->name);
data->new = opendir ("new");
data->tmp = opendir ("tmp");
data->cur = opendir ("cur");
data->time = time (NULL);
data->pid = getpid ();
data->sequence = 0;
/* data->host = strdup (utsinfo->sysname); */
data->messages = malloc (10 * sizeof (maildir_message));
alloced = 10;
/* process the new directory */
while (entry = readdir (data->new))
{
/* no dot files */
if (entry->d_name[0] != '.')
{
if (mbox->messages >= alloced)
{
alloced *= 2;
data->messages = realloc (data->messages,
alloced * sizeof (maildir_message));
/* check */
}
data->messages[mbox->messages].deleted = 0;
data->messages[mbox->messages].info = NULL;
data->messages[mbox->messages].location = new;
data->messages[mbox->messages].file = strdup (entry->d_name);
/* check */
mbox->messages++;
}
}
/* then the cur directory */
while (entry = readdir (data->cur))
{
if (entry->d_name[0] != '.')
{
if (mbox->messages >= alloced)
{
alloced *= 2;
data->messages = realloc (data->messages,
alloced * sizeof (maildir_message));
/* check */
}
data->messages[mbox->messages].deleted = 0;
data->messages[mbox->messages].location = cur;
data->messages[mbox->messages].file = strdup (entry->d_name);
/* check */
/* data->messages[i].info = parse_for_info (entry->d_name); */
mbox->messages++;
}
}
for (i=0; i < mbox->messages; i++)
{
FILE *f;
char buf[80];
chdir (mbox->name);
if (data->messages[i].location == new)
chdir ("new");
else if (data->messages[i].location == cur)
chdir ("cur");
f = fopen (data->messages[i].file, "r");
data->messages[i].body = 0;
while (fgets (buf, 80, f))
if (!strncmp (buf, "\r\n", 2) || strlen (buf) <= 1)
fgetpos (f, &(data->messages[i].body));
fclose (f);
}
mbox->_data = data;
mbox->_close = maildir_close;
mbox->_delete = maildir_delete;
mbox->_undelete = maildir_undelete;
mbox->_expunge = maildir_expunge;
mbox->_add_message = maildir_add_message;
mbox->_is_deleted = maildir_is_deleted;
mbox->_lock = maildir_lock;
mbox->_get_body = maildir_get_body;
mbox->_get_header = maildir_get_header;
chdir (old_dir);
return 0;
}
/*
* Closes and unlocks a mailbox, does not expunge
*/
int
maildir_close (mailbox * mbox)
{
/* FIXME: hack from unixmbox */
return 0;
}
/*
* Marks a message for deletion
*/
int
maildir_delete (mailbox * mbox, unsigned int num)
{
maildir_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 1;
mbox->num_deleted++;
return 0;
}
/*
* Unmark a message for deletion
*/
int
maildir_undelete (mailbox * mbox, unsigned int num)
{
maildir_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || !mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 0;
mbox->num_deleted--;
return 0;
}
/*
* Updates a mailbox to remove message marked for deletion
*/
int
maildir_expunge (mailbox * mbox)
{
maildir_data *data;
int i = 0;
char old_dir[PATH_MAX];
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
getcwd (old_dir, PATH_MAX);
chdir (mbox->name);
if (mbox->num_deleted)
{
data = mbox->_data;
for (i = 0; i < mbox->messages; i++)
{
if (data->messages[i].deleted == 0)
{
unlink (data->messages[i].file);
mbox->num_deleted--;
}
}
}
/* reorder messages? */
chdir (old_dir);
return 0;
}
/*
* Determines whether or a not a message is marked for deletion
*/
int
maildir_is_deleted (mailbox * mbox, unsigned int num)
{
maildir_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (mbox->num_deleted == 0)
return 0;
data = mbox->_data;
return (data->messages[num].deleted == 1);
}
int
maildir_is_updated (mailbox *mbox)
{
struct stat st;
maildir_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (stat (mbox->name, &st) == -1)
return -1;
data = mbox->_data;
return (st.st_mtime > data->last_mod_time);
}
/*
* Adds a message to the mailbox
*/
int
maildir_add_message (mailbox * mbox, char *message)
{
/*
* FIXME: please write me
* http://www.qmail.org/man/man5/maildir.html
*/
errno = ENOSYS;
return -1;
}
/*
* Returns a message body
*/
char *
maildir_get_body (mailbox * mbox, unsigned int num)
{
maildir_data *data;
char *buf;
char old_dir[PATH_MAX];
FILE *f;
struct stat st;
size_t size;
if (mbox == NULL)
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages || num < 0)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
getcwd (old_dir, PATH_MAX);
chdir (mbox->name);
if (data->messages[num].location == cur)
chdir ("cur");
else if (data->messages[num].location == tmp)
chdir ("tmp");
else if (data->messages[num].location == new)
chdir ("new");
f = fopen (data->messages[num].file, "r");
if (f == NULL)
{
chdir (old_dir);
perror (NULL);
return NULL;
}
stat (data->messages[num].file, &st);
size = st.st_size - data->messages[num].body + 1;
buf = malloc (sizeof (char) * size);
if (buf == NULL)
{
fclose (f);
chdir (old_dir);
errno = ENOMEM;
return NULL;
}
memset (buf, 0, size);
if (fsetpos (f, &(data->messages[num].body)) == -1)
{
fclose (f);
chdir (old_dir);
free (buf);
return NULL;
}
if (fread (buf, sizeof (char), size-1, f) < size)
{
fclose (f);
chdir (old_dir);
free (buf);
return NULL;
}
fclose (f);
chdir (old_dir);
return buf;
}
/*
* Returns just the header of a message
*/
char *
maildir_get_header (mailbox * mbox, unsigned int num)
{
maildir_data *data;
char *buf;
if ( mbox == NULL )
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
buf = NULL; /* FIXME: read the file until data->message[num].body */
return buf;
}
/*
* Sets lock mode for a mailbox
* FIXME: What to do for Maildir? no locking?
*/
int
maildir_lock (mailbox *mbox, mailbox_lock_t mode)
{
return 0;
}
/* FIXME: not implemented */
int
maildir_scan (mailbox *mbox)
{
errno = ENOSYS;
return -1;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILDIR_H
#define _MAILDIR_H 1
#include <mailbox.h>
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* FIXME need auto* wrapper */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/utsname.h>
#include <time.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#elif HAVE_STRINGS_H
#include <strings.h>
#endif
typedef struct _maildir_message
{
off_t body;
char deleted;
enum { new, tmp, cur } location;
char *file;
char *info;
}
maildir_message;
typedef struct _maildir_data
{
maildir_message *messages;
DIR *new;
DIR *cur;
DIR *tmp;
time_t time;
pid_t pid;
unsigned int sequence;
char *host;
time_t last_mod_time;
}
maildir_data;
int maildir_open (mailbox *mbox);
int maildir_close (mailbox *mbox);
int maildir_delete (mailbox *mbox, unsigned int num);
int maildir_undelete (mailbox *mbox, unsigned int num);
int maildir_expunge (mailbox *mbox);
int maildir_scan (mailbox *mbox);
int maildir_is_deleted (mailbox *mbox, unsigned int num);
int maildir_is_updated (mailbox *mbox);
int maildir_lock (mailbox *mbox, mailbox_lock_t mode);
int maildir_add_message (mailbox *mbox, char *message);
char *maildir_get_body (mailbox *mbox, unsigned int num);
char *maildir_get_header (mailbox *mbox, unsigned int num);
#endif
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mh.h"
/*
* Opens a mailbox
*/
int
mh_open (mailbox * mbox)
{
unsigned long seq_num = 0;
struct dirent *entry;
mh_data *data;
if(mbox == NULL)
return EINVAL;
data = malloc (sizeof (mh_data));
data->dir = opendir (mbox->name);
if(data->dir == NULL)
return errno; /* set by opendir() */
/* process directory */
while ((entry = readdir (data->dir)))
{
char *foo = NULL;
char fname[PATH_MAX];
char line[80];
FILE *fp;
mh_message message;
if (entry->d_name[0] == '.')
{
if (strcmp(entry->d_name, ".mh_sequences") == 0)
/* TODO: deal with mh sequence files */;
continue;
}
if (entry->d_name[0] == ',')
{
message.deleted = 1;
seq_num = strtoul ((entry->d_name) + 1, &foo, 10);
}
else
{
/* TODO: handle ERANGE */
seq_num = strtoul (entry->d_name, &foo, 10);
}
if (*foo != '\0') /* invalid sequence number */
{
printf("skipping invalid message: %s\n", entry->d_name);
continue; /* TODO: handle this better? */
}
sprintf(fname, "%s/%ld", mbox->name, seq_num);
if ((fp = fopen(fname, "r")) == NULL)
continue; /* TODO: handle the error */
/* TODO: handle corrupt files */
while (fgets (line, 80, fp))
{
if ((line[0] == '\r' && line[1] == '\n') || line[0] == '\n')
{
fgetpos(fp, &message.body);
break;
}
}
fclose (fp);
mbox->messages++;
}
/* store next sequence number to use */
data->sequence = seq_num + 1;
mbox->_data = data;
#if 0
mbox->_close = mh_close;
mbox->_delete = mh_delete;
mbox->_undelete = mh_undelete;
mbox->_expunge = mh_expunge;
mbox->_add_message = mh_add_message;
mbox->_is_deleted = mh_is_deleted;
mbox->_lock = mh_lock;
mbox->_get_body = mh_get_body;
mbox->_get_header = mh_get_header;
#endif
return 0;
}
#if 0
/*
* Closes and unlocks a mailbox, does not expunge
*/
int
mh_close (mailbox * mbox)
{
/* FIXME: hack from unixmbox */
return 0;
}
/*
* Marks a message for deletion
*/
int
mh_delete (mailbox * mbox, unsigned int num)
{
mh_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 1;
mbox->num_deleted++;
return 0;
}
/*
* Unmark a message for deletion
*/
int
mh_undelete (mailbox * mbox, unsigned int num)
{
mh_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || !mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 0;
mbox->num_deleted--;
return 0;
}
/*
* Updates a mailbox to remove message marked for deletion
*/
int
mh_expunge (mailbox * mbox)
{
mh_data *data;
int i = 0;
char old_dir[PATH_MAX];
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
getcwd (old_dir, PATH_MAX);
chdir (mbox->name);
if (mbox->num_deleted)
{
data = mbox->_data;
for (i = 0; i < mbox->messages; i++)
{
if (data->messages[i].deleted == 0)
{
unlink (data->messages[i].file);
mbox->num_deleted--;
}
}
}
/* reorder messages? */
chdir (old_dir);
return 0;
}
/*
* Determines whether or a not a message is marked for deletion
*/
int
mh_is_deleted (mailbox * mbox, unsigned int num)
{
mh_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (mbox->num_deleted == 0)
return 0;
data = mbox->_data;
return (data->messages[num].deleted == 1);
}
int
mh_is_updated (mailbox *mbox)
{
struct stat st;
mh_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (stat (mbox->name, &st) == -1)
return -1;
data = mbox->_data;
return (st.st_mtime > data->last_mod_time);
}
/*
* Adds a message to the mailbox
*/
int
mh_add_message (mailbox * mbox, char *message)
{
/*
* FIXME: please write me
* http://www.qmail.org/man/man5/mh.html
*/
errno = ENOSYS;
return -1;
}
/*
* Returns a message body
*/
char *
mh_get_body (mailbox * mbox, unsigned int num)
{
mh_data *data;
char *buf;
char old_dir[PATH_MAX];
FILE *f;
struct stat st;
size_t size;
if (mbox == NULL)
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages || num < 0)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
getcwd (old_dir, PATH_MAX);
chdir (mbox->name);
if (data->messages[num].location == cur)
chdir ("cur");
else if (data->messages[num].location == tmp)
chdir ("tmp");
else if (data->messages[num].location == new)
chdir ("new");
f = fopen (data->messages[num].file, "r");
if (f == NULL)
{
chdir (old_dir);
perror (NULL);
return NULL;
}
stat (data->messages[num].file, &st);
size = st.st_size - data->messages[num].body + 1;
buf = malloc (sizeof (char) * size);
if (buf == NULL)
{
fclose (f);
chdir (old_dir);
errno = ENOMEM;
return NULL;
}
memset (buf, 0, size);
if (fsetpos (f, &(data->messages[num].body)) == -1)
{
fclose (f);
chdir (old_dir);
free (buf);
return NULL;
}
if (fread (buf, sizeof (char), size-1, f) < size)
{
fclose (f);
chdir (old_dir);
free (buf);
return NULL;
}
fclose (f);
chdir (old_dir);
return buf;
}
/*
* Returns just the header of a message
*/
char *
mh_get_header (mailbox * mbox, unsigned int num)
{
mh_data *data;
char *buf;
if ( mbox == NULL )
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
buf = NULL; /* FIXME: read the file until data->message[num].body */
return buf;
}
/*
* Sets lock mode for a mailbox
* FIXME: What to do for Mh? no locking?
*/
int
mh_lock (mailbox *mbox, mailbox_lock_t mode)
{
return 0;
}
/* FIXME: not implemented */
int
mh_scan (mailbox *mbox)
{
errno = ENOSYS;
return -1;
}
#endif
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MH_H
#define _MH_H 1
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <mailbox.h>
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* FIXME need auto* wrapper */
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/utsname.h>
#include <time.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#elif HAVE_STRINGS_H
#include <strings.h>
#endif
typedef struct _mh_message
{
off_t body;
char deleted;
}
mh_message;
typedef struct _mh_data
{
mh_message *messages;
DIR *dir;
unsigned int sequence;
}
mh_data;
int mh_open (mailbox *mbox);
int mh_close (mailbox *mbox);
int mh_delete (mailbox *mbox, unsigned int num);
int mh_undelete (mailbox *mbox, unsigned int num);
int mh_expunge (mailbox *mbox);
int mh_scan (mailbox *mbox);
int mh_is_deleted (mailbox *mbox, unsigned int num);
int mh_is_updated (mailbox *mbox);
int mh_lock (mailbox *mbox, mailbox_lock_t mode);
int mh_add_message (mailbox *mbox, char *message);
char *mh_get_body (mailbox *mbox, unsigned int num);
char *mh_get_header (mailbox *mbox, unsigned int num);
#endif
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "unixmbox.h"
/*
* Opens a mailbox
*/
int
unixmbox_open (mailbox * mbox)
{
char buf[80];
unsigned int max_count = 10;
int mess = 0;
unixmbox_data *data;
struct stat st;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
data = malloc (sizeof (unixmbox_data));
if (data == NULL)
{
errno = ENOMEM;
free (data);
return -1;
}
mbox->_data = data;
data->file = fopen (mbox->name, "r+");
if (data->file == NULL)
{
/* errno is set by fopen() */
free (data);
return -1;
}
data->messages = malloc (sizeof (unixmbox_message) * max_count);
mbox->sizes = malloc (sizeof (int) * max_count);
if (data->messages == NULL || mbox->sizes == NULL)
{
unixmbox_close (mbox);
errno = ENOMEM;
return -1;
}
if (stat (mbox->name, &st) == -1)
{
unixmbox_close (mbox);
return -1;
}
data->last_mod_time = st.st_mtime;
if (fgets (buf, 80, data->file) == NULL)
{
if (feof(data->file))
goto END; /* empty file, no messages */
unixmbox_close (mbox);
return -1;
}
if (strncmp (buf, "From ", 5))
{
/* This is NOT an mbox file */
unixmbox_close (mbox);
errno = EBADMSG; /* use this to signify wrong mbox type */
return -1;
}
do
{
if (!strncmp (buf, "From ", 5))
{
/* Beginning of a header */
while (strchr (buf, '\n') == NULL)
if (fgets (buf, 80, data->file) == NULL) /* eat the From line */
{
if (feof (data->file))
errno = EIO; /* corrupted mailbox? */
unixmbox_close (mbox);
return -1;
}
mbox->messages++;
if (mbox->messages > max_count)
{
max_count = mbox->messages * 2;
data->messages = realloc (data->messages,
max_count * sizeof (unixmbox_message));
mbox->sizes = realloc (mbox->sizes, max_count * sizeof (int));
if (data->messages == NULL || mbox->sizes == NULL)
{
unixmbox_close (mbox);
errno = ENOMEM;
return -1;
}
}
fgetpos (data->file, &(data->messages[mbox->messages - 1].header));
mbox->sizes[mbox->messages - 1] = 0;
data->messages[mbox->messages - 1].deleted = 0;
mess = 0;
}
else if (((!strncmp (buf, "\r\n", 2) || strlen (buf) <= 1)) && mess == 0)
{
/* Beginning of a body */
fgetpos (data->file, &(data->messages[mbox->messages - 1].body));
mbox->sizes[mbox->messages - 1] += strlen (buf) + 1;
mess = 1;
}
else
{
mbox->sizes[mbox->messages - 1] += strlen (buf) + 1;
fgetpos (data->file, &(data->messages[mbox->messages - 1].end));
}
}
while (fgets (buf, 80, data->file));
if (!feof (data->file)) /* stopped due to error, not EOF */
{
unixmbox_close (mbox);
return -1; /* errno is set */
}
END:
mbox->_close = unixmbox_close;
mbox->_delete = unixmbox_delete;
mbox->_undelete = unixmbox_undelete;
mbox->_expunge = unixmbox_expunge;
mbox->_add_message = unixmbox_add_message;
mbox->_is_deleted = unixmbox_is_deleted;
mbox->_lock = unixmbox_lock;
mbox->_get_body = unixmbox_get_body;
mbox->_get_header = unixmbox_get_header;
#ifdef TESTING
mbox->_tester = unixmbox_tester;
#endif
return 0;
}
/*
* Closes and unlocks a mailbox, does not expunge
*/
int
unixmbox_close (mailbox * mbox)
{
unixmbox_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
data = mbox->_data;
unixmbox_lock (mbox, MO_ULOCK);
if (data->file)
fclose (data->file);
free (data->messages);
free (mbox->sizes);
free (data);
return 0;
}
/*
* Marks a message for deletion
*/
int
unixmbox_delete (mailbox * mbox, unsigned int num)
{
unixmbox_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 1;
mbox->num_deleted++;
return 0;
}
/*
* Unmark a message for deletion
*/
int
unixmbox_undelete (mailbox * mbox, unsigned int num)
{
unixmbox_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (num > mbox->messages || !mbox_is_deleted (mbox, num))
{
errno = ERANGE;
return -1;
}
data = mbox->_data;
data->messages[num].deleted = 0;
mbox->num_deleted--;
return 0;
}
/*
* Updates a mailbox to remove message marked for deletion
* FIXME: BROKEN! DOES NOT WORK! BLOWS UP REAL GOOD!
*/
int
unixmbox_expunge (mailbox * mbox)
{
unixmbox_data *data;
int i = 0;
size_t size = 0, size_read = 0;
char *buf = NULL;
int file;
int deletion_needed = 0; /* true when a deleted message has been found */
size_t buff_size = 0;
size_t tmp = 0;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (mbox->num_deleted)
{
data = mbox->_data;
fclose(data->file);
/* error handling */
data->file = NULL;
file = open(mbox->name, O_RDWR);
/* error handling */
for (i = 0; i < mbox->messages; i++)
{
if (data->messages[i].deleted == 0)
{
if (deletion_needed)
{
tmp = mbox->sizes[i];
if (tmp > buff_size)
{
buff_size = tmp;
buf = realloc (buf, tmp);
/* error checking */
}
lseek (file, data->messages[i].header, SEEK_SET);
size_read = read (file, buf, tmp);
/* error checking */
lseek (file, size, SEEK_SET);
write (file, buf, size_read);
/* error checking */
size += size_read;
}
else
{
size += mbox->sizes[i];
}
}
else
{
deletion_needed = 1;
}
}
close (file);
truncate (mbox->name, size);
free (buf);
}
return 0;
}
/*
* Determines whether or a not a message is marked for deletion
*/
int
unixmbox_is_deleted (mailbox * mbox, unsigned int num)
{
unixmbox_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (mbox->num_deleted == 0)
return 0;
data = mbox->_data;
return (data->messages[num].deleted == 1);
}
int
unixmbox_is_updated (mailbox *mbox)
{
struct stat st;
unixmbox_data *data;
if (mbox == NULL)
{
errno = EINVAL;
return -1;
}
if (stat (mbox->name, &st) == -1)
return -1;
data = mbox->_data;
return (st.st_mtime > data->last_mod_time);
}
/*
* Adds a message to the mailbox
*/
int
unixmbox_add_message (mailbox * mbox, char *message)
{
/*
* FIXME: please write me
* move to end of file and write text, don't forget to update
* mbox->messages and mbox->_data->messages
*/
errno = ENOSYS;
return -1;
}
/*
* Returns a message body
*/
char *
unixmbox_get_body (mailbox * mbox, unsigned int num)
{
unixmbox_data *data;
size_t size;
char *buf;
if (mbox == NULL)
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages || num < 0)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
size = data->messages[num].end - data->messages[num].body;
buf = malloc ((1 + size) * sizeof (char));
if (buf == NULL)
{
errno = ENOMEM;
return NULL;
}
memset (buf, 0, size + 1);
if (fsetpos (data->file, &(data->messages[num].body)) == -1)
{
free (buf);
return NULL;
}
if (fread (buf, sizeof (char), size, data->file) < size)
{
free (buf);
return NULL;
}
return buf;
}
/*
* Returns just the header of a message
*/
char *
unixmbox_get_header (mailbox * mbox, unsigned int num)
{
unixmbox_data *data;
size_t size;
char *buf;
if ( mbox == NULL )
{
errno = EINVAL;
return NULL;
}
if (num > mbox->messages)
{
errno = ERANGE;
return NULL;
}
data = mbox->_data;
size = (data->messages[num].body - 1) - data->messages[num].header;
buf = malloc ((1 + size) * sizeof (char));
if (buf == NULL)
{
errno = ENOMEM;
return NULL;
}
memset (buf, 0, size + 1);
if (fsetpos (data->file, &(data->messages[num].header)) == -1)
{
free (buf);
return NULL;
}
if (fread (buf, sizeof (char), size, data->file) < size)
{
free (buf);
return NULL;
}
return buf;
}
/*
* Sets lock mode for a mailbox
* FIXME: this doesn't do anything, really
* Get locking code from Procmail and/or Exim
*/
int
unixmbox_lock (mailbox *mbox, mailbox_lock_t mode)
{
unixmbox_data *data = mbox->_data;
data->lockmode = mode;
return 0;
}
/* FIXME: not implemented */
int
unixmbox_scan (mailbox *mbox)
{
errno = ENOSYS;
return -1;
}
#ifdef TESTING
void unixmbox_tester (mailbox *mbox, unsigned int num)
{
unixmbox_data *data = mbox->_data;
if (!data || num > mbox->messages || num < 0)
return;
printf ("Message size: %u\n", mbox->sizes[num]);
printf ("Message length: %lu\n",
data->messages[num].end - data->messages[num].header);
}
#endif
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _UNIXMBOX_H
#define _UNIXMBOX_H 1
#include <mailbox.h>
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* FIXME need auto* wrapper */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#elif HAVE_STRINGS_H
#include <strings.h>
#endif
typedef struct _unixmbox_message
{
off_t header;
off_t body;
off_t end;
char deleted;
}
unixmbox_message;
typedef struct _unixmbox_data
{
unixmbox_message *messages;
FILE *file;
mailbox_lock_t lockmode;
time_t last_mod_time;
}
unixmbox_data;
int unixmbox_open (mailbox *mbox);
int unixmbox_close (mailbox *mbox);
int unixmbox_delete (mailbox *mbox, unsigned int num);
int unixmbox_undelete (mailbox *mbox, unsigned int num);
int unixmbox_expunge (mailbox *mbox);
int unixmbox_scan (mailbox *mbox);
int unixmbox_is_deleted (mailbox *mbox, unsigned int num);
int unixmbox_is_updated (mailbox *mbox);
int unixmbox_lock (mailbox *mbox, mailbox_lock_t mode);
int unixmbox_add_message (mailbox *mbox, char *message);
char *unixmbox_get_body (mailbox *mbox, unsigned int num);
char *unixmbox_get_header (mailbox *mbox, unsigned int num);
#ifdef TESTING
void unixmbox_tester (mailbox *mbox, unsigned int num);
#endif
#endif