bug-mailutils
[Top][All Lists]
Advanced

[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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]