Subject: tenex format mailfolders

From: [email-masked] (Zack Weinberg)
Date: 15 Jul 1997 19:52:14 GMT

Is there a simple way to get Pine to use tenex format mailfolders by
default? I've been through the documentation and the only thing I can find
is a reference to a `mail.txt' file in $HOME, which doesn't sound right. 
Ideally I'd like Pine to extract mail in Berkeley format from
/var/spool/mail/<user> and splat it in tenex format into $HOME/mail/INBOX,
and create new folders in tenex format.

Also, is there a berkeley->tenex conversion script out there, before I go
and reinvent the wheel?

[I'm running into memory problems with huge -- >10Mb, 600+ msgs -- Berkeley
mailfolders; the machine thrashes for several minutes when such a folder is
opened.  It seems Pine triggers pathological behavior in malloc() such that
a big Berkeley mailfolder wants memory to the tune of O(folder size*10), and
the machine doesn't have 100Mb of real RAM.  There're some messages in the
pine-users archive implying that tenex format does better in this case,
hence the question.]

zw... dreading the day when three people open 10M saved-messages folders
simultaneously and Solaris suicides for lack of swap...

---

From: "Robert de Bath" <[email-masked]>
Date: Sun, 20 Jul 1997 12:29:00 +0100 (BST)

> and create new folders in tenex format.
Pine's support for it proprietary format seems seems a bit spotty, As
far as I can tell you can't say that new folders are to be in tenex format.

The ref to mail.txt is to do with having pine automatically copy INBOX
to that file when it spots mail in the real INBOX. Pine then treats
mail.txt as the INBOX; of course this is useless if you're using procmail.

> Also, is there a berkeley->tenex conversion script out there, before I go
There's a program called 'mbxcvt' in the imap daemon gzip which will
convert a mailbox between pine's various formats. Because it uses the
same interface as pine it is horribly slow but it does get everything.

I've also attached a quick hack C program that converts a mbox folder to
tenex, it loses the 'Status:' and 'X-Status:' info; but only 'cause I
didn't need them: If you want to add them it shouldn't be difficult.
This is just a little slower than 'cp'.

I use this to make procmail create tenex format inboxes with lines like:
| tenex -1 >> linux-kernel

> pine-users archive implying that tenex format does better in this case,
I use mbox format upto about 800 messages then it gets rather slow; Pine's
implementation of it's tenex format is better and runs out of steam over
about 2-3000 messages.

-- 
Rob.                           (Robert de Bath <http://www.cix.co.uk/~mayday>)

#include <stdio.h>
#include <time.h>
#include <malloc.h>
#include <string.h>
#include <sys/stat.h>

FILE * ifd = stdin;
FILE * ofd = stdout;

char zonestr[8];
time_t now;
struct tm * tnow;

int onemessage = 0;

char * strword(char *ptr, char *buf, int blen);

main(argc, argv)
int argc;
char ** argv;
{
   int ar, done=0;

   time(&now); tnow = localtime(&now);
   {
      int tz;
      tz = timezone/60;
      if(tnow->tm_isdst == 1) tz += 60;
      if( tz <= 0 ) tz = -tz;
      sprintf(zonestr, "%s%02d%02d", timezone>0?"-":"+", tz/60, tz%60);
   }

   for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-' )
   switch( argv[ar][1] )
   {
   case '1': onemessage=1; break;
   case 'm': onemessage=0; break;
   }
   else
   {
      ifd = fopen(argv[ar], "r");
      if( ifd == 0 )
         fprintf(stderr, "Cannot open %s.\n", argv[ar]);
      else
         do_file();
      done=1;
   }
   if( !done ) do_file();
   exit(0);
}

do_file()
{
   char * mem = 0;
   int memsize = 0;
   int filesize = 0;
   int cc;
   struct stat st;

   if( fstat(fileno(ifd), &st) >= 0 )
      if( (mem=malloc(memsize=st.st_size)) == 0 )
         memsize=0;

   for(;;)
   {
      if( filesize <= memsize )
      {
         char * nptr;
	 nptr = realloc(mem, memsize+=4096);
	 if( nptr == 0 ) exit(99);
	 mem = nptr;
      }

      cc = fread(mem+filesize, 1, memsize-filesize, ifd);
      if( cc <= 0 ) break;

      filesize += cc;
   }
   if( cc < 0 ) exit(99);
   if( ifd != stdin ) fclose(ifd);

   if( memcmp(mem, "From ", 5) == 0 )
      write_mbox(mem, filesize);
   else if( mem[2] == '-' && mem[6] == '-' && mem[11] == ' ' && mem[27] == ',')
      fwrite(mem, 1, filesize, ofd);
   else
   {
      printf("%2d-%3.3s-%4d %02d:%02d:%02d %5s,%d;000000000000\n",
	    tnow->tm_mday,
	    "JanFebMarAprMayJunJulAugSepOctNovDec"+tnow->tm_mon*3,
	    tnow->tm_year+1900,
	    tnow->tm_hour,
	    tnow->tm_min,
	    tnow->tm_sec,
	    zonestr,
	    filesize
            );
      fwrite(mem, 1, filesize, ofd);
   }
   if( ofd != stdout ) fclose(ofd);

   free(mem);
}

write_mbox(char * mem, int length)
{
   int fromstart=0, fromoff=0;
   int som;
   int delch = 0;

   char *p, buf1[20], buf2[20], buf3[20], buf4[20];

   time_t now;
   struct tm * tnow, tmset;
   time(&now); tnow = localtime(&now);
   
   for(;;)
   {
      fromstart = fromoff;
      while(fromoff < length && mem[fromoff] != '\n') fromoff++;
      if( fromoff >= length ) break;
      fromoff++;
      som = fromoff;
      delch = 0;
      for(;;)
      {
         while(fromoff < length && mem[fromoff] != '\n') fromoff++;
         if( fromoff >= length ) break;
	 fromoff++;
	 if( !onemessage && memcmp(mem+fromoff, "From ", 5) == 0 )
	    break;
	 if( memcmp(mem+fromoff, ">From ", 6) == 0 )
	    delch++;
      }

#if 0
      /* This sometimes (stupidly) does a strlen! */
      sscanf(mem+fromstart, "%*s %*s %*s %s %s %s %s", buf2, buf1, buf4, buf3);
#endif
      p = mem+fromstart;
      p = strword(p, 0, 0); p = strword(p, 0, 0); p = strword(p, 0, 0);
      p = strword(p, buf2, sizeof(buf2));
      p = strword(p, buf1, sizeof(buf1));
      p = strword(p, buf4, sizeof(buf4));
      p = strword(p, buf3, sizeof(buf3));

      if( atoi(buf3) > 1990 && atoi(buf1) >= 1 && atoi(buf1) <= 31 && strlen(buf4) == 8 )
      {
         printf("%2s-%3.3s-%4s %8s %5s,%d;000000000000\n",
               buf1, buf2, buf3, buf4, zonestr,
	       fromoff-som-delch
               );
      }
      else
      {
         printf("%2d-%3.3s-%4d %02d:%02d:%02d %1s%04d,%d;000000000000\n",
	       tnow->tm_mday,
	       "JanFebMarAprMayJunJulAugSepOctNovDec"+tnow->tm_mon*3,
	       tnow->tm_year+1900,
	       tnow->tm_hour,
	       tnow->tm_min,
	       tnow->tm_sec,
	       "+", 0,
	       fromoff-som-delch
               );
      }

      if( delch == 0 )
         fwrite(mem+som, 1, fromoff-som, ofd);
      else for(;som<fromoff;)
      {
         if( delch >0 && memcmp(mem+som, ">From ", 6) == 0 )
	    som++,delch--;

         do putchar(mem[som]); while(mem[som++] != '\n' && som<length);
      }
   }
}

char * strword(ptr, buf, blen)
char * ptr, *buf;
int blen;
{
   if( ptr == 0 ) return ptr;
   while( *ptr == ' ' || *ptr == '\t' ) ptr++;

   while(blen>1 && (*ptr > ' ' || *ptr < 0 ) )
   {
      *buf++ = *ptr++;
      blen--;
   }

   if( blen > 0 ) *buf++ = 0;
   while(*ptr > ' ' || *ptr < 0 ) ptr++;

   return ptr;
}