home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume26 / em / part01 / em.c < prev    next >
C/C++ Source or Header  |  1991-11-25  |  9KB  |  527 lines

  1. /*
  2. ** em: expire mail messages
  3. **
  4. **
  5. ** Options:
  6. **
  7. ** -a age
  8. **       Specify how many days old an 'expired' message is.  Default
  9. **       is 180 (six months).
  10. ** -d
  11. **       Debug.  Only generates an audit trail.  No actual removal takes
  12. **       place.  More 'd's, more debugging information.
  13. ** -o
  14. **       Do not remove mailboxes just because they're older than 'age'
  15. **       days. Instead, explicitly scan the mailbox to ensure that all
  16. **       messages have expired.  The default is for em to remove any
  17. **       mailboxes that have modification times older than 'age' days.
  18. ** -u username
  19. **       Secify that only messages from 'username' will be considered
  20. **       for expiration.  Useful for removing messages from an offensive
  21. **       user.
  22. ** -v 
  23. **       Be verbose.  This option produces the same output as the debug
  24. **       option but all actions are followed through.  That is, messages
  25. **       are expired, mailboxes are removed, etc.
  26. ** -z
  27. **       Do not remove mailboxes of zero length.
  28. **
  29. **
  30. ** Author:
  31. **
  32. ** Steve Mitchell
  33. ** California State University, Fresno
  34. ** steve_mitchell@csufresno.edu
  35. **
  36. **
  37. ** NOTICE:
  38. ** 
  39. ** THE AUTHOR OFFERS NO WARRANTY FOR THE PERFORMANCE OF THIS SOFTWARE.
  40. ** (In other words, use at your own risk)
  41. **
  42. **
  43. ** Version History:
  44. **
  45. ** 09/12/91: first version
  46. **
  47. */
  48.  
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <ctype.h>
  52. #include <sys/time.h>
  53. #include <stdio.h>
  54. #include <fcntl.h>
  55. #ifdef UTIME
  56. #ifdef sun
  57. #include <utime.h>
  58. #endif
  59. #endif
  60.  
  61. #ifndef S_ISREG
  62. #define    S_ISREG(m)    (((m)&S_IFMT) == S_IFREG)
  63. #endif
  64.  
  65. int    aged    = 160;
  66. int    sec_aged;
  67. int    debug    = 0;
  68. int    verbose = 0;
  69. int    oldflag = 1;
  70. int    zeroflag = 1;
  71. char    *fromwho = (char *)0;
  72. char    *myname;
  73. char    *whoami;
  74. time_t    currtime;
  75. #ifdef UTIME
  76. struct    utimbuf tv;
  77. #else
  78. struct    timeval    tv[2];
  79. #endif
  80. int    mbox_id;
  81.  
  82. void    usage();
  83. time_t    time();
  84. char    *getlogin();
  85. char    *strrchr();
  86.  
  87. time_t    mystrptime();
  88. void    resettimes();
  89.  
  90. struct    msg {
  91.     char    *from;
  92.     time_t    time;
  93. };
  94.  
  95. main(argc,argv)
  96.     int    argc;
  97.     char    *argv[];
  98. {
  99.     FILE    *mfp;
  100.     FILE    *ofp;
  101.     char    *mailbox;
  102.     int    c;
  103.     int    errflg = 0;
  104.     int    num_expired = 0;
  105.     extern    char    *optarg;
  106.     extern    int    optind;
  107.     struct    stat    sbuf;
  108.     char    tname[BUFSIZ];
  109.     char    *p;
  110.  
  111.     myname = argv[0];
  112.  
  113.     whoami = getlogin();
  114.  
  115.     while((c = getopt(argc,argv,"a:dou:vz")) != -1)
  116.         switch(c) {
  117.         case 'a':
  118.             aged = atoi(optarg);
  119.             break;
  120.         case 'd':
  121.             debug++;
  122.             break;
  123.         case 'o':
  124.             oldflag = 0;
  125.             break;
  126.         case 'u':
  127.             fromwho = optarg;
  128.             break;
  129.         case 'v':
  130.             verbose = 1;
  131.             break;
  132.         case 'z':
  133.             zeroflag = 0;
  134.             break;
  135.         default:
  136.             errflg++;
  137.         }
  138.  
  139.     if(errflg || optind == argc) {
  140.         usage();
  141.         return(1);
  142.     }
  143.  
  144.     sec_aged = aged * 86400;
  145.  
  146.     (void)time(&currtime);
  147.  
  148.     for(;optind < argc; optind++) {
  149.         mailbox = argv[optind];
  150.  
  151.         if(stat(mailbox,&sbuf) < 0) {
  152.             perror(mailbox);
  153.             continue;
  154.         } 
  155. #ifdef UTIME
  156.         tv.actime = sbuf.st_atime;
  157.         tv.modtime = sbuf.st_mtime;
  158. #else
  159.         tv[0].tv_sec = sbuf.st_atime;
  160.         tv[1].tv_sec = sbuf.st_mtime;
  161. #endif
  162.  
  163.         mbox_id = sbuf.st_uid;
  164.  
  165.         p = strrchr(mailbox,'.');
  166.         if(p)
  167.             if(!strcmp(p,".lock"))
  168.                 continue;
  169.  
  170.         if(locked(mailbox)) {
  171.             (void)fprintf(stderr,"%s: locked\n",mailbox);
  172.             continue;
  173.         }
  174. #ifdef    S_ISREG
  175.         if(!S_ISREG(sbuf.st_mode)) {
  176.             (void)fprintf(stderr,"%s: not a regular file\n",
  177.                     mailbox);
  178.             continue;
  179.         }
  180. #endif
  181.         if(debug >= 1 || verbose >= 1)
  182.             (void)printf("%s:\n",mailbox);
  183.         if(currtime - sbuf.st_mtime > sec_aged && oldflag) {
  184.             if(debug >= 1 || verbose >= 1)
  185.                 (void)printf(
  186.                     "\tolder than %d days - remove\n",aged);
  187.             if(!debug)
  188.                 if(unlink(mailbox) < 0)
  189.                     perror(mailbox);
  190.             continue;
  191.         }
  192.         if(sbuf.st_size == 0 && zeroflag) {
  193.             if(debug >= 1 || verbose >= 1)
  194.                 (void)printf("\tzero length - remove\n");
  195.             if(!debug)
  196.                 if(unlink(mailbox) < 0)
  197.                     perror(mailbox);
  198.             continue;
  199.         }
  200.         if(!lock(mailbox)) {
  201.             (void)fprintf(stderr,"%s: can't lock\n",mailbox);
  202.             continue;
  203.         }
  204.         if((mfp = fopen(mailbox,"r")) == NULL) {
  205.             perror(mailbox);
  206.             continue;
  207.         }
  208.  
  209.         p = strrchr(mailbox,'/');
  210.         if(p)
  211.             p++;
  212.         else
  213.             p = mailbox;
  214.         (void)sprintf(tname,"/tmp/%s.expire",p);
  215.  
  216.         if((ofp = fopen(tname,"w")) == NULL) {
  217.             perror(tname);
  218.             (void)fclose(mfp);
  219.             resettimes(mailbox);
  220.             (void)unlock(mailbox);
  221.             continue;
  222.         }
  223.  
  224.         num_expired = do_msgs(mfp,ofp);
  225.  
  226.         if(stat(tname,&sbuf) < 0) {
  227.             perror(tname);
  228.             (void)unlock(mailbox);
  229.             continue;
  230.         } 
  231.         if(sbuf.st_size == 0 && zeroflag) {
  232.             if(debug >= 1 || verbose >= 1) {
  233.                 (void)printf("\tzero length - remove\n");
  234.                 resettimes(mailbox);
  235.             } 
  236.             if(!debug)
  237.                 if(unlink(mailbox) < 0)
  238.                     perror(mailbox);
  239.             if(unlink(tname) < 0)
  240.                 perror(tname);
  241.             (void)unlock(mailbox);
  242.             continue;
  243.         }
  244.         if(debug || !num_expired) {
  245.             (void)unlink(tname);
  246.             (void)fclose(mfp);
  247.             resettimes(mailbox);
  248.             if(!unlock(mailbox)) 
  249.                 (void)fprintf(stderr,
  250.                     "%s: can't unlock\n",mailbox);
  251.             continue;
  252.         }
  253.  
  254.         if((mfp = fopen(mailbox,"w")) == NULL) {
  255.             perror(mailbox);
  256.             (void)unlock(mailbox);
  257.             continue;
  258.         }
  259.         if((ofp = fopen(tname,"r")) == NULL) {
  260.             perror(tname);
  261.             (void)fclose(mfp);
  262.             resettimes(mailbox);
  263.             (void)unlock(mailbox);
  264.             continue;
  265.         }
  266.         while((c = fgetc(ofp)) != EOF)
  267.             (void)fputc(c,mfp);
  268.         (void)fclose(ofp);
  269.         (void)fclose(mfp);
  270.  
  271.         resettimes(mailbox);
  272.  
  273.         if(!unlock(mailbox)) {
  274.             (void)fprintf(stderr,"%s: can't unlock\n",mailbox);
  275.             continue;
  276.         }
  277.             
  278.         if(unlink(tname) < 0)
  279.             perror(tname);
  280.     }
  281.     return(0);
  282. }
  283.  
  284.  
  285. void
  286. resettimes(mbox)
  287.     char    *mbox;
  288. {
  289.     if(geteuid() == 0 || getuid() == mbox_id ) {
  290. #ifdef UTIME
  291.         if(utime(mbox,&tv) < 0) {
  292.             perror("utime");
  293.         }
  294. #else
  295.         tv[0].tv_usec = (time_t)0;
  296.         tv[1].tv_usec = (time_t)0;
  297.         if(utimes(mbox,tv) < 0) {
  298.             perror("utimes");
  299.         }
  300. #endif
  301.     }
  302. }
  303.  
  304. do_msgs(mfp,ofp)
  305.     FILE    *mfp;
  306.     FILE    *ofp;
  307. {
  308.     int    writeout = 1;
  309.     int    msgnum = 0;
  310.     char    buf[BUFSIZ];
  311.     struct    msg msg;
  312.     int    num_expired = 0;
  313.  
  314.     
  315.     while(fgets(buf,BUFSIZ,mfp)) {
  316.         if(!strncmp("From ",buf,5)) {
  317.             msgnum++;
  318.             get_msg_info(buf,&msg);
  319.             if(msg.time < 0) {
  320.                 (void)fprintf(stderr,"Bad header\n");
  321.                 continue;
  322.             }
  323.             if(debug >= 3 || verbose >= 3)
  324.                 (void)printf("\t\tmessage from %s %d\n",
  325.                         msg.from, msg.time);
  326.             if(currtime - msg.time > sec_aged) {
  327.                 writeout = 0;
  328.                 num_expired++;
  329.                 if(fromwho && strcmp(fromwho,msg.from)) 
  330.                     writeout = 1;
  331.                 if((debug >= 1 || verbose >= 1) && !writeout)
  332.                          (void)printf(
  333.                          "\tmessage #%d, expired (%d days)\n",
  334.                          msgnum,(currtime-msg.time)/86400);
  335.                 if(debug >= 2 || verbose >= 2)
  336.                     (void)printf(
  337.                      "\t\tcurrtime = %d, msg.time = %d\n",
  338.                     currtime,msg.time);
  339.                 if(debug >= 2 || verbose >= 2)
  340.                          (void)printf("\t\tfrom = %s\n", msg.from);
  341.             } else {
  342.                 writeout = 1;
  343.             }
  344.         }
  345.         if(writeout)
  346.             (void)fprintf(ofp,"%s",buf);
  347.     }
  348.     (void)fclose(mfp);
  349.     (void)fclose(ofp);
  350.     return(num_expired);
  351. }
  352.  
  353.  
  354. get_msg_info(fromp,s)
  355.     char    *fromp;
  356.     struct msg *s;
  357. {
  358.     static    char    name[1024];
  359.     char    *p, *wp;
  360. #ifdef HAVE_STRPTIME
  361.     struct    tm tm;
  362. #endif
  363.  
  364.     for(p=fromp;*p!=' ';p++)
  365.         ;
  366.     for(;*p==' ';p++)
  367.         ;
  368.     for(wp=name;*p!=' ';p++,wp++)
  369.         *wp = *p;
  370.     *wp = 0;
  371.     s->from = name;
  372.  
  373.  
  374.     for(;*p==' ';p++)
  375.         ;
  376.  
  377. #ifdef HAVE_STRPTIME
  378.     strptime(p,"%a %h %e %H:%M:%S %Y",&tm);
  379.     s->time = timelocal(&tm);
  380. #else
  381.     s->time = mystrptime(p);
  382. #endif /* HAVE_STRPTIME */
  383.     if(debug >= 3) {
  384.         (void)printf("\t\ttimelocal = %ld\n",s->time);
  385.     }
  386. }
  387.  
  388. #define    equal(S1,S2)    (!strcmp(S1,S2))
  389.  
  390. #define MINUTE    (60L)
  391. #define HOUR    (MINUTE * 60L)
  392. #define DAY    (HOUR    * 24L)
  393. #define RYEAR    (DAY    * 365L)
  394. #define LYEAR    (DAY    * 366L)
  395.  
  396. struct mons {
  397.     int    days;
  398.     char    *month;
  399. } months[] = {
  400.     31,    "Jan",
  401.     28,    "Feb",
  402.     31,    "Mar",
  403.     30,    "Apr",
  404.     31,    "May",
  405.     30,    "Jun",
  406.     31,    "Jul",
  407.     31,    "Aug",
  408.     30,    "Sep",
  409.     31,    "Oct",
  410.     30,    "Nov",
  411.     31,    "Dec",
  412.      0,    0
  413. };
  414.  
  415. time_t
  416. mystrptime(s)
  417.     char    *s;
  418. {
  419.     struct    mons    *mp;
  420.     char    mymon[4];
  421.     char    myyear[5];
  422.     char    *p;
  423.     int    dom, tot=0, year, mfound=0;
  424.     int    hr, min;
  425.     int    dindex = 70;
  426.     long    sectot=0;
  427.  
  428.     if(sscanf(s,"%*s %s %d %d:%d",
  429.                 mymon,&dom,&hr,&min) < 3) {
  430.         (void)fprintf(stderr,"Bad date format\n");
  431.         return(-1);
  432.     }
  433.  
  434.     p = s + strlen(s);
  435.     for(;!isdigit(*p);p--)
  436.         ;
  437.     p-=3;
  438.     (void)strncpy(myyear,p,4);
  439.     myyear[4] = 0;
  440.  
  441.     year = atoi(myyear);
  442.     
  443.     /* handle leap years */
  444.     if((year % 4) == 0)
  445.         months[1].days++;
  446.  
  447.     /* add to tot until we find the month we're looking for */
  448.     for(mp=months;mp->days;mp++) {
  449.         if(equal(mp->month,mymon)) {
  450.             mfound++;
  451.             break;
  452.         }
  453.         tot += mp->days;
  454.     }
  455.  
  456.     if(!mfound) {
  457.         (void)fprintf(stderr,"Bad date format\n");
  458.         return(-1);
  459.     }
  460.  
  461.     sectot = ((tot+dom-1)*DAY) + (hr*HOUR) + (min*MINUTE);
  462.  
  463.     for(dindex=70;dindex<(year-1900);dindex++)
  464.         if(dindex % 4 == 0)
  465.             sectot += LYEAR;
  466.         else
  467.             sectot += RYEAR;
  468.  
  469.     return(sectot);
  470. }
  471.  
  472. locked(file)
  473.     char    *file;
  474. {
  475.     char    lfile[BUFSIZ];
  476.     struct    stat sbuf;
  477.     int    count = 0;
  478.  
  479.     (void)sprintf(lfile,"%s.lock",file);
  480.  
  481.     for(count = 0; count < 3; count++) {
  482.         if(stat(lfile,&sbuf) < 0)
  483.             break;
  484.         else
  485.             sleep(3);
  486.     }
  487.     return(count==3);
  488. }
  489.  
  490. lock(file)
  491.     char    *file;
  492. {
  493.     char    fname[BUFSIZ];
  494.     int    fd;
  495.  
  496.     (void)sprintf(fname,"%s.lock",file);
  497.  
  498.     if((fd = open(fname,O_CREAT,0700)) < 0) {
  499.         perror(fname);
  500.         return(0);
  501.     }
  502.     (void)close(fd);
  503.     return(1);
  504. }
  505.  
  506. unlock(file)
  507.     char    *file;
  508. {
  509.     char    fname[BUFSIZ];
  510.  
  511.     (void)sprintf(fname,"%s.lock",file);
  512.  
  513.     if(unlink(fname) < 0) {
  514.         perror(fname);
  515.         return(0);
  516.     }
  517.     return(1);
  518. }
  519.     
  520. void
  521. usage()
  522. {
  523.     (void)fprintf(stderr,
  524.     "Usage: %s [-a age] [-d] [-o] [-u username] [-v] [-z] mailbox..\n",
  525.         myname);
  526. }
  527.