home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Mail / appnmail-1.8-Solaris / mailapp-utilities / compactmail.m < prev    next >
Encoding:
Text File  |  1997-04-19  |  6.9 KB  |  251 lines

  1. /* -*-C-*-
  2. *******************************************************************************
  3. *
  4. * File:         compactmail.m
  5. * RCS:          /usr/local/sources/CVS/mailapp-utilities/compactmail.m,v 1.4 1997/04/19 17:37:19 tom Exp
  6. * Description:  Compact Mail.app mailboxes (expunge deleted messages)
  7. * Author:       Carl Edman
  8. * Created:      Fri Mar 12 18:21:23 1993
  9. * Modified:     Sat Nov 30 23:28:56 1996 Tom Hageman <tom@basil.icce.rug.nl>
  10. * Language:     Objective C
  11. * Package:      mailapp-utilities
  12. * Status:       First release.
  13. *
  14. * (C) Copyright 1993, but otherwise this file is perfect freeware.
  15. *
  16. *******************************************************************************
  17. */
  18.  
  19. #import <libc.h>
  20. #import <errno.h>
  21. //#import <stdlib.h>
  22. //#import <stdio.h>
  23. //#import <string.h>
  24. //#import <time.h>
  25. #import <regex.h>
  26. //#import <sys/file.h>
  27. //#import <sys/param.h>
  28. //#import <sys/types.h>
  29. //#import <sys/stat.h>
  30. #import <defaults/defaults.h>
  31. #import "mailutil.h"
  32. #import "mailtoc.h"
  33. #import "optutil.h"
  34.  
  35. #define USAGE "\
  36. Usage: %s [-nruv] [-d days] [-f from] [-s subject] [-V|-H] mbox...\n"
  37.  
  38. #define HELP "\
  39.  -n           skip mailbox if locked\n\
  40.  -r           expunge read messages too (default deleted messages only)\n\
  41.  -u           expunge all messages (even unread)\n\
  42.  -v           talkative mode\n\
  43.  -d days      restrict to messages of at least `days' days old.\n\
  44.  -f from      restrict to messages whose From: header matches (regexp)\n\
  45.  -s subject   restrict to messages whose Subject: header matches (regexp)\n\
  46.  -V           show version\n\
  47.  -H           this help\n\
  48. "
  49.  
  50. char line[LINELEN];
  51.  
  52. int main(int ac,char *av[])
  53. {
  54.    char *buf=0;
  55.    int c,pos;
  56.    int nowaitflg=0,verboseflg=0,deletereadflg=0,deleteunreadflg=0;
  57.    int days=-1;
  58.    struct regex *subjectregexp=0,*fromregexp=0;
  59.    time_t mboxtime;
  60.    int mboxdis,tocdis,msgdis,changed;
  61.    int mboxfd=-1;
  62.    FILE *tocf=NULL;
  63.    struct table_of_contents_header *toch=0;
  64.    struct message_index *mi=0;
  65.    int status=EXIT_SUCCESS;
  66.  
  67.    set_progname(av[0]);
  68.  
  69.    while((c=getopt(ac,av,"d:s:f:nruvVH"))!=EOF) switch(c)
  70.    {
  71.     case 'd':
  72.       if (days!=-1 || (days=atoi(optarg))<=0)
  73.          status=EXIT_USAGE;
  74.       break;
  75.     case 's':
  76.       if (subjectregexp || !(subjectregexp=re_compile(optarg,0)))
  77.          status=EXIT_USAGE;
  78.       break;
  79.     case 'f':
  80.       if (fromregexp || !(fromregexp=re_compile(optarg,0)))
  81.          status=EXIT_USAGE;
  82.       break;
  83.     case 'n':
  84.       nowaitflg++;
  85.       break;
  86.     case 'r':
  87.       deletereadflg++;
  88.       break;
  89.     case 'u':
  90.       deleteunreadflg++;
  91.       break;
  92.     case 'v':
  93.       verboseflg++;
  94.       break;
  95.     case 'V':
  96.       status=EXIT_VERSION;
  97.       break;
  98.     case 'H':
  99.       status=EXIT_HELP;
  100.       break;
  101.     case '?':
  102.     default:
  103.       status=EXIT_USAGE;
  104.    }
  105.    if (status==EXIT_SUCCESS && optind>=ac) status=EXIT_USAGE;
  106.    handle_usage_help_version(status, USAGE, HELP);
  107.  
  108.    for(;optind<ac;optind++)
  109.    {
  110.       if (verboseflg) fprintf(stderr,"Entering %s...\n",av[optind]);
  111.       if (cd_mbox(av[optind],1)) goto next;
  112.       if (lock_mbox(nowaitflg)) goto next;
  113.  
  114.       mboxtime=mtime("mbox");
  115.  
  116.       if (((mboxfd=open("mbox",O_RDWR))==-1) ||
  117.           ((tocf=fopen("table_of_contents","r+b"))==NULL))
  118.       {
  119.          fprintf(stderr,"%s: opening %s: %s\n",progname(),av[optind],strerror(errno));
  120.          status=EXIT_FAILURE;
  121.          goto unlock;
  122.       }
  123.  
  124.       toch=get_table_of_contents_header(tocf,0);
  125.       if (!toch)
  126.       {
  127.          fprintf(stderr,"%s: %s: invalid old table_of_contents\n",progname(),av[optind]);
  128.          status=EXIT_FAILURE;
  129.          goto unlock;
  130.       }
  131.  
  132.       if (toch->mbox_time!=mboxtime)
  133.       {
  134.          fprintf(stderr,"%s: %s: table of contents out of sync\n",progname(),av[optind]);
  135.          status=EXIT_FAILURE;
  136.          goto unlock;
  137.       }
  138.  
  139.       for(changed=FALSE,msgdis=mboxdis=tocdis=c=0;c<toch->num_msgs;c++)
  140.       {
  141.          if ((mi=get_message_index(tocf))==0)
  142.      {
  143.             fprintf(stderr,"%s: %s: reading old mbox entries: %s\n",progname(),av[optind],(errno?strerror(errno):"invalid"));
  144.             status=EXIT_FAILURE;
  145.             goto unlock;
  146.      }
  147.          if ((mi->status=='d' || mi->status=='D' || deleteunreadflg ||
  148.               (mi->status!='*' && deletereadflg)) &&
  149.              (days==-1 || message_age(mi)>=days) &&
  150.              (!subjectregexp || re_match(message_subject(mi),subjectregexp)) &&
  151.              (!fromregexp || re_match(message_from(mi),fromregexp)))
  152.      {
  153.             if (verboseflg>1)
  154.         {
  155.                fprintf(stderr,"Expunging \"%s\" from %s (%d days old).\n",message_subject(mi),message_from(mi),message_age(mi));
  156.         }
  157.             if (mi->msgtype=='r')
  158.         {
  159.                char *dir=mi->data;
  160.                dir+=strlen(dir)+1;
  161.                dir+=strlen(dir)+1;
  162.                if (*dir)
  163.            {
  164.           int pid,childpid=fork();
  165.           union wait status;
  166.  
  167.           switch (childpid)
  168.           {
  169.           case -1:
  170.              break;
  171.           case 0:
  172.              execl("/bin/rm", "rm", "-rf", dir, NULL);
  173.              _exit(255);
  174.           default:
  175.              while ((pid=wait(&status))>=0 && pid!=childpid) ;
  176.           }
  177.            }
  178.         }
  179.             changed=TRUE;
  180.             msgdis++;
  181.             tocdis +=mi->record_length;
  182.             mboxdis+=mi->mes_length;
  183.      }
  184.          else
  185.      {
  186.             if (verboseflg>2)
  187.         {
  188.                fprintf(stderr,"Keeping \"%s\" from %s (%d days old).\n",message_subject(mi),message_from(mi),message_age(mi));
  189.         }
  190.             if (mboxdis!=0)
  191.         {
  192.                lseek(mboxfd,mi->mes_offset,L_SET);
  193.                buf=malloc(mi->mes_length);
  194.                read(mboxfd,buf,mi->mes_length);
  195.                mi->mes_offset -= mboxdis;
  196.                lseek(mboxfd,mi->mes_offset,L_SET);
  197.                write(mboxfd,buf,mi->mes_length);
  198.                free(buf); buf=0;
  199.         }
  200.  
  201.             if (tocdis!=0 || mboxdis!=0)
  202.         {
  203.                pos=ftell(tocf);
  204.                fseek(tocf,-mi->record_length-tocdis,SEEK_CUR);
  205.                put_message_index(tocf,mi);
  206.                fseek(tocf,pos,SEEK_SET);
  207.         }
  208.      }
  209.          free(mi); mi=0;
  210.       }
  211.       
  212.       if (tocdis!=0)
  213.       {
  214.      fflush(tocf);
  215.          pos=fseek(tocf,0,SEEK_END);
  216.          ftruncate(fileno(tocf),pos-tocdis);
  217.       }
  218.  
  219.       if (mboxdis!=0)
  220.       {
  221.          pos=lseek(mboxfd,0,L_XTND);
  222.          ftruncate(mboxfd,pos-mboxdis);
  223.       }
  224.       close(mboxfd), mboxfd=-1;
  225.       
  226.       toch->num_msgs-=msgdis;
  227.       mboxtime=mtime("mbox");
  228.       if ((toch->mbox_time!=mboxtime) || changed)
  229.       {
  230.          toch->mbox_time=mboxtime;
  231.          fseek(tocf,0,SEEK_SET);
  232.          if (put_table_of_contents_header(tocf,toch))
  233.      {
  234.             fprintf(stderr,"%s: %s: writing updated table_of_contents: %s\n",progname(),av[optind],strerror(errno));
  235.             status=EXIT_FAILURE;
  236.             goto unlock;
  237.      }
  238.       }
  239.     unlock:
  240.       if(mboxfd>=0) close(mboxfd), mboxfd=-1;
  241.       if(tocf!=NULL) fclose(tocf), tocf=NULL;
  242.       unlock_mbox();
  243.     next:;
  244.       if (toch) { free(toch); toch=0; }
  245.       if (mi) { free(mi); mi=0; }
  246.       if (buf) { free(buf); buf=0; }
  247.       uncd_mbox();
  248.    }
  249.    exit(status);
  250. }
  251.