procmail
[Top] [All Lists]

Re: New procmail Maildir patches...

1997-09-10 13:58:15
Hi,

Just in case anyone else runs into this problem:

On Solaris 2.5/2.5.1 (but NOT 2.6), snprintf is only available as
__snprintf.  To get this patch to work happily, you need to do something like:

perl -pe 's/snprintf/__snprintf/g;' <patchfile >patchfile.solaris25

Rumor has it that snprintf is named correctly in Solaris 2.6, and that
Solaris <=2.4 doesn't have it at all.

At 02:17 PM 9/6/97 +0000, Edward S. Marshall wrote:
Well, as I promised last night on the QMail list, here's a from-scratch
patch for handling Maildir mailboxes in procmail. It was inspired by
Matthew Zahorik's patch (http://www.qmail.org/procmail), but does a few
things that his patch failed to address:

a) this version works (theoretically) with any maildir, regardless of
  naming, by checking for an appropriate directory tree within it.

b) appropriate steps are taken to first write the file to $MAILDIR/tmp,
  and then move it with a link/unlink() to $MAILDIR/new, preventing
  potential problems.

c) following the maildir(5) manpage suggestions, this patch gives a
  filename of <time>.<pid>.<hostname> instead of <time>.<pid>.procmail.
  This is important for NFS situations where you could potentially have
  two machines delivering mail at the same time.

I've tried to ensure that MH support still works, although since I don't
have MH, I can't verify if it does; if some kind soul would test whether
I've completely broken MH support, I'd appreciate it. Also, this was only
tested on Linux, and it compiles cleanly under Solaris 2.5.1 (both gcc and
Sun's cc). For solaris, make sure you add -Dsnprintf=__snprintf to CFLAGS,
or you'll get some undefined symbols warnings.

There's still a few issues with this patch:

a) Procmail still locks everything in sight. This is a performance hit,
  but it won't hurt anything, and the performance hit has always been
  there anyway. Low priority.

b) Right now, procmail is excessively aggressive about creating a Maildir
  if the file in question doesn't exist. In other words, if the
  particular mailbox/maildir doesn't exist, a maildir is created, no
  questions asked. This should be configurable in some manner, but
  shouldn't the world really be using Maildir anyway? Medium priority.

Using this is extremely easy; just reference the maildir as you would an
mbox...by filename. Procmail takes responsibility for checking if the
mailbox is in maildir, mh, or mbox format. Keep in mind b) above; if you
reference a filename that doesn't exist, expect procmail to create a
maildir by default. If you really want it to be in mbox format, touch the
file. If you're into MH mailboxes, create the directory (and whatever
additional magic MH mailboxes require ;-).

One nice thing about this patch and the patches to Pine, for instance, is
that it hides the implementation details of how the messages are stored
pretty much completely from the end user. They don't need to worry about
how the system is storing their messages; they can get to the business of
reading their mail.

Patch is included below. No warrenty on this; if it breaks, you get to
keep both pieces. Don't bug Stephen R. van den Berg about this patch
(unless you're bugging him to incorporate it into the main procmail
distribution ;-). Mail me if you have any problems or suggestions about
it.

--
 ____ ______ _____
_/ __ \  ___//     \  Edward S. Marshall <emarshal(_at_)logic(_dot_)net>
\  ___/___ \|  | |  \ http://www.logic.net/~emarshal/
\____\_____>__|_|__/ Information Systems Manager, Logical Solutions

[  Are you a spammer looking for a great opportunity to be blacklisted?
Then  ]
[ have your automatic bots email spam(_at_)logic(_dot_)net and secure a spot 
on my
list! ]


*** procmail-3.11pre7/src/mailfold.c.old       Sat Sep  6 13:04:45 1997
--- procmail-3.11pre7/src/mailfold.c   Sat Sep  6 13:47:19 1997
***************
*** 53,60 ****
   return ffrom?(doesc=1,(ffrom-fromw)+1L):len;        /* +1 to write out the
'\n' */
 }
 
 long dump(s,source,len)const int s;const char*source;long len;
! { int i;long part;
   lasttell=i= -1;SETerrno(EBADF);
   if(s>=0)
    { if(tofile&&(lseek(s,(off_t)0,SEEK_END),fdlock(s)))
--- 53,106 ----
   return ffrom?(doesc=1,(ffrom-fromw)+1L):len;        /* +1 to write out the
'\n' */
 }
 
+ static int ismaildir(chp)char*const chp;
+ { int fish;
+   struct stat blue;
+   char *womble;
+   womble=(char *)malloc(strlen(chp)+4);
+   fish=lstat(chp,&blue);
+   if(fish==-1)
+    { if(errno==ENOENT)
+       { /* We'll create a Maildir for them. */
+      if(mkdir(chp,0700)==0)
+       { snprintf(womble,1024,"%s/new",chp);
+         if(mkdir(womble,0700)==0)
+          { snprintf(womble,1024,"%s/cur",chp);
+            if(mkdir(womble,0700)==0)
+             { snprintf(womble,1024,"%s/tmp",chp);
+               if(mkdir(womble,0700)==0)
+                { free(womble);
+                  return 1;
+                }
+             }
+          }
+       }
+      free(womble);
+      return 0;
+       }
+      free(womble);
+      return 0;
+    }
+   if(S_ISDIR(blue.st_mode))
+    { snprintf(womble,1024,"%s/new",chp);
+      if((lstat(womble,&blue)==0)&&(S_ISDIR(blue.st_mode)))
+       { snprintf(womble,1024,"%s/cur",chp);
+      if((lstat(womble,&blue)==0)&&(S_ISDIR(blue.st_mode)))
+       { snprintf( womble,1024,"%s/tmp",chp);
+         if((lstat(womble,&blue)==0)&&(S_ISDIR(blue.st_mode)))
+          { free(womble);
+            return 1; /* Woohoo. */
+          }
+       }
+       }
+    }
+   /* Something is missing or screwed up. */
+   free(womble);
+   return 0;
+ }
+ 
 long dump(s,source,len)const int s;const char*source;long len;
! { int i;long part;char blue[1024];char *blah,*foo,*hmm;
   lasttell=i= -1;SETerrno(EBADF);
   if(s>=0)
    { if(tofile&&(lseek(s,(off_t)0,SEEK_END),fdlock(s)))
***************
*** 97,102 ****
--- 143,165 ----
      i=rclose(s);
    }                    /* return an error even if nothing was to be sent */
   tofile=0;
+   blah=strdup(buf);                               /* do the Maildir thing */
+   foo=strrchr(blah,*MCDIRSEP_);                              /* yank off 
filename */
+   if(foo&&(*(foo+1))!='\0')
+    { *foo='\0';
+      foo=strrchr(blah,*MCDIRSEP_);                        /* yank off tmp */
+      if(foo)
+       {
+      *foo='\0';
+      if(ismaildir(blah))
+       { strncpy(blue,buf,1024);
+         strncpy(blue+(foo-blah),"/new",4);
+         if(link(buf,blue)==0)
+           unlink(buf); /* Be safe. */
+       }
+       }
+    }
+   free(blah);
   return i&&!len?-1:len;
 }
 
***************
*** 162,167 ****
--- 225,231 ----
                                     /* 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;
+   int maildir;char fish[1024];char womble[1024];
   asgnlastf=1;
   if(*boxname=='|'&&(!linkfolder||linkfolder==Tmnate))
    { setlastfolder(boxname);
***************
*** 171,177 ****
--- 235,251 ----
   if(boxname!=buf)
      strcpy(buf,boxname);             /* boxname can be found back in buf */
   if(*(chp=buf))                               /* not null length target? */
+     maildir=ismaildir(chp);
+   if(*chp)
      chp=strchr(buf,'\0')-1;              /* point to just before the end */
+   if(maildir)
+    { gethostname(womble,1024);
+      snprintf(fish,1024,"%s/tmp/%d.%d.%s",buf,time(NULL),getpid(),womble);
+      fflush(NULL);
+      strcpy(buf,fish);
+      strcpy(buf2,fish);
+      return opena(buf);
+    }
   mhdir=ismhdir(chp);                                      /* is it an MH 
folder? */
   if(!stat(boxname,&stbuf))                                  /* it exists */
    { if(numask&&!(stbuf.st_mode&UPDATE_MASK))




-- 
Ivan Kohler
VoiceNet Staff
ivan(_at_)voicenet(_dot_)com
"I ain't often right but I've never been wrong
 It seldom turns out the way it does in the song
 Once in a while you get shown the light
 in the strangest of places if you look at it right" -JG/RH

<Prev in Thread] Current Thread [Next in Thread>