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;