home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume05 / junkmail < prev    next >
Encoding:
Text File  |  1988-09-11  |  29.8 KB  |  1,209 lines

  1. Subject: junkmail - delete outdated mail automatically
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 5, Issue 6
  6. Submitted by: Wombat <pur-ee!pucc-j.Purdue.EDU!rsk>
  7.  
  8. #    This is a shell archive.
  9. #    Remove everything above and including the cut line.
  10. #    Then run the rest of the file through sh.
  11. #----cut here-----cut here-----cut here-----cut here----#
  12. #!/bin/sh
  13. # shar:    Shell Archiver
  14. #    Run the following text with /bin/sh to create:
  15. #    README
  16. #    junkmail.8
  17. #    junkmail.c
  18. # This archive created: Thu May 15 14:37:16 1986
  19. # By:    Wombat (Purdue University)
  20. cat << \SHAR_EOF > README
  21. Junkmail is designed to be run from "cron" or "at" on a regular basis
  22. in order to keep the size of /usr/spool/mail within reasonable limits.
  23. It deletes old/large mail according to criteria described in the manual
  24. page, and settable at compile or run time.
  25.  
  26. It should be compatible with 4.x BSD; don't know about AT&T Unix.
  27.  
  28. It is also capable of deleting all mail from a specified user--a feature
  29. which is occasionally handy when a malicious/naive user discovers mail.
  30. Comments and bugs to:
  31.  
  32. Rich Kulawiec, pucc-j!rsk, rsk@asc.purdue.edu
  33.  
  34. README            This file
  35. junkmail.c        Superfluous/malicious mail deletion program
  36.     (cc -O -DPUCC -DBSD4_2  -o junkmail junkmail.c)
  37. junkmail.8l        Manual page for above
  38.     (nroff -man junkmail.8l)
  39. SHAR_EOF
  40. cat << \SHAR_EOF > junkmail.8
  41. .TH JUNKMAIL 8 
  42. .UC 4
  43. .SH NAME
  44. junkmail \- delete undesired mail from /usr/spool/mail
  45. .SH SYNOPSIS
  46. .B junkmail \fR[\fB-a\fR] [\fB-w\fR] [\fB-dn\fR[\fB-m\fR]] [\fB-u\fRusername] [directory]
  47. .SH DESCRIPTION
  48. .I Junkmail
  49. is designed to cope with overuse of /usr/spool/mail.
  50. It searches 
  51. /usr/spool/mail/*
  52. for old and/or large letters and deletes them,
  53. leaving a message informing the user of this action.
  54. It may also be used to delete all mail from a specified user.
  55.  
  56. The following options are interpreted by 
  57. .I junkmail.
  58. .TP
  59. .B \-a
  60. Select an audit trail.
  61. .TP
  62. .B \-w
  63. Specifies that shortened files are to be written, 
  64. containing letters that indicate what has been deleted.
  65. Otherwise, only an audit is performed.
  66. .TP
  67. .BI \-d n[-m]
  68. Specifies that the following number
  69. .I
  70. n
  71. or range of numbers
  72. .I
  73. n-m
  74. defines the age of discarded letters.
  75. A letter newer than
  76. .I
  77. n
  78. days will only be discarded if the mail file
  79. exceeds the limit by 100%.
  80. A letter between
  81. .I
  82. n
  83. and
  84. .I
  85. m
  86. days old will be discarded if the mail file exceeds the size
  87. limit.
  88. A letter older than
  89. .I
  90. m
  91. days will always be discarded.
  92. .I
  93. N
  94. defaults to 7;
  95. .I
  96. m,
  97. to 21.
  98. If a single value is specified, it is taken to be
  99. .I
  100. m,
  101. and 
  102. .I
  103. n
  104. is assumed to be 7.
  105. Of course,
  106. .I
  107. m
  108. must be greater than
  109. .I
  110. n.
  111. .TP
  112. .B \-u\fRusername
  113. specifies that all mail originating from user
  114. "username" 
  115. be deleted, whether or not it satisfies the aging constraints.  
  116. All other mail will be untouched, and no letter informing the
  117. recipient(s) of the deletion will be left.
  118. .TP
  119. [directory]
  120. is the optional mail directory name,
  121. with "/usr/spool/mail" as the default.
  122. .SH FILES
  123. /usr/spool/mail/*
  124. .SH "SEE ALSO"
  125. mail(1)
  126. .SH BUGS
  127. When an individual username is selected,
  128. .I
  129. junkmail
  130. cannot cope with large files and prints a message to that
  131. effect rather than deleting the letters.
  132. SHAR_EOF
  133. cat << \SHAR_EOF > junkmail.c
  134.  
  135. /*==========================================================
  136.  *
  137.  * junkmail - delete undesired mail from /usr/spool/mail/*
  138.  *
  139.  * Copyright, Purdue University Computing Center, 1982, all
  140.  * rights reserved.
  141.  *
  142.  * Author: V. Abell
  143.  * Modifications: R. Kulawiec 8/83 added -u flag.
  144.  *          Rewrote a lot of the code to handle buffering.
  145.  *          R. Kulawiec 10/84 added audit trail for -u flag.
  146.  *                    added "reason for deletion"
  147.  *                    added extra line on rewritten headers
  148.  *          R. Kulawiec 6/85  rewritten headers now conform to RFC822.
  149.  *
  150.  *    junkmail [-a] [-w] [-dn[-m]] [-u username] [directory]
  151.  *
  152.  *        -a selects an audit trail.
  153.  *
  154.  *        -w specifies that shortened files are to
  155.  *           be written, containing letters that
  156.  *           indicate what has been deleted.
  157.  *           Otherwise, only an audit is performed.
  158.  *
  159.  *        -d specifies that the following number, n,
  160.  *           or range of numbers, n-m, defines the
  161.  *           age of discarded letters. A letter
  162.  *           newer than n days will only be discarded
  163.  *           if the mail file size exceeds the limit
  164.  *           by 100%. A letter older than m days will
  165.  *           be discarded. n defaults to 7; m, to 21.
  166.  *           If a single value is specified, it is
  167.  *           taken to be m, and n is assumed to be 7.
  168.  *           Of course, m must be > n.
  169.  *
  170.  *        -u username specifies that all mail from user
  171.  *           "username" be deleted, regardless of age
  172.  *           or size.
  173.  *
  174.  *        [directory] is the optional mail directory
  175.  *           name - "/usr/spool/mail" is the default.
  176.  *        
  177.  *
  178.  *==========================================================
  179.  */
  180.  
  181. #include    <stdio.h>
  182. #include    <ctype.h>
  183. #include    <sys/types.h>
  184. #include    <sys/dir.h>
  185. #include    <sys/stat.h>
  186. #include    <time.h>
  187.  
  188. #define    LINE_LEN    1024        /* Maximum length of a line */
  189. #define LOC_TIME_ZONE     5*60        /* local time zone offset (EST) */
  190. #define    FILENAME_LEN    128        /* Length of individual filenames */
  191. #define    DIRECTORY_LEN    128         /* Length of directory name */
  192. #define USERNAME_LEN    128        /* Maximum length of any originator */
  193.  
  194.  
  195. #define    FAILED        -1        /* Failure return code from call */    
  196. #define FAILED_LONG    -1l        /* Failure return code from call */
  197. #define SUCCEED        0        /* Success return code from call */
  198. #define SUCCEED_LONG    0l        /* Success return code from call */
  199.  
  200.  
  201. #define DIRECT    "/usr/spool/mail/"    /* directory name for mail */
  202.  
  203. #define SENDER    "MAILER-DAEMON"        /* audit letter sender */
  204.  
  205. #define MAX_AGE      21L            /* maximum letter age (default) */
  206. #define MIN_AGE      7L            /* minimum letter age (default) */
  207.  
  208. #define PROTECT_MODE     0600        /* protection mode */
  209.  
  210. #define MAX_SIZE      50000            /* nominal maximum mailbox size */
  211. #define ABS_MAX_SIZE     2*MAX_SIZE    /* absolute maximum mailbox size */
  212.  
  213. #define NEWLINE        '\n'        /* Ascii newline character */
  214.  
  215. char Selectname[USERNAME_LEN];        /* name of user whose mail to blast */
  216. char Directory[DIRECTORY_LEN] = DIRECT;    /* working directory (default)    */
  217. char Filename[FILENAME_LEN];        /* individual files as we go */
  218.  
  219. int    audit_flag = 0;            /* Audit trail is selected */
  220. int    rewrite_flag = 0;        /* Rewriting of files will be done */
  221. int    select_flag = 0;        /* Individual user has been selected */
  222. int    date_flag = 0;            /* User has overridden a date(s) */
  223.  
  224. long max_age = MAX_AGE;            /* maximum letter age */
  225. long min_age = MIN_AGE;            /* minimum letter age */
  226.  
  227. char    *day_table[7]    = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
  228.  
  229. int    month_size[12]    = {31,28,31,30,31,30,31,31,30,31,30,31};
  230.  
  231. char    *month_table[12] = {"Jan","Feb","Mar","Apr","May","Jun",
  232.                 "Jul","Aug","Sep","Oct","Nov","Dec"};
  233. struct zone {
  234.     int hours_west;        /* hours west of Greenwich */
  235.     char *st;        /* standard time zone name */
  236.     char *dl;        /* daylight time zone name */
  237. } z_tab[] = {
  238.     4*60, "AST", "ADT",    /* Atlantic */
  239.     5*60, "EST", "EDT",    /* Eastern */
  240.     6*60, "CST", "CDT",    /* Central */
  241.     7*60, "MST", "MDT",    /* Mountain */
  242.     8*60, "PST", "PDT",    /* Pacific */
  243.     0000, "GMT", "GMT",    /* Greenwich */
  244.     -1            /* end of table indicator */
  245. };
  246.  
  247. struct     stat    Sbuf;        /* for return values from stat() call */
  248. struct    direct    Dir_entry;    /* directory structure */
  249.  
  250. #ifdef vax
  251. DIR    *Dfd;
  252. #else
  253. int    Dfd;            /* directory file descriptor */
  254. #endif
  255.  
  256. FILE    *Mfp;                /* mail file pointer         */
  257. FILE    *Tfp;                /* temp file pointer         */
  258.  
  259. char    *Tempfile = "/tmp/junkXXXXXX"; /* Temporary file for copying */
  260.  
  261. char    sndl[512];            /* "MAIL~SYSTEM" sender line */
  262. int    compare_length = USERNAME_LEN;    /* longest originator length */
  263. char    Buffer[LINE_LEN];        /* Input/output mail buffer  */
  264. char    Headbuf[LINE_LEN];        /* Save area for mail header */
  265. long    File_length    = 0l;        /* Length of input mail file */
  266.  
  267. char    *ctime();            /* Time conversion         */
  268. char    *mktemp();            /* Temporary filename maker  */
  269.  
  270. #ifndef vax
  271. char    machine();            /* Machine identifier         */
  272. #endif
  273.  
  274. int    Copy_flag    = 1;    /* Whether or not to copy bytes through */
  275.  
  276. long    bytes_del;        /* Number of bytes deleted from this file */
  277.                 /* (or that could be deleted).  Note that */
  278.                 /* this does NOT account for bytes written */
  279.                 /* by junkmail itself.            */
  280. long    tot_bytes_del    = 0;    /* Total number of bytes deleted in run    */
  281. int    files_short    = 0;    /* Total number of files shortened    */
  282. int    files_del    = 0;    /* Total number of zero-length files deleted */
  283.  
  284. char    Loginname[255];        /* The name of the file in /usr/spool/mail. */
  285.                 /* Set to 255 to avoid unpleasant surprises */
  286.                 /* should a filename > 8 chars creep in.    */
  287.  
  288. main(argc, argv)
  289. int argc;
  290. char *argv[];
  291. {
  292.     int i;
  293.     long time();
  294.     long time_buf;
  295.     char    hoststr[32];
  296.  
  297.     i = 1;
  298.  
  299.     do {
  300.     if(argc != 0)
  301.         if(argc > 1 && strncmp(argv[i],"-",1) == 0 ) {
  302.             if(strncmp(argv[i],"-a",2) == 0) {    /* audit */
  303.                 audit_flag = 1;
  304.                 continue;
  305.             }
  306.             if(strncmp(argv[i],"-w",2) == 0) {    /* rewrite */
  307.                 rewrite_flag = 1;
  308.                 continue;
  309.             }
  310.             if(strncmp(argv[i],"-d",2) == 0) {    /* date ch. */
  311.                 date_flag = 1;
  312.                 if( agerange(argv[i]) == FAILED)
  313.                     usage();
  314.                 continue;
  315.             }
  316.             if(strncmp(argv[i],"-u",2) == 0) {    /* target */
  317.                 if( get_selectname(argv[++i]) == FAILED )
  318.                     usage();
  319.                 select_flag = 1;
  320.                 rewrite_flag = 1;
  321.                 continue;
  322.             }
  323.             usage();
  324.         }
  325.         if(argc > 1) {                    /* chdir */
  326.             if( get_dirname(argv[i])  == FAILED )
  327.                 usage();
  328.             continue;
  329.         }
  330.     }
  331.     while(++i < argc);
  332.  
  333.     if(select_flag && date_flag) {
  334.         fprintf(stderr,"Use of -u and -d together not allowed\n");
  335.         usage();
  336.     }
  337.  
  338.     time(&time_buf);
  339.  
  340. #ifdef vax
  341.     if(gethostname(hoststr,sizeof(hoststr)) == FAILED)
  342.         fprintf(stderr,"Gethostname() failed!\n");    
  343. #else
  344.     sprintf(hoststr,"pucc-%s",machine());
  345. #endif
  346.  
  347.     if(audit_flag)
  348.         printf("\n%s, %s\n",hoststr,ctime(&time_buf));
  349.  
  350.     if(rewrite_flag)
  351.         sprintf(sndl,"From %s %sReceived: by %s, %sDate: %sFrom: <pucc> %s\nTo: ",SENDER,ctime(&time_buf),hoststr,ctime(&time_buf),ctime(&time_buf),SENDER);
  352.  
  353.     if(rewrite_flag)
  354.         Tempfile = mktemp(Tempfile);
  355.  
  356.     if(check_dirname() == FAILED)
  357.         usage();
  358.  
  359.     if(select_flag)
  360.         printf("Deleting all mail from user %s\n\n",Selectname);
  361.  
  362.     while( get_filename() != FAILED) {
  363.         if(select_flag) {
  364.             if(del_user()==FAILED)
  365.                 exit(1);
  366.         }
  367.         else {
  368.             if(del_oldbig() == FAILED)
  369.                 exit(1);
  370.         }
  371.         if(audit_flag && (bytes_del != 0) ) {
  372.             printf("\t%s",Filename);
  373.             if(rewrite_flag)
  374.                 printf(" was shortened by "); 
  375.             else
  376.                 printf(" could be shortened by ");
  377.             printf("%ld bytes\n",bytes_del);
  378.         }
  379.     }
  380.     if(audit_flag) {
  381.         printf("----------\n");
  382.         printf("%d files",files_short);
  383.         if(rewrite_flag)
  384.             printf(" were shortened by "); 
  385.         else
  386.             printf(" could be shortened by ");
  387.         printf("%ld bytes\n",tot_bytes_del);
  388.         if( !select_flag) {
  389.             printf("%d zero-length files",files_del);
  390.             if(rewrite_flag)
  391.                 printf(" were deleted\n"); 
  392.             else
  393.                 printf(" could be deleted\n");
  394.         }
  395.         printf("----------\n");
  396.     }
  397. }
  398. /*==================================================
  399.  *
  400.  * usage() - print argument usage message and exit. 
  401.  *
  402.  *
  403.  *==================================================
  404.  */
  405.  
  406. usage()
  407. {
  408.     fprintf(stderr,"Usage: junkmail [-a] [-w] [-dn[-m]] [-u username] [directory]\n");
  409.     exit(1);
  410. }
  411.  
  412. /*==================================================
  413.  *
  414.  * get_selectname(p) - Get the username pointed to.
  415.  *
  416.  *
  417.  *==================================================
  418.  */
  419.  
  420. get_selectname(p)
  421. char *p;
  422. {
  423.     if(strlen(p) > USERNAME_LEN)        /* Username can't be more */
  424.         return(FAILED);            /* than this long         */
  425.     if(strlen(p) <= 0 )            /* Username can't this    */
  426.         return(FAILED);            /* long either           */
  427.     else {
  428.         strcpy(Selectname,p);
  429.         return(SUCCEED);
  430.     }
  431. }
  432.  
  433. /*==================================================
  434.  *
  435.  * get_dirname(p) - Get the directory name pointed to.
  436.  *
  437.  *
  438.  *==================================================
  439.  */
  440.  
  441. get_dirname(p)
  442. char *p;
  443. {
  444.     if(strlen(p) > DIRECTORY_LEN)        /* Username can't be more */
  445.         return(FAILED);            /* than this long         */
  446.     if(strlen(p) <= 0 )            /* Username can't this    */
  447.         return(FAILED);            /* long either           */
  448.     else {
  449.         strcpy(Directory,p);
  450.         return(SUCCEED);
  451.     }
  452. }
  453.  
  454. /*==========================================================
  455.  *
  456.  * agerange(p) - assemble the age range represented by the
  457.  *         characters at (p).
  458.  *
  459.  *    exit    return = 0 if range assembled
  460.  *            -1 if assembly error detected
  461.  *        (min_age) = minimum age
  462.  *        (max_age) = maximum age
  463.  *
  464.  *==========================================================
  465.  */
  466.  
  467. agerange(p)
  468. char *p;
  469. {
  470.     int n;            /* number being assembled */
  471. /*
  472.  *    Assemble first number.
  473.  */
  474.     p += 2;            /* Skip over the "-d" flag    */
  475.  
  476.     for(n = 0; *p >= '0' && *p <= '9'; p++)
  477.         n = 10 * n + *p - '0';
  478.     if(*p != '\0') {
  479.         if(*p++ != '-')
  480.         return(FAILED);
  481. /*
  482.  *    If the first number is terminated by a minus sign ("-"),
  483.  *    assemble the second number of an "n-m" range.
  484.  */
  485.         min_age = (long) n;
  486.         for(n = 0; *p >= '0' && *p <= '9'; p++)
  487.         n = 10 * n + *p - '0';
  488.         }
  489.     max_age = (long) n;
  490.     if(min_age <= 0l || max_age <= 0l || min_age >= max_age)
  491.         return(FAILED);
  492.     return(SUCCEED);
  493. }
  494.  
  495. /*======================================================================
  496.  *
  497.  * long dysince(a) - convert the ctime() format date, addressed by (a)
  498.  *             to the number of days since that date.
  499.  *
  500.  *    exit    return = -1L if the date cannot be converted
  501.  *
  502.  *======================================================================
  503.  */
  504. long dysince(a)
  505. char    *a;
  506. {
  507.  
  508.     int day;        /* day */
  509.     int hours;        /* hours */
  510.     int minutes;         /* minutes */
  511.     int month;         /* month */
  512.     int seconds;        /* seconds */
  513.     int year;        /* year */
  514.     int z = LOC_TIME_ZONE;    /* time zone offset */
  515.     long time_buf;        /* time buffer */
  516.     long time_sec = 0l;    /* time in seconds */
  517.     register int i;     /* temporary index */
  518. /*
  519.  *    Check and skip day of week.
  520.  */
  521.     if(ckalpha(a,3) == 0)
  522.         return(FAILED_LONG);
  523.     for(i = 0; i < 7; i++)
  524.         if(strncmp(a,day_table[i],3) == 0)
  525.         break;
  526.     if(i > 6)
  527.         return(FAILED_LONG);
  528.     a += 3;
  529.     if(*a++ != ' ')
  530.         return(FAILED_LONG);
  531. /*
  532.  *     Check month and convert to integer.
  533.  */
  534.     if(ckalpha(a,3) == 0)
  535.         return(FAILED_LONG);
  536.     for(month = 0; month < 12; month++)
  537.         if(strncmp(a,month_table[month],3) == 0)
  538.         break;
  539.     if(month > 11)
  540.         return(FAILED_LONG);
  541.     a += 3;
  542.     while(*a == ' ') {
  543.         if(*a == '\0')
  544.         return(FAILED_LONG);
  545.         a++;
  546.         }
  547. /*
  548.  *    Convert day number.
  549.  */
  550.     day = atoi(a);
  551.     while(*a >= '0' && *a <= '9')
  552.         a++;
  553.     while(*a == ' ') {
  554.         if(*a == '\0')
  555.         return(FAILED_LONG);
  556.         a++;
  557.         }
  558. /*
  559.  *    Convert time.
  560.  */
  561.     hours = atoi(a);
  562.     while(*a >= '0' && *a <= '9')
  563.         a++;
  564.     if(hours < 0 || hours > 23 || *a++ != ':')
  565.         return(FAILED_LONG);
  566.     minutes = atoi(a);
  567.     while(*a >= '0' && *a <= '9')
  568.         a++;
  569.     if(minutes < 0 || minutes > 59 || *a++ != ':')
  570.         return(FAILED_LONG);
  571.     seconds = atoi(a);
  572.     while(*a >= '0' && *a <= '9')
  573.         a++;
  574.     if(seconds < 0 || seconds > 59 || *a++ != ' ')
  575.         return(FAILED_LONG);
  576. /*
  577.  *    Convert time zone and year.
  578.  */
  579.     if((*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z')) {
  580.         if(ckalpha(a,3) == 0)
  581.         return(FAILED_LONG);
  582.         for(i = 0; (z = z_tab[i].hours_west) >= 0; i++) {
  583.         if(strncmp(a,z_tab[i].st,3) == 0
  584.            || strncmp(a,z_tab[i].dl,3) == 0)
  585.             break;
  586.         }
  587.         if(z == -1)
  588.         return(FAILED_LONG);
  589.         while(*a < '0' || *a > '9') {
  590.         if(*a == '\0')
  591.             return(FAILED_LONG);
  592.         a++;
  593.         }
  594.         }
  595.     minutes += z;
  596.     year = atoi(a);
  597. /*
  598.  *    Check year.
  599.  */
  600.     if(year < 1970)
  601.         return(FAILED_LONG);
  602. /*
  603.  *    Cope with February in leap/non-leap years.
  604.  */
  605.     if(leap(year))
  606.         month_size[1] = 29;
  607.     else
  608.         month_size[1] = 28;
  609.     if(day < 1 || day > month_size[month])
  610.         return(FAILED_LONG);
  611. /*
  612.  *    Calculate seconds since the epoch.
  613.  */
  614.     for(i = 1970; i < year; i++)
  615.         time_sec += (leap(i) ? 366 : 365);
  616.     while(--month >= 0)
  617.         time_sec += month_size[month];
  618.     time_sec += (long) day - 1l;
  619.     time_sec = time_sec*24l + (long) hours;
  620.     time_sec = time_sec*60l + (long) minutes;
  621.     time_sec = time_sec*60l + (long) seconds;
  622. /*
  623.  *    Return days from today as (seconds from today).
  624.  *                   ------------------
  625.  *                      24 * 60 * 60
  626.  */
  627.     time(&time_buf);
  628.     if(time_sec > time_buf)
  629.         return(FAILED_LONG);
  630.     return((time_buf - time_sec) / 86400l);
  631. }
  632.  
  633. /*=============================================
  634.  *
  635.  * leap(y) - test (y) for a leap year
  636.  *
  637.  *    exit    return = 0 if not a leap year
  638.  *             1 if a leap year
  639.  *
  640.  *=============================================
  641.  */
  642.  
  643. leap(y)
  644. int y;
  645. {
  646.     return(y%4 == 0 && y%100 != 0 || y%400 == 0);
  647. }
  648.  
  649. /*====================================================================
  650.  *
  651.  * ckalpha(a,n) - check for n consecutive alpha characters, starting 
  652.  *          at (a).
  653.  *
  654.  *    exit    return = 0 if non-alpha character encountered
  655.  *             1 if characters available
  656.  *
  657.  *====================================================================
  658.  */
  659.  
  660. ckalpha(a,n)
  661.  
  662. char *a;
  663. int n;
  664.  
  665. {
  666.     register int i;     /* temporary index */
  667.     
  668.     for(i = 0; i < n; i++)
  669.         if( (! isascii(*a)) || (! isalpha(*a)) )
  670.             return(0);
  671.     return(1);
  672. }
  673.  
  674. /*====================================================================
  675.  *
  676.  * check_dirname() - Verify that "Directory" exists, is a 
  677.  *            directory, and is readable.
  678.  *
  679.  *    exit    return = 0 if a legitimate directory has been found
  680.  *            -1 otherwise
  681.  *
  682.  *====================================================================
  683.  */
  684. check_dirname()
  685. {
  686.  
  687.     if( stat(Directory,&Sbuf) == FAILED) {
  688.         fprintf(stderr,"Can't stat %s\n",Directory); 
  689.         return(FAILED);
  690.     }
  691.     if( ((Sbuf.st_mode & S_IFDIR) == 0) || Sbuf.st_ino == 0 ) {
  692.         fprintf(stderr,"%s is not a directory\n",Directory);
  693.         return(FAILED);
  694.     }
  695. #ifdef vax
  696.     if( (Dfd = opendir(Directory)) == NULL) {
  697. #else
  698.     if( (Dfd = open(Directory,0)) == FAILED) {
  699. #endif
  700.         fprintf(stderr,"Can't open directory %s\n",Directory);
  701.         return(FAILED);
  702.     }
  703.     return(SUCCEED);
  704. }    
  705. /*====================================================================
  706.  *
  707.  * get_filename() - Get the next file in directory "Directory".
  708.  *
  709.  *    exit    return = 0 if a legitimate file has been found
  710.  *            -1 otherwise
  711.  *
  712.  *        Note: "Reads through" '.' and '..' transparently.
  713.  *
  714.  *====================================================================
  715.  */
  716. get_filename()
  717. {
  718.     int    pathlength;
  719. #ifdef vax
  720.     struct direct *dirent;
  721. #endif
  722.     /* Add tailing slash to directory name if user forgot it */
  723.  
  724.     if(Directory[strlen(Directory)-1] != '/')
  725.         strcat(Directory,"/");
  726.  
  727.     strcpy(Filename,Directory);
  728.     pathlength = strlen(Filename);
  729.  
  730. #ifdef vax
  731.     while( (dirent = readdir(Dfd)) != NULL) {
  732.         if(dirent->d_ino == 0)        /* File has been deleted */
  733.             continue;
  734.         if(strncmp(dirent->d_name,".",1) == 0)        /* Skip "." */
  735.             continue;
  736.         if(strncmp(dirent->d_name,"..",2) == 0)        /* Skip ".." */
  737.             continue;
  738.         strncpy(&Filename[pathlength],dirent->d_name,sizeof(dirent->d_name));
  739.         strcpy(Loginname,dirent->d_name);
  740.         return(SUCCEED);
  741.     }
  742.     closedir(Dfd);
  743.     return(FAILED);
  744. #else
  745.     while(read(Dfd,&Dir_entry,sizeof(Dir_entry)) > 0) {
  746.         if(Dir_entry.d_ino == 0)    /* File has been deleted */
  747.             continue;
  748.         if(strncmp(Dir_entry.d_name,".",1) == 0)    /* Skip "." */
  749.             continue;
  750.         if(strncmp(Dir_entry.d_name,"..",2) == 0)    /* Skip ".." */
  751.             continue;
  752.         strncpy(&Filename[pathlength],Dir_entry.d_name,sizeof(Dir_entry.d_name));
  753.         strcpy(Loginname,Dir_entry.d_name);
  754.         return(SUCCEED);
  755.     }
  756.     if( close(Dfd) == FAILED)
  757.         fprintf(stderr,"Couldn't close %s\n",Directory);
  758.  
  759.     return(FAILED);                /* Have read entire dir. */
  760. #endif
  761. }    
  762. /*==================================================
  763.  *
  764.  * del_oldbig() - remove letters that are either too old or too big.
  765.  *          remove mailboxes that are zero length.
  766.  *        exit -    0 if no problems encountered
  767.  *              1 if couldn't open or other nastiness
  768.  *
  769.  *==================================================
  770.  */
  771. del_oldbig()
  772. {
  773.     long    finalsize;
  774.     long    size_date();
  775.     long    filemark;        /* Marks beginning of current letter */
  776.     int    onetrip;        /* Whether or not we've made first   */
  777.                     /* trip through mail scanning loop   */
  778.     int    copy;            /* Temporary loop index for saving   */
  779.                     /* mail headers              */
  780.     int    wrote_sndl;        /* Whether or not we've written our  */
  781.                     /* "From" line to temp file         */
  782.  
  783.     if( stat(Filename,&Sbuf) == FAILED) {
  784.         fprintf(stderr,"Can't stat %s\n",Filename); 
  785.         return(FAILED);
  786.     }
  787.  
  788.     /* Reset delete counter in case we exit before setting it below */
  789.  
  790.     bytes_del = 0l;
  791.  
  792.     /* If file is zero length, mark it for deletion */
  793.  
  794.     if(Sbuf.st_size == 0) {
  795.         ++files_del;
  796.         if(rewrite_flag)
  797.             unlink(Filename);
  798.         if(audit_flag && rewrite_flag)
  799.             printf("\t%s was zero-length, deleted\n",Filename);
  800.         if(audit_flag && !rewrite_flag)
  801.             printf("\t%s is zero-length\n",Filename);
  802.         return(SUCCEED);
  803.     }
  804.  
  805.     /* Determine what the final size for this file should be */
  806.  
  807.     if( (finalsize = size_date()) == FAILED_LONG) {
  808.         fprintf(stderr,"Error determining date/size of %s\n",Filename);
  809.         return(FAILED);
  810.     }
  811.         
  812.     if(Sbuf.st_size <= finalsize)        /* File is smaller than it */
  813.         return(SUCCEED);        /* has to be, no problem.  */
  814.  
  815.     ++files_short;                /* Another one shortened */
  816.  
  817.     File_length = Sbuf.st_size;
  818.     filemark = File_length;
  819.  
  820.     onetrip = FAILED;
  821.     wrote_sndl = FAILED;
  822.  
  823.     if( (Mfp = fopen(Filename,"r+")) == NULL) {
  824.         fprintf(stderr,"Can't open %s\n",Filename);
  825.         return(FAILED);
  826.     }
  827.     if(rewrite_flag) {
  828.         if( (Tfp = fopen(Tempfile,"w+")) == NULL) {
  829.             fprintf(stderr,"Can't open tempfile %s\n",Tempfile);
  830.             return(FAILED);
  831.         }
  832.     }
  833.  
  834.     while( readline() == SUCCEED && File_length > finalsize) {
  835.         if(is_a_header() == SUCCEED) {
  836.             if(rewrite_flag && (from_system() == FAILED) ) {
  837.                     if(wrote_sndl == FAILED) {
  838.     fprintf(Tfp,"%s",sndl);
  839.     if( rindex(Filename,'/') == NULL) {
  840.         fprintf(Tfp,"%s\nSubject: Mail deleted by MAILER-DAEMON\n\n",Filename);
  841.     }
  842.     else {
  843.         fprintf(Tfp,"%s\nSubject: Mail deleted by MAILER-DAEMON\n\n",rindex(Filename,'/') + (char *) (1));
  844.     }
  845.                         wrote_sndl = SUCCEED;
  846.                     }
  847.                 fprintf(Tfp,"  Letter deleted: ");
  848.                 writeline();
  849.             }
  850.             if(audit_flag && (onetrip == SUCCEED) ) {
  851.                 printf("%s: ",Loginname);
  852.                 printf("%8ld bytes: ",filemark-File_length);
  853.                 filemark = File_length;
  854.                 printhead();
  855.             }
  856.             if (audit_flag) {
  857.                 for(copy=0 ; copy < LINE_LEN ; copy++) {
  858.                     Headbuf[copy]= Buffer[copy];
  859.                 }
  860.             }
  861.             onetrip = SUCCEED;
  862.         }
  863.     }
  864.  
  865.     /* Eat up rest of last message deleted; wait for next letter header */
  866.  
  867.     while(readline() == SUCCEED && is_a_header() == FAILED);
  868.  
  869.     bytes_del = Sbuf.st_size - File_length;
  870.     tot_bytes_del += bytes_del;
  871.  
  872.     /* Write out this new header, but be careful to check that */
  873.     /* it definitely is one. (I.e., one-line loop above may have */
  874.     /* exited due to EOF and not a "From" line.        */
  875.  
  876.     /* Also make sure to add a newline at the end of our message */
  877.     /* so as not to confuse any mailers.            */
  878.  
  879.     if(rewrite_flag && is_a_header() == SUCCEED ) {
  880.         if(finalsize == 0)
  881.             fprintf(Tfp,"\n  Reason: system mailbox older than %d days\n\n",max_age);
  882.         else if (finalsize == MAX_SIZE)
  883.             fprintf(Tfp,"\n  Reason: system mailbox older than %d days and larger than %ld bytes\n\n",min_age,MAX_SIZE);
  884.         else if (finalsize == ABS_MAX_SIZE)
  885.             fprintf(Tfp,"\n  Reason: system mailbox larger than %ld bytes\n\n",ABS_MAX_SIZE);
  886.         else 
  887.             fprintf(Tfp,"\n  Reason: unknown\n\n");
  888.         writeline();
  889.     }
  890.     if(audit_flag) {
  891.         printf("%s: ",Loginname);
  892.         printf("%8ld bytes: ",filemark-File_length);
  893.         filemark = File_length;
  894.         printhead();
  895.         for(copy=0 ; copy < LINE_LEN ; copy++) {
  896.             Headbuf[copy]= Buffer[copy];
  897.         }
  898.     }
  899.  
  900.     while(readline() == SUCCEED) {
  901.         if(rewrite_flag)
  902.             writeline();
  903.     }
  904.  
  905.     if(cleanup() == FAILED)
  906.         return(FAILED);
  907.     return(SUCCEED);
  908. }
  909. /*==================================================
  910.  *
  911.  * from_system() - returns true if this letter was
  912.  *         from a previous invocation of this
  913.  *        program; causes mail files to decay
  914.  *        to zero length eventually.
  915.  *
  916.  *==================================================
  917.  */
  918. from_system()
  919. {
  920.     if( strncmp(&Buffer[5],&sndl[5],strlen(SENDER) ) == 0)
  921.         return(SUCCEED);
  922.     else
  923.         return(FAILED);
  924. }
  925.  
  926. /*==================================================
  927.  *
  928.  *
  929.  * del_user() - remove letters that are from user "Selectname" 
  930.  *        exit -    0 if no problems encountered
  931.  *              1 if couldn't open or other nastiness
  932.  *
  933.  *
  934.  *==================================================
  935.  */
  936. del_user()
  937. {
  938.     int    file_trunc;        /* Set if this file truncated */
  939.  
  940.     long    mark_beg;        /* marks beginning of current letter */
  941.     long    mark_end;        /* marks end of current letter */
  942.     int    copy;            /* Temporary loop index for saving */
  943.                     /* mail headers */
  944.     file_trunc = 0;            /* Zero out audit counters */
  945.     bytes_del = 0;
  946.  
  947.     if( stat(Filename,&Sbuf) == FAILED) {
  948.         fprintf(stderr,"Can't stat %s\n",Filename); 
  949.         return(FAILED);
  950.     }
  951.  
  952.     /* If file is zero length, don't bother with it.    */
  953.     if(Sbuf.st_size == 0)
  954.         return(SUCCEED);
  955.  
  956.     if( (Mfp = fopen(Filename,"r+")) == NULL) {
  957.         fprintf(stderr,"Can't open %s\n",Filename);
  958.         return(FAILED);
  959.     }
  960.     if( (Tfp = fopen(Tempfile,"w+")) == NULL) {
  961.         fprintf(stderr,"Can't open tempfile %s\n",Tempfile);
  962.         return(FAILED);
  963.     }
  964.  
  965.     File_length = Sbuf.st_size;
  966.     mark_beg = File_length;
  967.     mark_end = File_length;
  968.     Copy_flag = 1;
  969.  
  970.     /* The idea of mark_beg and mark_end is that mark_end continually */
  971.     /* keeps track of the end of the previous line, and that mark_beg */
  972.     /* keeps track of the end of the last line of the last letter, so */
  973.     /* the distance between reflects the number of bytes deep we are */
  974.     /* into the current letter.  When we finish with a letter, we know */
  975.     /* how long it was. */
  976.  
  977.     while(readline() == SUCCEED) {
  978.         if(is_a_header() == SUCCEED) {
  979.             if(audit_flag && !Copy_flag) {
  980.                 printf("%s: ", Loginname);
  981.                 printf("%8ld bytes: ", mark_beg - mark_end);
  982.                 printhead();
  983.                 bytes_del += (mark_beg - mark_end);
  984.                 mark_beg = mark_end;
  985.             }
  986.             if(audit_flag && Copy_flag)
  987.                 mark_beg = mark_end;
  988.             if(is_from_user() == SUCCEED) {
  989.                 Copy_flag = 0;
  990.                 file_trunc = 1;
  991.                 if(audit_flag)
  992.                     for(copy = 0; copy < LINE_LEN; copy++)
  993.                         Headbuf[copy] = Buffer[copy];
  994.             }
  995.             else
  996.                 Copy_flag = 1;
  997.         }
  998.         if(Copy_flag)
  999.             writeline();
  1000.         mark_end = File_length;
  1001.     }
  1002.  
  1003.     if( !Copy_flag) {            /* Last letter was hit */
  1004.         if(audit_flag) {
  1005.             printf("%s: ", Loginname);
  1006.             printf("%8ld bytes: ", mark_beg - mark_end);
  1007.             printhead();
  1008.             bytes_del += (mark_beg - mark_end);
  1009.         }
  1010.     }
  1011.  
  1012.     if(file_trunc == 1)
  1013.         ++files_short;
  1014.  
  1015.     tot_bytes_del += bytes_del;
  1016.  
  1017.     if(cleanup() == FAILED)
  1018.         return(FAILED);
  1019.     return(SUCCEED);
  1020. }
  1021. /*
  1022. *******************************************************************
  1023. *    readline() - read a line from input mail file
  1024. *        returns 0 if line successfully read
  1025. *            -1 if out of characters to read
  1026. *******************************************************************
  1027. */
  1028. readline()
  1029. {
  1030.     int    how_many_read = 0;
  1031.     char    *bufptr    = Buffer;
  1032.     char    c;
  1033.  
  1034.     if(File_length == 0)
  1035.         return(FAILED);
  1036.     do{
  1037.         c = getc(Mfp);
  1038.         *bufptr++ = c;
  1039.         ++how_many_read;
  1040.     }
  1041.     while( (c != NEWLINE)
  1042.         && (how_many_read < LINE_LEN)
  1043.         && (how_many_read < File_length) );
  1044.  
  1045.     File_length -= how_many_read;
  1046.     return(SUCCEED);
  1047. }
  1048. /*
  1049. *******************************************************************
  1050. *    writeline() - Write out a line to the temp file.
  1051. *        returns 0 ALWAYS
  1052. *******************************************************************
  1053. */
  1054. writeline()
  1055. {
  1056.     int    i;
  1057.     char    *bufptr    = Buffer;
  1058.     char     c;
  1059.  
  1060.     for( i = 0; i < LINE_LEN; i++) {
  1061.         c = *bufptr++;
  1062.         putc(c,Tfp);
  1063.         if(c == NEWLINE)
  1064.             return(SUCCEED);
  1065.     }
  1066.     return(SUCCEED);
  1067. }
  1068. /*
  1069. *******************************************************************
  1070. *    printhead() - Write out a line to stdout.
  1071. *        returns 0 ALWAYS
  1072. *******************************************************************
  1073. */
  1074. printhead()
  1075. {
  1076.     int    i;
  1077.     char    *bufptr    = Headbuf;
  1078.     char     c;
  1079.  
  1080.     for( i = 0; i < LINE_LEN; i++) {
  1081.         c = *bufptr++;
  1082.         putchar(c);
  1083.         if(c == NEWLINE)
  1084.             return(SUCCEED);
  1085.     }
  1086.     return(SUCCEED);
  1087. }
  1088. /*
  1089. *******************************************************************
  1090. *    is_a_header() - Is this line a mail letter header?
  1091. *            (i.e. Does it begin with "From "?
  1092. *        returns 0 if it is
  1093. *            -1 if not
  1094. *******************************************************************
  1095. */
  1096. is_a_header()
  1097. {
  1098.     if( Buffer[0] != 'F' )
  1099.         return(FAILED);
  1100.     if( Buffer[1] == 'r'
  1101.       && Buffer[2] == 'o'
  1102.       && Buffer[3] == 'm'
  1103.       && Buffer[4] == ' ')        /* If succeeds, must be header */
  1104.         return(SUCCEED);
  1105.     else
  1106.         return(FAILED);
  1107. }
  1108. /*
  1109. *******************************************************************
  1110. *    is_from_user() - Is this file from user "Selectname"?
  1111. *        returns 0 if it is
  1112. *            -1 if not
  1113. *******************************************************************
  1114. */
  1115. is_from_user()
  1116. {
  1117.     int    j;
  1118.     for(j=0;j<strlen(Selectname);j++)
  1119.         if(Buffer[j+5] != Selectname[j])
  1120.             return(FAILED);
  1121.     return(SUCCEED);
  1122. }
  1123. /*
  1124. *******************************************************************
  1125. *    size_date() - Look at modify time and size of this file
  1126. *            to determine to what length it should be cut.
  1127. *        returns 0 if everything goes ok
  1128. *            -1 if time didn't make sense.
  1129. *******************************************************************
  1130. */
  1131. long
  1132. size_date()
  1133. {
  1134.     long    finalsize;
  1135.     long    days_elapsed;
  1136.     char    *filetime;
  1137.  
  1138.     filetime = ctime(&Sbuf.st_mtime);
  1139.  
  1140.     days_elapsed = dysince(filetime);
  1141.  
  1142.     if(days_elapsed > max_age)
  1143.         finalsize = 0;
  1144.     if(days_elapsed <= max_age && days_elapsed > min_age)
  1145.         finalsize = MAX_SIZE;
  1146.     if(days_elapsed <= min_age && days_elapsed >= 0l)
  1147.         finalsize = ABS_MAX_SIZE;
  1148.     if(days_elapsed < 0l)
  1149.         return(FAILED_LONG);
  1150.     return(finalsize);
  1151. }
  1152. /*
  1153. *******************************************************************
  1154. *    cleanup() - Copy results back to original, blast temp file.
  1155. *        returns 0 if everything goes ok
  1156. *            -1 if closes/(un)links/chown/chmod fail
  1157. *******************************************************************
  1158. */
  1159. cleanup()
  1160. {
  1161.     int    c;            /* Character for copying    */
  1162.  
  1163.     if( !rewrite_flag) {        /* If not writing, then stop here */
  1164.         if( fclose(Mfp) != SUCCEED) {
  1165.             fprintf(stderr,"Couldn't close %s\n",Filename);
  1166.             return(FAILED);
  1167.         }
  1168.         return(SUCCEED);
  1169.     }
  1170.  
  1171.     if( fflush(Mfp) != SUCCEED) {
  1172.         fprintf(stderr,"Couldn't fflush %s\n",Filename);
  1173.         return(FAILED);
  1174.     }
  1175.     if( fflush(Tfp) != SUCCEED) {
  1176.         fprintf(stderr,"Couldn't fflush tempfile %s\n",Tempfile);
  1177.         return(FAILED);
  1178.     }
  1179.     if( (Mfp=freopen(Filename,"w",Mfp)) == NULL) {
  1180.         fprintf(stderr,"Couldn't freopen %s\n",Filename);
  1181.         return(FAILED);
  1182.     }
  1183.     if( rewind(Tfp) != SUCCEED) {
  1184.         fprintf(stderr,"Couldn't rewind tempfile %s\n",Tempfile);
  1185.         return(FAILED);
  1186.     }
  1187.  
  1188.     while( (c=getc(Tfp)) != EOF)
  1189.         putc(c,Mfp);
  1190.  
  1191.     if( fclose(Mfp) != SUCCEED) {
  1192.         fprintf(stderr,"Couldn't close %s\n",Filename);
  1193.         return(FAILED);
  1194.     }
  1195.     if( fclose(Tfp) != SUCCEED) {
  1196.         fprintf(stderr,"Couldn't close tempfile %s\n",Tempfile);
  1197.         return(FAILED);
  1198.     }
  1199.     if( unlink(Tempfile) == FAILED) {
  1200.         fprintf(stderr,"Couldn't unlink tempfile %s\n",Tempfile);
  1201.         return(FAILED);
  1202.     }
  1203.     return(SUCCEED);
  1204. }
  1205. SHAR_EOF
  1206. #    End of shell archive
  1207. exit 0
  1208.  
  1209.