[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-mailutils] Maildir append
From: |
Jeff Williams |
Subject: |
[bug-mailutils] Maildir append |
Date: |
Tue, 14 Oct 2003 20:24:57 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.4) Gecko/20030827 Debian/1.4-3 |
This is a patch against the current CVS which allows for mail to be
appended to a maildir format mailbox. This is to enable mail.local to
deliver to maildirs if it is changed to use mailbox_append. It worked
with my hacked version of mail.local, but it could probably do with a
look over and some more testing. I will try to add some more of the
maildir functions when I get time.
Jeff
diff -urN -x CVS mailutils-orig/configure.ac mailutils/configure.ac
--- mailutils-orig/configure.ac 2003-10-14 19:33:20.000000000 +0200
+++ mailutils/configure.ac 2003-10-14 19:23:38.000000000 +0200
@@ -480,6 +480,8 @@
BUILD_MH_LIBRARIES='$(LIBRARIES_MH)';
BUILD_MH_EXEC_HOOK=mh_finish_install])
+MU_ENABLE_SUPPORT(maildir)
+
dnl AC_ARG_ENABLE([experimental],
dnl AC_HELP_STRING([--enable-experimental],
dnl [build experimental and/or unfinished
utilities]),
diff -urN -x CVS mailutils-orig/include/mailutils/registrar.h
mailutils/include/mailutils/registrar.h
--- mailutils-orig/include/mailutils/registrar.h 2003-10-14
19:33:24.000000000 +0200
+++ mailutils/include/mailutils/registrar.h 2003-10-09 17:04:57.000000000
+0200
@@ -97,6 +97,8 @@
extern record_t path_record;
/* Local MH, "mh:" */
extern record_t mh_record;
+/* Local MH, "mh:" */
+extern record_t maildir_record;
/* SMTP mailer, "smtp://" */
extern record_t smtp_record;
diff -urN -x CVS mailutils-orig/mailbox/include/registrar0.h
mailutils/mailbox/include/registrar0.h
--- mailutils-orig/mailbox/include/registrar0.h 2003-10-14 19:35:10.000000000
+0200
+++ mailutils/mailbox/include/registrar0.h 2003-09-26 11:10:23.000000000
+0200
@@ -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 -urN -x CVS mailutils-orig/mailbox/maildir/folder.c
mailutils/mailbox/maildir/folder.c
--- mailutils-orig/mailbox/maildir/folder.c 1970-01-01 01:00:00.000000000
+0100
+++ mailutils/mailbox/maildir/folder.c 2003-10-08 16:55:33.000000000 +0200
@@ -0,0 +1,143 @@
+/* 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 <config.h>
+#endif
+
+#ifdef ENABLE_MAILDIR
+
+#include <errno.h>
+
+#include <folder0.h>
+#include <registrar0.h>
+
+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;
+
+
+/* lsub/subscribe/unsubscribe are not needed. */
+static void folder_maildir_destroy __P ((folder_t));
+static int folder_maildir_open __P ((folder_t, int));
+static int folder_maildir_close __P ((folder_t));
+static int folder_maildir_delete __P ((folder_t, const char *));
+static int folder_maildir_rename __P ((folder_t , const char *,
+ const char *));
+static int folder_maildir_list __P ((folder_t, const char *, const char
*,
+ struct folder_list *));
+static int folder_maildir_subscribe __P ((folder_t, const char *));
+static int folder_maildir_unsubscribe __P ((folder_t, const char *));
+static int folder_maildir_lsub __P ((folder_t, const char *, const char
*,
+ struct folder_list *));
+
+
+int
+_folder_maildir_init (folder_t folder)
+{
+ /* store some local data about the folder */
+ /* folder->data = NULL; */
+
+ /* assign the functions */
+ folder->_destroy = folder_maildir_destroy;
+ folder->_open = folder_maildir_open;
+ folder->_close = folder_maildir_close;
+
+ folder->_list = folder_maildir_list;
+ folder->_lsub = folder_maildir_lsub;
+ folder->_subscribe = folder_maildir_subscribe;
+ folder->_unsubscribe = folder_maildir_unsubscribe;
+ folder->_delete = folder_maildir_delete;
+ folder->_rename = folder_maildir_rename;
+
+ return 0;
+}
+
+void
+folder_maildir_destroy (folder_t folder)
+{
+ /* free the local data */
+}
+
+int
+folder_maildir_open (folder_t folder, int flags)
+{
+ /* maybe check for MU_STREAM_CREAT */
+ return 0;
+}
+
+int
+folder_maildir_close (folder_t folder)
+{
+ return 0;
+}
+
+int
+folder_maildir_delete (folder_t folder, const char *filename)
+{
+ return 0;
+}
+
+int
+folder_maildir_rename (folder_t folder, const char *oldpath, const char
*newpath)
+{
+ return 0;
+}
+
+int
+folder_maildir_list (folder_t folder, const char *dirname, const char *pattern,
+ struct folder_list *pflist)
+{
+ return 0;
+}
+
+int
+folder_maildir_subscribe (folder_t folder, const char *name)
+{
+ return 0;
+}
+
+int
+folder_maildir_unsubscribe (folder_t folder, const char *name)
+{
+ return 0;
+}
+
+int
+folder_maildir_lsub (folder_t folder, const char *ref ARG_UNUSED, const char
*name,
+ struct folder_list *pflist)
+{
+ return 0;
+}
+
+#else /* ENABLE_MAILDIR */
+#include <stdio.h>
+#include <registrar0.h>
+record_t maildir_record = NULL;
+#endif /* ENABLE_MAILDIR */
diff -urN -x CVS mailutils-orig/mailbox/maildir/Makefile.am
mailutils/mailbox/maildir/Makefile.am
--- mailutils-orig/mailbox/maildir/Makefile.am 2003-10-14 19:33:26.000000000
+0200
+++ mailutils/mailbox/maildir/Makefile.am 2003-10-08 15:02:52.000000000
+0200
@@ -24,6 +24,7 @@
lib_LTLIBRARIES = libmu_maildir.la
libmu_maildir_la_SOURCES = \
- mbox.c
-
+ mbox.c \
+ url.c \
+ folder.c
diff -urN -x CVS mailutils-orig/mailbox/maildir/mbox.c
mailutils/mailbox/maildir/mbox.c
--- mailutils-orig/mailbox/maildir/mbox.c 2003-10-14 19:34:01.000000000
+0200
+++ mailutils/mailbox/maildir/mbox.c 2003-10-14 20:06:11.000000000 +0200
@@ -21,6 +21,8 @@
# include <config.h>
#endif
+#ifdef ENABLE_MAILDIR
+
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
@@ -125,12 +127,27 @@
return;
}
-/* Open the file. For MU_STREAM_READ, the code tries mmap() first and fall
- back to normal file. */
+/* Open the maildir
+ *
+ * We need to do a bit of voodoo here with setting the stream
+ * since mail.local calls this with flags MU_STREAM_RDWR|MU_STREAM_CREAT
+ * and then proceeds to get and write to the stream. Therefore
+ * if the MU_STREAM_CREAT flag is given, we should create a file in
+ * the tmp/ dir and attach a file_stream to it.
+ *
+ * Actually, we could make a stream which handles maildir
+ * But how to handle offsets? since different offsets will actually
+ * be different files. This means scanning the whole directory which
+ * is not a good option.
+ *
+ * For now we don't bother about a stream.
+ *
+ */
static int
maildir_open (mailbox_t mailbox, int flags)
{
- return -1;
+ mailbox->flags = flags;
+ return 0;
}
static int
@@ -139,19 +156,18 @@
return -1;
}
-/* Cover function that call the real thing, maildir_scan(), with
- notification set. */
static int
maildir_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
{
+ /* some useful stuff:
+ *
+ * opendir
+ * readdir
+ *
+ */
return 0;
}
-/* 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)
{
@@ -185,7 +201,280 @@
static int
maildir_append_message (mailbox_t mailbox, message_t msg)
{
- return -1;
+ size_t dir_len;
+ char nl = '\n';
+ char *dir;
+ struct timeval tv;
+ pid_t pid;
+ char *tmpname;
+ char *newname;
+ int unique = 0;
+ int status = 0;
+ struct stat st;
+
+ /* buffers for the strings used for making the
+ * new file name
+ * what size should these be?
+ */
+ char hostname[256];
+ char pid_buf[256];
+ char time_buf[256];
+ char usec_buf[256];
+ char unique_buf[256];
+ char dev_buf[256];
+ char ino_buf[256];
+ char size_buf[256];
+
+ /* what we need for creating the temp file is:
+ * the dir to deliver to (get from mailbox)
+ * a unique number (a counter which goes up with every attempt)
+ * hostname gethostname(2)
+ * time gettimeofday(2)
+ * usec gettimeofday(2)
+ * pid getpid(2)
+ *
+ * "time.MusecPpid_unique.host"
+ *
+ * stat(2) must return ENOENT
+ *
+ * write to file and do fstat(2)
+ *
+ * then when we are moving to the new dir we need:
+ * size fstat(2)
+ * inode fstat(2)
+ * dev fstat(2)
+ *
+ * "time.MusecPpidVdevIino_unique.host,S=cnt"
+ */
+
+ /* get the path to the maildir */
+ url_get_path (mailbox->url, NULL, 0, &dir_len);
+ dir = calloc (dir_len + 1, sizeof (char));
+ if (dir == NULL)
+ {
+ return ENOMEM;
+ }
+ url_get_path (mailbox->url, dir, dir_len + 1, NULL);
+
+ /* get the hostname */
+ hostname[sizeof(hostname)-1] = 0; /* cause gethostname doesn't necessarily
do this */
+ if (gethostname(hostname, sizeof(hostname)-1) < 0)
+ strcpy(hostname, "localhost");
+
+ /* get the pid */
+ pid = getpid();
+ if (snprintf(pid_buf, sizeof(pid_buf), "%d", pid))
+ {
+ /* allocated buf too small */
+ free (dir);
+ return ENOMEM;
+ }
+
+ /* this has 100 goes. Should have some sort of time limit
+ (* loop while the tempfile exists */
+ for (unique = 0; ((status == 0) && (unique < 100)); unique++)
+ {
+ /* get the time and usec */
+ gettimeofday(&tv, NULL);
+ if (snprintf(time_buf, sizeof(time_buf), "%ld", tv.tv_sec))
+ {
+ /* allocated buf too small */
+ free (dir);
+ return ENOMEM;
+ }
+ if (snprintf(usec_buf, sizeof(usec_buf), "%ld", tv.tv_usec))
+ {
+ /* allocated buf too small */
+ free (dir);
+ return ENOMEM;
+ }
+
+ if (snprintf(unique_buf, sizeof(unique_buf), "%d", unique))
+ {
+ /* allocated buf too small */
+ free (dir);
+ return ENOMEM;
+ }
+
+ /* allocate memory for the tmpname */
+ tmpname = malloc(strlen(dir) + strlen(time_buf)
+ + strlen(usec_buf) + strlen(pid_buf) + strlen(unique_buf)
+ + strlen(hostname) + 11);
+
+ if (!tmpname)
+ {
+ free (dir);
+ return ENOMEM;
+ }
+
+ /* make the temp file name */
+ strcpy(tmpname, dir);
+ strcat(tmpname, "/tmp/");
+ strcat(tmpname, time_buf);
+ strcat(tmpname, ".M");
+ strcat(tmpname, usec_buf);
+ strcat(tmpname, "P");
+ strcat(tmpname, pid_buf);
+ strcat(tmpname, "_");
+ strcat(tmpname, unique_buf);
+ strcat(tmpname, ".");
+ strcat(tmpname, hostname);
+
+ /* stat the file */
+ status = stat(tmpname, &st);
+
+ /* if the tempfile exists sleep for 2 seconds before
+ * trying again
+ * Should we be trying again for all errors, or just
+ * when the filename exists?
+ */
+ if (status == 0) sleep(2);
+ }
+
+ if (errno != ENOENT)
+ {
+ /* we have other problems */
+ free (dir);
+ free (tmpname);
+ return errno;
+ }
+
+ /* create the output stream */
+ stream_t os = NULL;
+ status = file_stream_create (&os, tmpname, MU_STREAM_WRITE|MU_STREAM_CREAT);
+ if (status != 0)
+ {
+ free (dir);
+ free (tmpname);
+ return status;
+ }
+
+ status = stream_open (os);
+ if (status != 0)
+ {
+ free (dir);
+ free (tmpname);
+ return -1;
+ }
+
+ {
+ /* Append the Message. */
+ char buffer[1024];
+ size_t nread = 0;
+ size_t nwrite = 0;
+ stream_t is = NULL;
+ int is_off = 0;
+ int os_off = 0;
+ message_get_stream (msg, &is);
+ do
+ {
+ status = stream_read (is, buffer, sizeof (buffer), is_off, &nread);
+ if (status != 0)
+ {
+ if (status != EAGAIN)
+ {
+ is_off = 0;
+ }
+ stream_flush (os);
+ return status;
+ }
+ status = stream_write (os, buffer, nread, os_off, &nwrite);
+ if (status != 0)
+ {
+ }
+ is_off += nread;
+ os_off += nwrite;
+ }
+ while (nread > 0);
+ nwrite = 0;
+ stream_write (os, &nl, 1, os_off, &nwrite);
+ os_off += nwrite;
+ }
+
+ /* check the write was successful */
+
+ /* fstat the file */
+ {
+ int fd;
+ status = stream_get_fd(os, &fd);
+ if (status != 0)
+ {
+ free (dir);
+ free (tmpname);
+ return status;
+ }
+ if (fstat(fd, &st) != 0)
+ {
+ free (dir);
+ free (tmpname);
+ return errno;
+ }
+
+ if (snprintf(dev_buf, sizeof(dev_buf), "%d", st.st_dev))
+ {
+ /* allocated buf too small */
+ free (dir);
+ free (tmpname);
+ return ENOMEM;
+ }
+ if (snprintf(ino_buf, sizeof(ino_buf), "%ld", st.st_ino))
+ {
+ /* allocated buf too small */
+ free (dir);
+ free (tmpname);
+ return ENOMEM;
+ }
+ if (snprintf(size_buf, sizeof(size_buf), "%ld", st.st_size))
+ {
+ /* allocated buf too small */
+ free (dir);
+ free (tmpname);
+ return ENOMEM;
+ }
+ }
+
+ /* allocate memory for the tmpname */
+ newname = malloc(strlen(dir) + strlen(time_buf)
+ + strlen(usec_buf) + strlen(pid_buf) + strlen(dev_buf)
+ + strlen(ino_buf) + strlen(unique_buf) + strlen(hostname)
+ + strlen(size_buf) + 15);
+
+ if (!newname)
+ {
+ free (dir);
+ free (tmpname);
+ return ENOMEM;
+ }
+
+ /* generate new file name */
+ strcpy(newname, dir);
+ strcat(newname, "/new/");
+ strcat(newname, time_buf);
+ strcat(newname, ".M");
+ strcat(newname, usec_buf);
+ strcat(newname, "P");
+ strcat(newname, pid_buf);
+ strcat(newname, "V");
+ strcat(newname, dev_buf);
+ strcat(newname, "I");
+ strcat(newname, ino_buf);
+ strcat(newname, "_");
+ strcat(newname, unique_buf);
+ strcat(newname, ".");
+ strcat(newname, hostname);
+ strcat(newname, ",S=");
+ strcat(newname, size_buf);
+
+ /* rename tmpfile to newfile */
+ if (rename(tmpname, newname))
+ {
+ free (dir);
+ free (tmpname);
+ free (newname);
+ return errno;
+ }
+
+ return 0;
}
static int
@@ -222,3 +511,9 @@
return -1;
}
+static int
+maildir_get_new_message_stream(mailbox_t mailbox)
+{
+}
+
+#endif /* ENABLE_MAILDIR */
diff -urN -x CVS mailutils-orig/mailbox/maildir/url.c
mailutils/mailbox/maildir/url.c
--- mailutils-orig/mailbox/maildir/url.c 1970-01-01 01:00:00.000000000
+0100
+++ mailutils/mailbox/maildir/url.c 2003-10-09 20:28:40.000000000 +0200
@@ -0,0 +1,78 @@
+/* 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 */
+
+/* Copied from mailbox/mh/url.c */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef ENABLE_MAILDIR
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <url0.h>
+#include <registrar0.h>
+
+static void
+url_maildir_destroy (url_t url ARG_UNUSED)
+{
+}
+
+/*
+ MAILDIR url
+ maildir:path
+*/
+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->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;
+}
+
+#endif
- [bug-mailutils] Maildir append,
Jeff Williams <=