procmail
[Top] [All Lists]

Revised maildir patch for procmail

1998-12-22 19:57:36
Greetings.

I have just finished revising my patch for procmail that allows it to
deliver to maildirs.  I have added code to strip leading "From " lines
from messages to be delivered into maildirs, as well as a note in the
procmailrc man page regarding maildir delivery.  Thanks also to Tor
Perkins <3c9x5(_at_)altabates(_dot_)com> for a patch to mailstat to allow it to
handle maildir deliveries.
-- 
Bruce Guenter, QCC Communications Corp.  EMail: 
bruce(_dot_)guenter(_at_)qcc(_dot_)sk(_dot_)ca
Phone: (306)249-0220               WWW: http://www.qcc.sk.ca/~bguenter/

diff -ur procmail-3.11pre7/examples/mailstat procmail-maildir/examples/mailstat
--- procmail-3.11pre7/examples/mailstat Mon Mar 20 08:51:08 1995
+++ procmail-maildir/examples/mailstat  Tue Dec 22 15:52:41 1998
@@ -186,6 +186,7 @@
   $sed -e '/^From /d' -e '/^ [Ss][uU][bB][jJ][eE][cC][tT]:/d' \
    -e '/^  Folder/s/           */      /' \
    -e '/^  Folder/s/\/msg.[-0-9A-Za-z_][-0-9A-Za-z_]*  /\/     /' \
+   -e '/^  Folder/s/\/\/tmp\/[-0-9A-Za-z_.][-0-9A-Za-z_.]*     /\/     /' \
    -e '/^  Folder/s/\/[0-9][0-9]*      /\/.    /' \
    -e 's/^  Folder: \(.*\)/\1/' -e t -e 's/    /\\t/g' \
    -e 's/^/ ## /' $OLDLOGFILE | $sort | $awk -f $TMPF -
@@ -193,6 +194,7 @@
   $sed -e '/^From /d' -e '/^ [Ss][uU][bB][jJ][eE][cC][tT]:/d' \
    -e '/^  Folder/s/           */      /' \
    -e '/^  Folder/s/\/msg.[-0-9A-Za-z_][-0-9A-Za-z_]*  /\/     /' \
+   -e '/^  Folder/s/\/\/tmp\/[-0-9A-Za-z_.][-0-9A-Za-z_.]*     /\/     /' \
    -e '/^  Folder/s/\/[0-9][0-9]*      /\/.    /' \
    -e 's/^  Folder: \(.*\)/\1/' -e t \
    -e 's/.*/ ## diagnostic messages ##/' $OLDLOGFILE | $sort | $awk -f $TMPF -
diff -ur procmail-3.11pre7/man/procmailrc.man 
procmail-maildir/man/procmailrc.man
--- procmail-3.11pre7/man/procmailrc.man        Fri Apr 11 04:29:00 1997
+++ procmail-maildir/man/procmailrc.man Tue Dec 22 15:52:41 1998
@@ -255,7 +255,11 @@
 If it is a (possibly yet nonexistent) filename, the mail will be appended to
 it.
 .PP
-If it is a directory, the mail will be delivered to a newly created, guaranteed
+If it is a directory and the directory does not exist, a maildir will be
+created and the mail delivered into it.
+if the directory exists and contains three subdirectories named "cur",
+"new", "tmp", the mail will be delivered to the named maildir.
+Otherwise, the mail will be delivered to a newly created, guaranteed
 to be unique file named $MSGPREFIX* in the specified directory.  If the
 directory name ends in "@MCDIRSEP@@chCURDIR@", then this directory is presumed
 to be an MH folder; i.e. procmail will use the next number it finds available.
@@ -400,7 +404,7 @@
 .TP
 .B MSGPREFIX
 Filename prefix that is used when delivering to a directory (not used when
-delivering to an MH directory).
+delivering to a maildir or an MH directory).
 .TP
 .B HOST
 If this is not the
diff -ur procmail-3.11pre7/src/mailfold.c procmail-maildir/src/mailfold.c
--- procmail-3.11pre7/src/mailfold.c    Wed Apr  2 19:58:45 1997
+++ procmail-maildir/src/mailfold.c     Tue Dec 22 15:53:32 1998
@@ -53,8 +53,21 @@
   return ffrom?(doesc=1,(ffrom-fromw)+1L):len;  /* +1 to write out the '\n' */
 }
 
+static int skip_from;
+
 long dump(s,source,len)const int s;const char*source;long len;
 { int i;long part;
+  if(skip_from)
+   { while(eqFrom_(source))
+      { char*end;
+        end=strchr(source, '\n');
+        if(end)
+         { ++end;
+          len-=end-source;
+          source=end;
+         }
+      }
+   }
   lasttell=i= -1;SETerrno(EBADF);
   if(s>=0)
    { if(tofile&&(lseek(s,(off_t)0,SEEK_END),fdlock(s)))
@@ -152,6 +165,87 @@
   return -1;
 }
 
+static int ckmaildir(dir,statbuf)const char*dir;struct stat*statbuf;
+{ int tmplen;
+  char*tmpstr;
+  tmplen=strlen(dir)+5;
+  tmpstr=(char*)malloc(tmplen);
+  if(S_ISDIR(statbuf->st_mode))
+   { snprintf(tmpstr,tmplen,"%s/new",dir);
+     if((lstat(tmpstr,statbuf)==0)&&(S_ISDIR(statbuf->st_mode)))
+      { snprintf(tmpstr,tmplen,"%s/cur",dir);
+       if((lstat(tmpstr,statbuf)==0)&&(S_ISDIR(statbuf->st_mode)))
+        { snprintf( tmpstr,tmplen,"%s/tmp",dir);
+          if((lstat(tmpstr,statbuf)==0)&&(S_ISDIR(statbuf->st_mode)))
+           { free(tmpstr);
+             return 1; /* Woohoo. */
+           }
+        }
+      }
+   }
+  /* Something is missing or screwed up. */
+  free(tmpstr);
+  return 0;
+}
+
+static int mkmaildir(dir)const char* dir;
+{ char *tmpstr;
+  int tmplen;
+  tmplen=strlen(dir)+5;
+  tmpstr=(char *)malloc(tmplen);
+  if(mkdir(dir,0700)==0)
+   { snprintf(tmpstr,tmplen,"%s/new",dir);
+     if(mkdir(tmpstr,0700)==0)
+      { snprintf(tmpstr,tmplen,"%s/cur",dir);
+        if(mkdir(tmpstr,0700)==0)
+         { snprintf(tmpstr,tmplen,"%s/tmp",dir);
+        if(mkdir(tmpstr,0700)==0)
+         { free(tmpstr);
+           return 1;
+         }
+         }
+      }
+   }
+  free(tmpstr);
+  return 0;
+}
+
+static int ismaildir(chp,buf)char*const chp;char*const buf;
+{ int err;
+  struct stat statbuf;
+  if(!(chp>buf&&*chp==*MCDIRSEP_))
+    return 0;
+  err=lstat(buf,&statbuf);
+  if(err==-1)
+    return (errno==ENOENT)?mkmaildir(buf):0;
+  else
+    return ckmaildir(buf,&statbuf);
+}
+
+static int deliver_maildir(source,len)
+  const char*source;const long len;
+{ char path_tmp[1024];char hostname[1024];char path_new[1024];int iteration;
+  pid_t pid;int fd;
+  skip_from=1;
+  gethostname(hostname,1024);
+  pid=getpid();
+  for(iteration=0; iteration<100; iteration++,sleep(2))
+   {struct stat statbuf;time_t currtime;
+    currtime=time(NULL);
+    snprintf(path_tmp,1024,"%s/tmp/%d.%d.%s",buf,currtime,pid,hostname);
+    snprintf(path_new,1024,"%s/new/%d.%d.%s",buf,currtime,pid,hostname);
+    if(lstat(path_tmp, &statbuf)==0 || errno!=ENOENT) continue;
+    fflush(NULL);
+    fd=opena(path_tmp);
+    if(fd>0) break;
+   }
+  strcpy(buf,path_tmp);
+  strcpy(buf2,path_tmp);
+  if(dump(fd,source,len))
+    return 1;
+  return link(path_tmp,path_new)||unlink(path_tmp);
+}
+
 static int ismhdir(chp)char*const chp;
 { if(chp-1>=buf&&chp[-1]==*MCDIRSEP_&&*chp==chCURDIR)
    { chp[-1]='\0';
@@ -160,19 +254,26 @@
   return 0;
 }
                                       /* open file or new file in directory */
-static int deliver(boxname,linkfolder)char*boxname,*linkfolder;
-{ struct stat stbuf;char*chp;int mhdir;mode_t numask;
+static int deliver(boxname,linkfolder,source,len)char*boxname,*linkfolder;
+  const char*source;const long len;
+{ struct stat stbuf;char*chp;int mhdir;mode_t numask;int maildir;
   asgnlastf=1;
+  skip_from=0;
   if(*boxname=='|'&&(!linkfolder||linkfolder==Tmnate))
    { setlastfolder(boxname);
-     return rdup(savstdout);
+     return dump(rdup(savstdout),source,len);
    }
   numask=UPDATE_MASK&~cumask;tofile=to_FILE;
   if(boxname!=buf)
      strcpy(buf,boxname);               /* boxname can be found back in buf */
   if(*(chp=buf))                                 /* not null length target? */
      chp=strchr(buf,'\0')-1;                /* point to just before the end */
+  maildir=ismaildir(chp,buf);
   mhdir=ismhdir(chp);                                /* is it an MH folder? */
+  if(maildir)
+    return deliver_maildir(source,len);
+  else if(!mhdir && *chp=='/')
+    *chp='\0';
   if(!stat(boxname,&stbuf))                                    /* it exists */
    { if(numask&&!(stbuf.st_mode&UPDATE_MASK))
        chmod(boxname,stbuf.st_mode|UPDATE_MASK);
@@ -184,7 +285,7 @@
    { if(linkfolder)      /* any leftovers?  Now is the time to display them */
        concatenate(linkfolder),skipped(linkfolder);
      tofile=strcmp(devnull,buf)?to_FOLDER:(rawnonl=1,0);
-     return opena(boxname);
+     return dump(opena(boxname),source,len);
    }
   if(linkfolder)                   /* any additional directories specified? */
    { size_t blen;
@@ -218,13 +319,13 @@
         }
      if(linkfolder)                                       /* free our cache */
        free(linkfolder);
-     return fd;                              /* return the file descriptor we 
saved */
+     return dump(fd,source,len);
    }
 }
 
 int writefolder(boxname,linkfolder,source,len,ignwerr)char*boxname,*linkfolder;
  const char*source;const long len;const int ignwerr;
-{ if(dump(deliver(boxname,linkfolder),source,len)&&!ignwerr)
+{ if(deliver(boxname,linkfolder,source,len)&&!ignwerr)
    { switch(errno)
       { case ENOSPC:nlog("No space left to finish writing"),logqnl(buf);
           break;

<Prev in Thread] Current Thread [Next in Thread>
  • Revised maildir patch for procmail, Bruce Guenter <=