diff -Naur mailutils-0.4.org/include/mailutils/registrar.h mailutils-0.4/include/mailutils/registrar.h --- mailutils-0.4.org/include/mailutils/registrar.h 2003-10-28 18:47:58.000000000 +0800 +++ mailutils-0.4/include/mailutils/registrar.h 2003-10-28 19:23:41.000000000 +0800 @@ -97,7 +97,9 @@ extern record_t path_record; /* Local MH, "mh:" */ extern record_t mh_record; - + +extern record_t maildir_record; //radixs + /* SMTP mailer, "smtp://" */ extern record_t smtp_record; /* Sendmail, "sendmail:" */ diff -Naur mailutils-0.4.org/mail/mail.c mailutils-0.4/mail/mail.c --- mailutils-0.4.org/mail/mail.c 2003-10-28 18:47:59.000000000 +0800 +++ mailutils-0.4/mail/mail.c 2003-10-28 19:23:41.000000000 +0800 @@ -229,6 +229,7 @@ /* Possible supported mailers. */ list_append (bookie, sendmail_record); list_append (bookie, smtp_record); + list_append (bookie, maildir_record); //radixs } interactive = isatty (fileno(stdin)); @@ -449,14 +450,21 @@ return 1; } + /* initial commands */ if (util_getenv(NULL, "header", Mail_env_boolean, 0) == 0) { + util_do_command ("summary"); + util_do_command ("z."); + + } + util_getenv (&prompt, "prompt", Mail_env_string, 0); + mail_mainloop (mail_cmdline, (void*) prompt, 1); fprintf (ofile, "\n"); util_do_command ("quit"); @@ -471,6 +479,7 @@ mail_mainloop (char *(*input) __P((void *, int)), void *closure, int do_history) { char *command, *cmd; + while ((command = (*input)(closure, 0)) != NULL) { int len = strlen (command); diff -Naur mailutils-0.4.org/mailbox/include/registrar0.h mailutils-0.4/mailbox/include/registrar0.h --- mailutils-0.4.org/mailbox/include/registrar0.h 2003-10-28 18:47:58.000000000 +0800 +++ mailutils-0.4/mailbox/include/registrar0.h 2003-10-28 19:23:41.000000000 +0800 @@ -83,6 +83,12 @@ extern int _mailbox_mh_init __P((mailbox_t mailbox)); extern int _folder_mh_init __P ((folder_t)); +#define MU_MAILDIR_SCHEME "maildir:" +#define MU_MAILDIR_SCHEME_LEN 8 +extern int _url_maildir_init __P ((url_t)); +extern int _mailbox_maildir_init __P((mailbox_t mailbox)); +extern int _folder_maildir_init __P((folder_t)); + #ifdef __cplusplus } #endif diff -Naur mailutils-0.4.org/mailbox/maildir/folder.c mailutils-0.4/mailbox/maildir/folder.c --- mailutils-0.4.org/mailbox/maildir/folder.c 1970-01-01 07:30:00.000000000 +0730 +++ mailutils-0.4/mailbox/maildir/folder.c 2003-10-28 19:23:41.000000000 +0800 @@ -0,0 +1,58 @@ + + +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef ENABLE_MH + +#include + +#include +#include + +static struct _record _maildir_record = { + MU_MAILDIR_SCHEME, + _url_maildir_init, /* Url init. */ + _mailbox_maildir_init, /* Mailbox init. */ + NULL, /* Mailer init. */ + _folder_maildir_init, /* Folder init. */ + NULL, /* back pointer. */ + NULL, /* _is_scheme method. */ + NULL, /* _get_url method. */ + NULL, /* _get_mailbox method. */ + NULL, /* _get_mailer method. */ + NULL /* _get_folder method. */ +}; +record_t maildir_record = &_maildir_record; + +int +_folder_maildir_init (folder_t folder ARG_UNUSED) +{ + return 0; +} + +#else +#include +#include + +record_t maildir_record = NULL; + +#endif diff -Naur mailutils-0.4.org/mailbox/maildir/Makefile.in mailutils-0.4/mailbox/maildir/Makefile.in --- mailutils-0.4.org/mailbox/maildir/Makefile.in 2003-10-28 18:47:58.000000000 +0800 +++ mailutils-0.4/mailbox/maildir/Makefile.in 2003-10-28 19:23:41.000000000 +0800 @@ -196,7 +196,7 @@ lib_LTLIBRARIES = libmu_maildir.la libmu_maildir_la_SOURCES = \ - mbox.c + mbox.c url.c folder.c subdir = mailbox/maildir ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -207,7 +207,7 @@ libmu_maildir_la_LDFLAGS = libmu_maildir_la_LIBADD = -am_libmu_maildir_la_OBJECTS = mbox.lo +am_libmu_maildir_la_OBJECTS = mbox.lo url.lo folder.lo libmu_maildir_la_OBJECTS = $(am_libmu_maildir_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) diff -Naur mailutils-0.4.org/mailbox/maildir/mbox.c mailutils-0.4/mailbox/maildir/mbox.c --- mailutils-0.4.org/mailbox/maildir/mbox.c 2003-10-28 18:47:58.000000000 +0800 +++ mailutils-0.4/mailbox/maildir/mbox.c 2003-10-28 19:23:41.000000000 +0800 @@ -17,6 +17,9 @@ /* First draft by Jeff Bailey based on mbox by Alain Magloire */ +/* modified by Tang Yongping, Radixs Pte Ltd, + * the structure of the codes is referenced from mh codes, 15/10/2003 Singapore+ */ + #ifdef HAVE_CONFIG_H # include #endif @@ -33,6 +36,7 @@ #include #include #include +#include #ifdef WITH_PTHREAD # ifdef HAVE_PTHREAD_H @@ -67,32 +71,189 @@ #include #include #include +#include +#include + +#define MAX_OPEN_STREAMS1 16 + +/* Notifications ADD_MESG. */ +#define DISPATCH_ADD_MSG1(mbox,maildird) \ +do \ +{ \ + int bailing = 0; \ + monitor_unlock (mbox->monitor); \ + if (mbox->observable) \ + bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \ + if (bailing != 0) \ + { \ + if (pcount) \ + *pcount = (maildird)->msg_count; \ + locker_unlock (mbox->locker); \ + return EINTR; \ + } \ + monitor_wrlock (mbox->monitor); \ +} while (0); + +/* Note: In this particular implementation the message sequence number + serves also as its UID. This allows to avoid many problems related + to keeping the uids in the headers of the messages. */ + +struct _maildir_data; +struct _maildir_message +{ + struct _maildir_message *next; + struct _maildir_message *prev; + + char *uniq_name; + + stream_t stream; /* Associated file stream */ + off_t body_start; /* Offset of body start in the message file */ + off_t body_end; /* Offset of body end (size of file, effectively) */ + +// size_t seq_number; /* message sequence number */ + + int attr_flags; /* Attribute flags */ + int deleted; /* Was the message originally deleted */ + + time_t mtime; /* Time of last modification */ + size_t header_lines; /* Number of lines in the header part */ + size_t body_lines; /* Number of lines in the body */ + + message_t message; /* Corresponding message_t */ + struct _maildir_data *maildird; /* Back pointer. */ +}; + +struct _maildir_data +{ + /* List of messages: */ + size_t msg_count; /* number of messages in the list */ + struct _maildir_message *msg_head; /* First */ + struct _maildir_message *msg_tail; /* Last */ + + unsigned long uidvalidity; + + char *name; /* Directory name */ + + /* Pool of open message streams */ + struct _maildir_message *msg_pool[MAX_OPEN_STREAMS1]; + int pool_first; /* Index to the first used entry in msg_pool */ + int pool_last; /* Index to the first free entry in msg_pool */ + + time_t mtime; /* Time of last modification */ + + mailbox_t mailbox; /* Back pointer. */ +}; + + + + + + /* Mailbox concrete implementation. */ -static int maildir_open __P ((mailbox_t, int)); -static int maildir_close __P ((mailbox_t)); -static void maildir_destroy __P ((mailbox_t)); -static int maildir_get_message __P ((mailbox_t, size_t, message_t *)); +static int maildir_open __P ((mailbox_t, int)); +static int maildir_close __P ((mailbox_t)); +static void maildir_destroy __P ((mailbox_t)); +static int maildir_get_message __P ((mailbox_t, size_t, message_t *)); /* static int maildir_get_message_by_uid __P ((mailbox_t, size_t, message_t *)); */ -static int maildir_append_message __P ((mailbox_t, message_t)); -static int maildir_messages_count __P ((mailbox_t, size_t *)); -static int maildir_messages_recent __P ((mailbox_t, size_t *)); -static int maildir_message_unseen __P ((mailbox_t, size_t *)); -static int maildir_expunge __P ((mailbox_t)); -static int maildir_save_attributes __P ((mailbox_t)); -static int maildir_uidvalidity __P ((mailbox_t, unsigned long *)); -static int maildir_uidnext __P ((mailbox_t, size_t *)); -static int maildir_scan __P ((mailbox_t, size_t, size_t *)); -static int maildir_is_updated __P ((mailbox_t)); -static int maildir_get_size __P ((mailbox_t, off_t *)); +static int maildir_append_message __P ((mailbox_t, message_t)); +static int maildir_messages_count __P ((mailbox_t, size_t *)); +static int maildir_messages_recent __P ((mailbox_t, size_t *)); +static int maildir_message_unseen __P ((mailbox_t, size_t *)); +static int maildir_expunge __P ((mailbox_t)); +static int maildir_save_attributes __P ((mailbox_t)); +static int maildir_uidvalidity __P ((mailbox_t, unsigned long *)); +static int maildir_uidnext __P ((mailbox_t, size_t *)); +static int maildir_scan __P ((mailbox_t, size_t, size_t *)); +static int maildir_is_updated __P ((mailbox_t)); +static int maildir_get_size __P ((mailbox_t, off_t *)); +static void maildir_cleanup (void *arg); + +static int +maildir_header_fill (header_t header, char *buffer, size_t len, + off_t off, size_t * pnread); + +static int maildir_header_size (header_t header, size_t * psize); + +static int maildir_header_lines (header_t header, size_t * plines); + +static int maildir_get_attr_flags (attribute_t attr, int *pflags); + +static int maildir_set_attr_flags (attribute_t attr, int flags); + +static int maildir_unset_attr_flags (attribute_t attr, int flags); +static int +maildir_body_read (stream_t is, char *buffer, size_t buflen, off_t off, + size_t * pnread); +static int +maildir_body_readline (stream_t is, char *buffer, size_t buflen, + off_t off, size_t * pnread); +static int maildir_stream_size (stream_t stream, off_t * psize); +static int maildir_body_size (body_t body, size_t * psize); +static int maildir_body_lines (body_t body, size_t * plines); +//static int maildir_message_uid (message_t msg, size_t * puid); +static int +maildir_envelope_date (envelope_t envelope, char *buf, size_t len, + size_t * psize); +static int +maildir_envelope_sender (envelope_t envelope, char *buf, size_t len, + size_t * psize); +struct _maildir_message *_maildir_get_message_seq1 (struct _maildir_data + *maildird, char *name); +void _maildir_message_insert (struct _maildir_data *maildird, + struct _maildir_message *msg); +void _maildir_message_delete (struct _maildir_data *maildird, + struct _maildir_message *msg); +struct _maildir_message **maildir_pool_lookup (struct _maildir_message + *maildirm); +void maildir_message_stream_close (struct _maildir_message *maildirm); + + +int get_log10(int number) +{ + int i=0; + while(number>0) + { + number=number/10; + i++; + } + return i; +} + + int _mailbox_maildir_init (mailbox_t mailbox) { + struct _maildir_data *maildird; + size_t name_len; + if (mailbox == NULL) return EINVAL; + + if (mailbox == NULL) + return EINVAL; + + maildird = mailbox->data = calloc (1, sizeof (*maildird)); + if (mailbox->data == NULL) + return ENOMEM; + + /* Back pointer. */ + maildird->mailbox = mailbox; + + url_get_path (mailbox->url, NULL, 0, &name_len); + maildird->name = calloc (name_len + 1, sizeof (char)); + if (maildird->name == NULL) + { + free (maildird); + mailbox->data = NULL; + return ENOMEM; + } + url_get_path (mailbox->url, maildird->name, name_len + 1, NULL); + + /* Overloading the defaults. */ mailbox->_destroy = maildir_destroy; @@ -108,21 +269,34 @@ mailbox->_expunge = maildir_expunge; mailbox->_save_attributes = maildir_save_attributes; mailbox->_uidvalidity = maildir_uidvalidity; - mailbox->_uidnext = maildir_uidnext; +// mailbox->_uidnext = maildir_uidnext; mailbox->_scan = maildir_scan; mailbox->_is_updated = maildir_is_updated; mailbox->_get_size = maildir_get_size; - return 0; /* okdoke */ + return 0; /* okdoke */ } -/* Destruct maildir setup */ -static void -maildir_destroy (mailbox_t mailbox) + +void +_maildir_delete_file (char *dirname, char *filename) { - return; + struct stat st; + char *name; + name = (char *) malloc (strlen (dirname) + 2 + strlen (filename)); + sprintf (name, "%s/%s", dirname, filename); + stat (name, &st); + if (time (NULL) - st.st_atime > 36 * 3600) + //a file in tmp may be safely removed if it has not + //been accessed in 36 hours + //in http://www.qmail.org/qmail-manual-html/man5/maildir.html + { + remove (name); + } + free (name); + } /* Open the file. For MU_STREAM_READ, the code tries mmap() first and fall @@ -130,95 +304,1589 @@ static int maildir_open (mailbox_t mailbox, int flags) { - return -1; + struct _maildir_data *maildird = mailbox->data; + int status = 0; + struct stat st; + DIR *dir; + char *name1; + struct dirent *entry; + + mailbox->flags = flags; + + if (stat (maildird->name, &st) < 0) + return errno; + + if (!S_ISDIR (st.st_mode)) + return EINVAL; + + maildird->mtime = st.st_mtime; + + //to delete out-date file in tmp directory + + name1 = (char *) malloc (strlen (maildird->name) + 5); + + strcpy (name1, maildird->name); + strcat (name1, "/tmp"); + + dir = opendir (name1); + + while ((entry = readdir (dir))) + { + switch (entry->d_name[0]) + { + case '.': + break; + + default: + _maildir_delete_file (name1, entry->d_name); + break; + } + } + + free (name1); + + closedir (dir); + + + /* FIXME: is this the right kind of locking for maildir folders? */ + if (mailbox->locker == NULL) + status = locker_create (&mailbox->locker, maildird->name, 0); + return 0; + } -static int -maildir_close (mailbox_t mailbox) +void +_maildir_move_message (char *dirname, char *filename) { - return -1; + char *from, *to; + from = (char *) malloc (strlen (dirname) + 5 + strlen (filename) + 1); + to = (char *) malloc (strlen (dirname) + 5 + strlen (filename) + 3 + 1); + sprintf (from, "%s/new/%s", dirname, filename); + sprintf (to, "%s/cur/%s:2,", dirname, filename); + + rename (from, to); + remove (from); // needed? } -/* Cover function that call the real thing, maildir_scan(), with - notification set. */ +/* Scan the mailbox */ static int -maildir_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) +maildir_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t * pcount, + int do_notify) { - return 0; + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *msg; + DIR *dir; + struct dirent *entry; + int status = 0; + struct stat st; + + char *name1 = (char *) malloc (strlen (maildird->name) + 1 + 4); + + char *pTmp, *pTmp1; + + if (maildird == NULL) + return EINVAL; + + strcpy (name1, maildird->name); + strcat (name1, "/new"); + + dir = opendir (name1); + + while ((entry = readdir (dir))) + { + switch (entry->d_name[0]) + { + case '.': + break; + default: + _maildir_move_message (maildird->name, entry->d_name); + break; + } + } + + closedir (dir); + + strcpy (name1, maildird->name); + strcat (name1, "/cur"); + + dir = opendir (name1); + + + if (!dir) + return errno; + + monitor_wrlock (mailbox->monitor); + +#ifdef WITH_PTHREAD + pthread_cleanup_push (maildir_cleanup, (void *) mailbox); //cleanup ??? +#endif + + locker_lock (mailbox->locker); + + /* Do actual work. */ + + while ((entry = readdir (dir))) + { + char *namep; + int attr_flags; + size_t num; + + attr_flags = 0; + switch (entry->d_name[0]) + { + case '.': + continue; + case ',': + continue; +#if 0 + attr_flags |= MU_ATTRIBUTE_DELETED; + namep = entry->d_name + 1; + break; +#endif +//case '0':case '1':case '2':case '3':case '4': +// case '5':case '6':case '7':case '8':case '9': + default: + /*FIXME: if there's Invalid entry. Report? */ + pTmp = strchr (entry->d_name, ','); + if ((pTmp1 = strchr (pTmp, 'T')) != NULL) + continue; + if ((pTmp1 = strchr (pTmp, 'S')) != NULL) + attr_flags |= MU_ATTRIBUTE_SEEN | MU_ATTRIBUTE_READ; + namep = entry->d_name; + break; + } + + //num = strtoul (namep, &namep, 10); + //if (namep[0]) + //continue; + + msg = _maildir_get_message_seq1 (maildird, namep); + if (!msg) + { + msg = calloc (1, sizeof (*msg)); + msg->attr_flags = attr_flags; + msg->deleted = attr_flags & MU_ATTRIBUTE_DELETED; + + msg->uniq_name = (char *) malloc (strlen (namep) + 1); + + strcpy (msg->uniq_name, namep); + + _maildir_message_insert (maildird, msg); + + } + else + { + msg->attr_flags = attr_flags; + if (strlen (msg->uniq_name) < strlen (namep)) + { + free (msg->uniq_name); + msg->uniq_name = (char *) malloc (strlen (namep) + 1); + + } + strcpy (msg->uniq_name, namep); + } + } + + closedir (dir); + + if (do_notify) + for (msg = maildird->msg_head; msg; msg = msg->next) + { + DISPATCH_ADD_MSG1 (mailbox, maildird); + } + + if (stat (name1 /*maildird->name */ , &st) == 0) + maildird->mtime = st.st_mtime; + + free (name1); + + if (pcount) + *pcount = maildird->msg_count; + + /* Reset the uidvalidity. */ + if (maildird->msg_count > 0) + { + if (maildird->uidvalidity == 0) + { + maildird->uidvalidity = (unsigned long) time (NULL); + /* FIXME maildird->uidnext = mhd->msg_count + 1; */ + /* Tell that we have been modified for expunging. */ + if (maildird->msg_head) + { + maildir_message_stream_open (maildird->msg_head); + maildir_message_stream_close (maildird->msg_head); + maildird->msg_head->attr_flags |= MU_ATTRIBUTE_MODIFIED; + } + } + } + + + /* Clean up the things */ + + maildir_cleanup (mailbox); +#ifdef WITH_PTHREAD + pthread_cleanup_pop (0); +#endif + return status; } +/* Is the internal representation of the mailbox up to date. + Return 1 if so, 0 otherwise. */ + /* FIXME: How to handle a shrink ? meaning, the &address@hidden@^& user start two browsers and deleted emails in one session. My views is that we should scream bloody murder and hunt them with a machette. But for now just play dumb, but maybe the best approach is to pack our things and leave .i.e exit()/abort(). */ + static int maildir_is_updated (mailbox_t mailbox) { - return -1; + struct stat st1, st2; + struct _maildir_data *maildird = mailbox->data; + + char *curname, *newname; + curname = (char *) malloc (strlen (maildird->name) + 5); + newname = (char *) malloc (strlen (maildird->name) + 5); + strcpy (curname, maildird->name); + strcat (curname, "/cur"); + strcpy (newname, maildird->name); + strcat (newname, "/new"); + + if (!maildird->msg_head) + return 0; + + if (stat (curname, &st1) < 0) + return 1; + if (stat (newname, &st2) < 0) + return 1; + + return (maildird->mtime == st1.st_mtime && maildird->mtime >= st2.st_mtime); + + } static int -maildir_expunge (mailbox_t mailbox) +maildir_scan (mailbox_t mailbox, size_t msgno, size_t * pcount) +{ + struct _maildir_data *maildird = mailbox->data; + + if (!maildir_is_updated (mailbox)) + return maildir_scan0 (mailbox, msgno, pcount, 1); + + + if (pcount) + *pcount = maildird->msg_count; + + return 0; +} + + + + + + +/* Return filename for the message. + NOTE: Allocates memory. */ +static char * +_maildir_message_name (struct _maildir_message *maildirm, int deleted) +{ + char *filename; + char *pTmp, *pTmp1; + size_t len = strlen (maildirm->maildird->name) + 2 + 5 + + strlen (maildirm->uniq_name); + filename = malloc (len); + if (maildirm->attr_flags & MU_ATTRIBUTE_READ) /*|| + maildirm->attr_flags & MU_ATTRIBUTE_SEEN) */ + { + + + pTmp = strchr (maildirm->uniq_name, ','); + pTmp1 = strchr (pTmp, 'S'); + if (pTmp1 == NULL) + { +/* snprintf (filename, len, "%s/cur/%s", maildirm->maildird->name, + maildirm->uniq_name); + remove(filename); + }*/ + + if (deleted) + snprintf (filename, len, "%s/cur/%sST", maildirm->maildird->name, + maildirm->uniq_name); + else + snprintf (filename, len, "%s/cur/%sS", maildirm->maildird->name, + maildirm->uniq_name); + } + else + { + + if (deleted) + snprintf (filename, len, "%s/cur/%sT", maildirm->maildird->name, + maildirm->uniq_name); + else + snprintf (filename, len, "%s/cur/%s", maildirm->maildird->name, + maildirm->uniq_name); + + + + } + } + else + { + if (deleted) + snprintf (filename, len, "%s/cur/%sT", maildirm->maildird->name, + maildirm->uniq_name); + else + snprintf (filename, len, "%s/cur/%s", maildirm->maildird->name, + maildirm->uniq_name); + } + + return filename; +} + +static void +maildir_destroy (mailbox_t mailbox) +{ + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *msg, *next; + + if (!maildird) + return; + + monitor_wrlock (mailbox->monitor); + msg = maildird->msg_head; + while (msg) + { + next = msg->next; + free (msg->uniq_name); + message_destroy (&msg->message, msg); + free (msg); + msg = next; + } + + if (maildird->name) + free (maildird->name); + + free (maildird); + mailbox->data = NULL; + monitor_unlock (mailbox->monitor); +} + +static int +maildir_close (mailbox_t mailbox) +{ + if (!mailbox) + return EINVAL; + return locker_unlock (mailbox->locker); +} + +static struct _maildir_message * +_maildir_get_message (struct _maildir_data *maildird, size_t msgno) +{ + size_t n; + struct _maildir_message *msg; + + for (n = 1, msg = maildird->msg_head; msg && n < msgno; + n++, msg = msg->next) + ; + + return msg; +} + +/* Find the message with the given uniq name */ +struct _maildir_message * +_maildir_get_message_seq1 (struct _maildir_data *maildird, char *name) +{ + struct _maildir_message *msg; + + char c = ','; + char *i1, *i2; + + for (msg = maildird->msg_head; msg != NULL; msg = msg->next) + { + + + if (msg == NULL) + break; + i1 = strchr (name, c); + i2 = strchr (msg->uniq_name, c); + + *i1 = 0; + *i2 = 0; + if (strcmp (name, msg->uniq_name) == 0) + { + *i1 = c; + *i2 = c; + break; + } + *i1 = c; + *i2 = c; + + } + + return msg; +} + + +static int +_maildir_attach_message (mailbox_t mailbox, struct _maildir_message *maildirm, + message_t * pmsg) { - return -1; + int status; + message_t msg; + + + /* Check if we already have it. */ + if (maildirm->message) + { + if (pmsg) + *pmsg = maildirm->message; + return 0; + } + + /* Get an empty message struct. */ + status = message_create (&msg, maildirm); + if (status != 0) + return status; + + /* Set the header. */ + { + header_t header = NULL; + status = header_create (&header, NULL, 0, msg); + if (status != 0) + { + free (maildirm->uniq_name); + message_destroy (&msg, maildirm); + return status; + } + header_set_fill (header, maildir_header_fill, msg); + header_set_size (header, maildir_header_size, msg); + header_set_lines (header, maildir_header_lines, msg); + /*FIXME: + header_set_get_fvalue (header, maildir_header_get_fvalue, msg); + */ + message_set_header (msg, header, maildirm); + } + + /* Set the attribute. */ + { + attribute_t attribute; + status = attribute_create (&attribute, msg); + if (status != 0) + { + free (maildirm->uniq_name); + + message_destroy (&msg, maildirm); + return status; + } + attribute_set_get_flags (attribute, maildir_get_attr_flags, msg); + attribute_set_set_flags (attribute, maildir_set_attr_flags, msg); + attribute_set_unset_flags (attribute, maildir_unset_attr_flags, msg); + message_set_attribute (msg, attribute, maildirm); + } + + /* Prepare the body. */ + { + + body_t body = NULL; + stream_t stream = NULL; + if ((status = body_create (&body, msg)) != 0 + || (status = stream_create (&stream, + mailbox->flags | MU_STREAM_SEEKABLE, + body)) != 0) + { + body_destroy (&body, msg); + stream_destroy (&stream, body); + free (maildirm->uniq_name); + + message_destroy (&msg, maildirm); + return status; + } + stream_set_read (stream, maildir_body_read, body); + stream_set_readline (stream, maildir_body_readline, body); + stream_set_size (stream, maildir_stream_size, body); + body_set_stream (body, stream, msg); + body_set_size (body, maildir_body_size, msg); + body_set_lines (body, maildir_body_lines, msg); + message_set_body (msg, body, maildirm); + } + + /* Set the envelope. */ + { + envelope_t envelope = NULL; + status = envelope_create (&envelope, msg); + if (status != 0) + { + free (maildirm->uniq_name); + + message_destroy (&msg, maildirm); + return status; + } + envelope_set_sender (envelope, maildir_envelope_sender, msg); + envelope_set_date (envelope, maildir_envelope_date, msg); + message_set_envelope (msg, envelope, maildirm); + } + + /* Set the UID. needed in maildir? */ +// message_set_uid (msg, maildir_message_uid, maildirm); + + /* Attach the message to the mailbox mbox data. */ + maildirm->message = msg; + message_set_mailbox (msg, mailbox, maildirm); + + + if (pmsg) + *pmsg = msg; + + return 0; } + static int -maildir_get_size (mailbox_t mailbox, off_t *psize) +maildir_get_message (mailbox_t mailbox, size_t msgno, message_t * pmsg) +{ + int status; + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + + /* Sanity checks. */ + if (pmsg == NULL || maildird == NULL) + return EINVAL; + + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + + if ((maildirm = _maildir_get_message (maildird, msgno)) == NULL) + return EINVAL; + return _maildir_attach_message (mailbox, maildirm, pmsg); +} + + +static FILE * +_maildir_tempfile (struct _maildir_data *maildird, char **namep) { - return -1; + int fd; + char *dir1 = (char *) malloc (strlen (maildird->name) + 5); + + strcpy (dir1, maildird->name); + strcat (dir1, "/tmp"); //radixs + fd = mu_tempfile (dir1, namep); + free (dir1); + if (fd == -1) + return NULL; + return fdopen (fd, "w"); } static int -maildir_save_attributes (mailbox_t mailbox) +_maildir_delim (char *str) { - return -1; + if (str[0] == '-') + { + for (; *str == '-'; str++) + ; + for (; *str == ' ' || *str == '\t'; str++) + ; + } + return str[0] == '\n'; } static int -maildir_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) +_maildir_message_save (struct _maildir_data *maildird, + struct _maildir_message *maildirm, int expunge) +{ + stream_t stream = NULL; + char *name = NULL, *buf = NULL, *msg_name; + size_t n, off = 0; + size_t bsize; + size_t nlines, nbytes; + size_t new_body_start, new_header_lines; + FILE *fp; + message_t msg = maildirm->message; + header_t hdr; + int status; + attribute_t attr; + body_t body; + char buffer[512]; + envelope_t env = NULL; + + char *pTmp, *pTmp1; + char *filename; + + +/* char *name1; + + if (maildirm->attr_flags & MU_ATTRIBUTE_READ || + maildirm->attr_flags & MU_ATTRIBUTE_SEEN) + { + name1 = (char *) malloc(strlen(name)+2); + strcpy(name1,name); + strcat(name1,"S"); + fp = _maildir_tempfile (maildirm->maildird, &name1); + + } + else*/ + fp = _maildir_tempfile (maildirm->maildird, &name); + + if (!fp) + return errno; + + message_size (msg, &bsize); + + /* Try to allocate large buffer */ + for (; bsize > 1; bsize /= 2) + if ((buf = malloc (bsize))) + break; + + if (!bsize) + return ENOMEM; + + /* Copy flags */ + message_get_header (msg, &hdr); + header_get_stream (hdr, &stream); + off = 0; + nlines = nbytes = 0; + while ((status = stream_readline (stream, buf, bsize, off, &n)) == 0 + && n != 0) + { + if (_maildir_delim (buf)) + break; + + if (!(strncasecmp (buf, "status:", 7) == 0 + || strncasecmp (buf, "x-imapbase:", 11) == 0 + || strncasecmp (buf, "x-uid:", 6) == 0 + || strncasecmp (buf, MU_HEADER_ENV_DATE ":", + sizeof (MU_HEADER_ENV_DATE)) == 0 + || strncasecmp (buf, MU_HEADER_ENV_SENDER ":", + sizeof (MU_HEADER_ENV_SENDER)) == 0)) + { + nlines++; + nbytes += fprintf (fp, "%s", buf); + } + + off += n; + } + + /* Add imapbase, no IMAP needed in maildir*/ +/* if (!maildird->msg_head || (maildird->msg_head == maildirm)) + { + nbytes += fprintf (fp, "X-IMAPbase: %lu %u\n", + (unsigned long) maildird->uidvalidity, + (unsigned) _maildir_next_seq (maildird)); + nlines++; + }*/ + + message_get_envelope (msg, &env); + if (envelope_date (env, buffer, sizeof buffer, &n) == 0 && n > 0) + { + /* NOTE: buffer is terminated with \n */ + char *p = buffer; + while (isspace (*p)) + p++; + nbytes += fprintf (fp, "%s: %s", MU_HEADER_ENV_DATE, p); + + if (*p && p[strlen (p) - 1] != '\n') + nbytes += fprintf (fp, "\n"); + + nlines++; + } + + if (envelope_sender (env, buffer, sizeof buffer, &n) == 0 && n > 0) + { + fprintf (fp, "%s: %s\n", MU_HEADER_ENV_SENDER, buffer); + nlines++; + } + + /* Add status */ + message_get_attribute (msg, &attr); + attribute_to_string (attr, buf, bsize, &n); + if (n) + { + nbytes += fprintf (fp, "%s", buf); + nlines++; + } + nbytes += fprintf (fp, "\n"); + nlines++; + + new_header_lines = nlines; + new_body_start = nbytes; + + /* Copy message body */ + + message_get_body (msg, &body); + body_get_stream (body, &stream); + off = 0; + nlines = 0; + while (stream_read (stream, buf, bsize, off, &n) == 0 && n != 0) + { + char *p; + for (p = buf; p < buf + n; p++) + if (*p == '\n') + nlines++; + fwrite (buf, 1, n, fp); + off += n; + nbytes += n; + } + + maildirm->header_lines = new_header_lines; + maildirm->body_start = new_body_start; + maildirm->body_lines = nlines; + maildirm->body_end = nbytes; + + free (buf); + fclose (fp); + + msg_name = _maildir_message_name (maildirm, maildirm->deleted); + rename (name, msg_name); + +// printf("%s, %s, %s\n",maildirm->uniq_name,name,msg_name); + + // the change the file name if the status changes from unread to read + // + + pTmp = strchr (maildirm->uniq_name, ','); + pTmp1 = strchr (pTmp, 'S'); + if (maildirm->attr_flags & MU_ATTRIBUTE_READ && pTmp1 == NULL) + { // to delete the original file if the status changes from unread to read + + filename = + (char *) malloc (strlen (maildirm->maildird->name) + 7 + + strlen (msg_name)); + + snprintf (filename, strlen (maildirm->maildird->name) + 7 + + strlen (msg_name), "%s/cur/%s", maildirm->maildird->name, + maildirm->uniq_name); + remove (filename); + free (maildirm->uniq_name); + maildirm->uniq_name = (char *) malloc (strlen (msg_name) + 1); + strcpy (maildirm->uniq_name, msg_name); + free (filename); + } + + + free (name); + free (msg_name); + + return 0; +} + +char * +_maildir_get_uniqname (int seq) { - return -1; + + char hostname[100]; + char *ptmp; + int pid; + + if (gethostname (hostname, 100) < 0) + strcpy (hostname, "localhost"); + + pid = getpid (); + + ptmp = + (char *) malloc ((int) get_log10 (time (NULL)) +1 + 1 + + (int) get_log10 ((double) pid) + 1 + 1 + + (int) get_log10 ((double) seq) + 1 + 1 + strlen (hostname) + 3 + + 2); + + sprintf (ptmp, "%d.%d_%d.%s:2,", time (NULL), pid, seq, hostname); + return ptmp; } static int maildir_append_message (mailbox_t mailbox, message_t msg) { - return -1; + int status; + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + + int msg_count; + + if (!mailbox || !msg) + return EINVAL; + + maildirm = calloc (1, sizeof (*maildirm)); + if (!maildirm) + return ENOMEM; + + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + + maildirm->maildird = maildird; +// maildirm->seq_number = _maildir_next_seq (maildird); + msg_count = maildird->msg_count; + maildirm->message = msg; + maildirm->uniq_name = _maildir_get_uniqname (msg_count); + status = _maildir_message_save (maildird, maildirm, 0); + maildirm->message = NULL; + /* Insert and re-scan the message */ + _maildir_message_insert (maildird, maildirm); + return status; } static int -maildir_messages_count (mailbox_t mailbox, size_t *pcount) +maildir_messages_count (mailbox_t mailbox, size_t * pcount) { - return -1; + struct _maildir_data *maildird = mailbox->data; + + if (maildird == NULL) + return EINVAL; + + if (!maildir_is_updated (mailbox)) + return maildir_scan0 (mailbox, maildird->msg_count, pcount, 0); + + if (pcount) + *pcount = maildird->msg_count; + + return 0; } /* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN ('O' in the Status header), i.e. a message that is first seen by the current session (see attributes.h) */ static int -maildir_messages_recent (mailbox_t mailbox, size_t *pcount) +maildir_messages_recent (mailbox_t mailbox, size_t * pcount) +{ + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + size_t count; + + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + int status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + count = 0; + for (maildirm = maildird->msg_head; maildirm; maildirm = maildirm->next) + { + if (MU_ATTRIBUTE_IS_UNSEEN (maildirm->attr_flags)) + count++; + } + *pcount = count; + return 0; +} + +/* An "unseen" message is the one that has not been read yet */ +static int +maildir_message_unseen (mailbox_t mailbox, size_t * pmsgno) { - return -1; + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + size_t i, unseen; + + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + int status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + for (unseen = i = 1, maildirm = maildird->msg_head; maildirm; + i++, maildirm = maildirm->next) + { + if (MU_ATTRIBUTE_IS_UNREAD (maildirm->attr_flags)) + { + unseen = i; + break; + } + } + *pmsgno = unseen; + return 0; } +static int +maildir_expunge (mailbox_t mailbox) +{ + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + + if (maildird == NULL) + return EINVAL; + + if (maildird->msg_count == 0) + return 0; + + /* Find the first dirty(modified) message. */ + for (maildirm = maildird->msg_head; maildirm; maildirm = maildirm->next) + { + if ((maildirm->attr_flags & MU_ATTRIBUTE_MODIFIED) || + (maildirm->attr_flags & MU_ATTRIBUTE_DELETED) || + (maildirm->message && message_is_modified (maildirm->message))) + break; + } + + if (!maildirm) + return 0; /* Nothing changed, just return. */ + + while (maildirm) + { + struct _maildir_message *next = maildirm->next; + + if (maildirm->attr_flags & MU_ATTRIBUTE_DELETED) + { + if (!maildirm->deleted) + { + char *old_name, *new_name; + /* Rename original message */ + old_name = _maildir_message_name (maildirm, 0); + new_name = _maildir_message_name (maildirm, 1); + rename (old_name, new_name); + free (old_name); + free (new_name); + } + _maildir_message_delete (maildird, maildirm); + } + else if ((maildirm->attr_flags & MU_ATTRIBUTE_MODIFIED) + || (maildirm->message + && message_is_modified (maildirm->message))) + { + _maildir_attach_message (mailbox, maildirm, NULL); + maildirm->deleted = maildirm->attr_flags & MU_ATTRIBUTE_DELETED; + _maildir_message_save (maildird, maildirm, 1); + } + maildirm = next; + } + + return 0; +} + +/* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN + ('O' in the Status header), i.e. a message that is first seen + by the current session (see attributes.h) */ + /* An "unseen" message is the one that has not been read yet */ + + static int -maildir_message_unseen (mailbox_t mailbox, size_t *pmsgno) +maildir_save_attributes (mailbox_t mailbox) { - return -1; + struct _maildir_data *maildird = mailbox->data; + struct _maildir_message *maildirm; + + if (maildird == NULL) + return EINVAL; + + if (maildird->msg_count == 0) + return 0; + + /* Find the first dirty(modified) message. */ + for (maildirm = maildird->msg_head; maildirm; maildirm = maildirm->next) + { + if ((maildirm->attr_flags & MU_ATTRIBUTE_MODIFIED) + || (maildirm->message && message_is_modified (maildirm->message))) + break; + } + + if (!maildirm) + return 0; /* Nothing changed, just return. */ + + while (maildirm) + { + struct _maildir_message *next = maildirm->next; + + if ((maildirm->attr_flags & MU_ATTRIBUTE_MODIFIED) + || (maildirm->message && message_is_modified (maildirm->message))) + { + _maildir_attach_message (mailbox, maildirm, NULL); + maildirm->deleted = maildirm->attr_flags & MU_ATTRIBUTE_DELETED; + _maildir_message_save (maildird, maildirm, 0); + } + maildirm = next; + } + + return 0; } static int maildir_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity) { - return -1; + struct _maildir_data *maildird = mailbox->data; + int status = maildir_messages_count (mailbox, NULL); + if (status != 0) + return status; + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + if (puidvalidity) + *puidvalidity = maildird->uidvalidity; + return 0; } +#if 0 static int -maildir_uidnext (mailbox_t mailbox, size_t *puidnext) +maildir_uidnext (mailbox_t mailbox, size_t * puidnext) +{ + struct _maildir_data *maildird = mailbox->data; + int status = maildir_messages_count (mailbox, NULL); + if (status != 0) + return status; + /* If we did not start a scanning yet do it now. */ + if (maildird->msg_count == 0) + { + status = maildir_scan0 (mailbox, 1, NULL, 0); + if (status != 0) + return status; + } + if (puidnext) + *puidnext = _maildir_next_seq (maildird); + return 0; +} +#endif + +/* FIXME: effectively the same as mbox_cleanup */ +static void +maildir_cleanup (void *arg) { - return -1; + mailbox_t mailbox = arg; + monitor_unlock (mailbox->monitor); + locker_unlock (mailbox->locker); } +/* Insert message msg into the message list on the appropriate position */ +/* ??? */ +void +_maildir_message_insert (struct _maildir_data *maildird, + struct _maildir_message *msg) +{ + struct _maildir_message *p; + struct _maildir_message *prev; + char *uniq_name = msg->uniq_name; + + for (p = maildird->msg_head; p && strcmp(p->uniq_name, uniq_name)< 0; p = p->next) + ; + + if (!p) + { + msg->next = NULL; + msg->prev = maildird->msg_tail; + maildird->msg_tail = msg; + if (!maildird->msg_head) + maildird->msg_head = msg; + } + else + { + msg->next = p; + msg->prev = p->prev; + p->prev = msg; + } + if ((prev = msg->prev) != NULL) + prev->next = msg; + else + maildird->msg_head = msg; + msg->maildird = maildird; + maildird->msg_count++; +} + +void +_maildir_message_delete (struct _maildir_data *maildird, + struct _maildir_message *msg) +{ + struct _maildir_message *p; + struct _maildir_message **pp = maildir_pool_lookup (msg); + + if (pp) + *pp = NULL; + + if ((p = msg->next) != NULL) + p->prev = msg->prev; + else + maildird->msg_tail = msg->prev; + + if ((p = msg->prev) != NULL) + p->next = msg->next; + else + maildird->msg_head = msg->next; + + free (msg->uniq_name); // free the uniq_name, radixs + message_destroy (&msg->message, msg); + free (msg); + maildird->msg_count--; +} + +/* Scan given message and fill maildir_message_t fields. + NOTE: the function assumes maildirm->stream != NULL. */ +static int +maildir_scan_message (struct _maildir_message *maildirm) +{ + stream_t stream = maildirm->stream; + char buf[1024]; + off_t off = 0; + size_t n; + int status; + int in_header = 1; + size_t hlines = 0; + size_t blines = 0; + size_t body_start = 0; + + /* Check if the message was modified after the last scan */ + if (maildirm->mtime) + { + struct stat st; + char *msg_name = _maildir_message_name (maildirm, maildirm->deleted); + + if (stat (msg_name, &st) == 0 && st.st_mtime == maildirm->mtime) + { + /* Nothing to do */ + free (msg_name); + return 0; + } + free (msg_name); + } + + while ((status = stream_readline (stream, buf, sizeof (buf), off, &n) == 0) + && n != 0) + { + if (in_header) + { + if (buf[0] == '\n') + { + in_header = 0; + body_start = off + 1; + } + if (buf[n - 1] == '\n') + hlines++; + + /* Process particular attributes */ + if (strncasecmp (buf, "status:", 7) == 0) + { + int deleted = maildirm->attr_flags & MU_ATTRIBUTE_DELETED; + string_to_flags (buf, &maildirm->attr_flags); + maildirm->attr_flags |= deleted; + } + else if (strncasecmp (buf, "x-imapbase:", 11) == 0) + { + char *p; + maildirm->maildird->uidvalidity = strtoul (buf + 11, &p, 10); + /* second number is next uid. Ignored */ + } + } + else + { + if (buf[n - 1] == '\n') + blines++; + } + off += n; + } + + if (!body_start) + body_start = off; + maildirm->header_lines = hlines; + maildirm->body_lines = blines; + maildirm->body_start = body_start; + maildirm->body_end = off; + return 0; +} + + +static int +maildir_get_size (mailbox_t mailbox ARG_UNUSED, off_t * psize ARG_UNUSED) +{ + /*FIXME*/ return ENOSYS; +} + +/* Return number of open streams residing in a message pool */ +static int +maildir_pool_open_count (struct _maildir_data *maildird) +{ + int cnt = maildird->pool_last - maildird->pool_first; + if (cnt < 0) + cnt += MAX_OPEN_STREAMS1; + return cnt; +} + +/* Look up a _maildir_message in the pool of open messages. + If the message is found in the pool, returns the address of + the pool slot occupied by it. Otherwise returns NULL. */ +struct _maildir_message ** +maildir_pool_lookup (struct _maildir_message *maildirm) +{ + struct _maildir_data *maildird = maildirm->maildird; + int i; + + for (i = maildird->pool_first; i != maildird->pool_last;) + { + if (maildird->msg_pool[i] == maildirm) + return &maildird->msg_pool[i]; + if (++i == MAX_OPEN_STREAMS1) + i = 0; + } + return NULL; +} + +/* Open a stream associated with the message maildirm. If the stream is + already open, do nothing. + NOTE: We could have reused the NULL holes in the msg_pool, but + that hardly is worth the effort, since the holes appear only when + expunging. On the other hand this may be useful when MAX_OPEN_STREAMS + size is very big. "Premature optimization is the root of all evil" */ +int +maildir_pool_open (struct _maildir_message *maildirm) +{ + struct _maildir_data *maildird = maildirm->maildird; + if (maildir_pool_lookup (maildirm)) + return 0; + if (maildir_pool_open_count (maildird) == MAX_OPEN_STREAMS1 - 1) + { + maildir_message_stream_close (maildird-> + msg_pool[maildird->pool_first++]); + maildird->pool_first %= MAX_OPEN_STREAMS1; + } + maildir_message_stream_open (maildirm); + maildird->msg_pool[maildird->pool_last++] = maildirm; + maildird->pool_last %= MAX_OPEN_STREAMS1; + return 0; +} + +/* Attach a stream to a given message structure. The latter is supposed + to be already added to the open message pool. */ +int +maildir_message_stream_open (struct _maildir_message *maildirm) +{ + struct _maildir_data *maildird = maildirm->maildird; + char *filename = NULL; + int status; + int flags = MU_STREAM_ALLOW_LINKS; + filename = _maildir_message_name (maildirm, maildirm->deleted); + + if (!filename) + return ENOMEM; + + /* The message should be at least readable */ + if (maildird->mailbox-> + flags & (MU_STREAM_RDWR | MU_STREAM_WRITE | MU_STREAM_APPEND)) + flags |= MU_STREAM_RDWR; + else + flags |= MU_STREAM_READ; + status = file_stream_create (&maildirm->stream, filename, flags); + + free (filename); + + if (status != 0) + return status; + + status = stream_open (maildirm->stream); + + if (status != 0) + stream_destroy (&maildirm->stream, NULL); + + if (status == 0) + status = maildir_scan_message (maildirm); + + return status; +} + +/* Close the stream associated with the given message. */ +void +maildir_message_stream_close (struct _maildir_message *maildirm) +{ + if (maildirm) + { + stream_close (maildirm->stream); + maildirm->stream = NULL; + } +} + +void +maildir_check_message (struct _maildir_message *maildirm) +{ + if (maildirm->body_end == 0) + maildir_pool_open (maildirm); +} + +/* Reading functions */ + +static int +maildir_readstream (struct _maildir_message *maildirm, char *buffer, + size_t buflen, off_t off, size_t * pnread, int isreadline, + off_t start, off_t end) +{ + size_t nread = 0; + int status = 0; + off_t ln; + + if (buffer == NULL || buflen == 0) + { + if (pnread) + *pnread = nread; + return 0; + } + + monitor_rdlock (maildirm->maildird->mailbox->monitor); +#ifdef WITH_PTHREAD + /* read() is cancellation point since we're doing a potentially + long operation. Lets make sure we clean the state. */ + pthread_cleanup_push (maildir_cleanup, + (void *) maildirm->maildird->mailbox); +#endif + + ln = end - (start + off); + if (ln > 0) + { + /* Position the file pointer and the buffer. */ + nread = ((size_t) ln < buflen) ? (size_t) ln : buflen; + if (isreadline) + status = stream_readline (maildirm->stream, buffer, buflen, + start + off, &nread); + else + status = stream_read (maildirm->stream, buffer, nread, + start + off, &nread); + } + + + monitor_unlock (maildirm->maildird->mailbox->monitor); +#ifdef WITH_PTHREAD + pthread_cleanup_pop (0); +#endif + + if (pnread) + *pnread = nread; +// printf("buf: %s\n",buffer); + return status; +} + +static int +maildir_body_read (stream_t is, char *buffer, size_t buflen, off_t off, + size_t * pnread) +{ + body_t body = stream_get_owner (is); + message_t msg = body_get_owner (body); + struct _maildir_message *maildirm = message_get_owner (msg); + maildir_pool_open (maildirm); + return maildir_readstream (maildirm, buffer, buflen, off, pnread, 0, + maildirm->body_start, maildirm->body_end); +} + +static int +maildir_body_readline (stream_t is, char *buffer, size_t buflen, + off_t off, size_t * pnread) +{ + body_t body = stream_get_owner (is); + message_t msg = body_get_owner (body); + struct _maildir_message *maildirm = message_get_owner (msg); + maildir_pool_open (maildirm); + return maildir_readstream (maildirm, buffer, buflen, off, pnread, 1, + maildirm->body_start, maildirm->body_end); +} + +/* Return corresponding sizes */ + +static int +maildir_stream_size (stream_t stream, off_t * psize) +{ + body_t body = stream_get_owner (stream); + return maildir_body_size (body, (size_t *) psize); +} + +static int +maildir_body_size (body_t body, size_t * psize) +{ + message_t msg = body_get_owner (body); + struct _maildir_message *maildirm = message_get_owner (msg); + if (maildirm == NULL) + return EINVAL; + maildir_check_message (maildirm); + if (psize) + *psize = maildirm->body_end - maildirm->body_start; + return 0; +} + +static int +maildir_body_lines (body_t body, size_t * plines) +{ + message_t msg = body_get_owner (body); + struct _maildir_message *maildirm = message_get_owner (msg); + if (maildirm == NULL) + return EINVAL; + maildir_check_message (maildirm); + if (plines) + *plines = maildirm->body_lines; + return 0; +} + +#if 0 +/* if needed in maildir, should create a machenism to generate uid*/ +static int +maildir_message_uid (message_t msg, size_t * puid) +{ + struct _maildir_message *maildirm = message_get_owner (msg); + if (puid) + *puid = maildirm->seq_number; + return 0; +} +#endif + +/* Headers */ +static int +maildir_header_fill (header_t header, char *buffer, size_t len, + off_t off, size_t * pnread) +{ + message_t msg = header_get_owner (header); + struct _maildir_message *maildirm = message_get_owner (msg); + + +// printf("maildir header fill\n"); + + maildir_pool_open (maildirm); + return maildir_readstream (maildirm, buffer, len, off, pnread, 0, + 0, maildirm->body_start); +} + +static int +maildir_header_size (header_t header, size_t * psize) +{ + message_t msg = header_get_owner (header); + struct _maildir_message *maildirm = message_get_owner (msg); + if (maildirm == NULL) + return EINVAL; + maildir_check_message (maildirm); + if (psize) + *psize = maildirm->body_start; + return 0; +} + +static int +maildir_header_lines (header_t header, size_t * plines) +{ + message_t msg = header_get_owner (header); + struct _maildir_message *maildirm = message_get_owner (msg); + if (maildirm == NULL) + return EINVAL; + maildir_check_message (maildirm); + if (plines) + *plines = maildirm->header_lines; + return 0; +} + +/* Attributes */ +static int +maildir_get_attr_flags (attribute_t attr, int *pflags) +{ + message_t msg = attribute_get_owner (attr); + struct _maildir_message *maildirm = message_get_owner (msg); + + if (maildirm == NULL) + return EINVAL; + if (pflags) + *pflags = maildirm->attr_flags; + return 0; +} + +static int +maildir_set_attr_flags (attribute_t attr, int flags) +{ + message_t msg = attribute_get_owner (attr); + struct _maildir_message *maildirm = message_get_owner (msg); + + if (maildirm == NULL) + return EINVAL; + maildirm->attr_flags |= flags; + return 0; +} + +static int +maildir_unset_attr_flags (attribute_t attr, int flags) +{ + message_t msg = attribute_get_owner (attr); + struct _maildir_message *maildirm = message_get_owner (msg); + + if (maildirm == NULL) + return EINVAL; + maildirm->attr_flags &= ~flags; + return 0; +} + +/* Envelope */ +static int +maildir_envelope_date (envelope_t envelope, char *buf, size_t len, + size_t * psize) +{ + message_t msg = envelope_get_owner (envelope); + struct _maildir_message *maildirm = message_get_owner (msg); + header_t hdr = NULL; + char *from; + int status; + + + if (maildirm == NULL) + return EINVAL; + + + if ((status = message_get_header (msg, &hdr)) != 0) + return status; + + if (header_aget_value (hdr, "Date", &from)) + return ENOSYS; + + + /* Format: "sender date" */ + if (buf && len > 0) + { + len--; /* Leave space for the null. */ + strncpy (buf, from, len); + if (strlen (from) < len) + { + len = strlen (buf); + buf[len++] = '\n'; + } + buf[len] = '\0'; + } + else + len = 0; + + //printf("from %s buf %s\n",from,buf); + + if (psize) + *psize = len; + return 0; +} + +static int +maildir_envelope_sender (envelope_t envelope, char *buf, size_t len, + size_t * psize) +{ + message_t msg = envelope_get_owner (envelope); + struct _maildir_message *maildirm = message_get_owner (msg); + header_t hdr = NULL; + char *from; + int status; + + if (maildirm == NULL) + return EINVAL; + + if ((status = message_get_header (msg, &hdr)) != 0) + return status; + if (header_aget_value (hdr, MU_HEADER_ENV_SENDER, &from)) + return ENOSYS; + + if (buf && len > 0) + { + int slen = strlen (from); + + if (len < slen + 1) + slen = len - 1; + memcpy (buf, from, slen); + buf[slen] = 0; + } + else + len = 0; + + if (psize) + *psize = len; + printf ("sender: %s\n", buf); + return 0; +} diff -Naur mailutils-0.4.org/mailbox/maildir/url.c mailutils-0.4/mailbox/maildir/url.c --- mailutils-0.4.org/mailbox/maildir/url.c 1970-01-01 07:30:00.000000000 +0730 +++ mailutils-0.4/mailbox/maildir/url.c 2003-10-28 19:23:41.000000000 +0800 @@ -0,0 +1,74 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Radixs Pte Ltd*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include +#include +#include + +#include +#include + +void +url_maildir_destroy (url_t url) +{ + +} + + +int +_url_maildir_init (url_t url) +{ + const char *name = url_to_string (url); + size_t len = strlen (name); + + /* reject the obvious */ + if (name == NULL + || strncmp (MU_MAILDIR_SCHEME, name, MU_MAILDIR_SCHEME_LEN) != 0 + || len < (MU_MAILDIR_SCHEME_LEN + 1) /* (scheme)+1(path) */ ) + return EINVAL; + + /* do I need to decode url encoding '% hex hex' ? */ + + /* TYPE */ + url->_destroy = url_maildir_destroy; + + /* SCHEME */ + (url_t) url->scheme = strdup (MU_MAILDIR_SCHEME); + if (url->scheme == NULL) + { + url_maildir_destroy (url); + return ENOMEM; + } + + /* PATH */ + name += MU_MAILDIR_SCHEME_LEN; /* pass the scheme */ + url->path = strdup (name); + if (url->path == NULL) + { + url_maildir_destroy (url); + return ENOMEM; + } + + return 0; +}