home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mq / mq.c < prev    next >
C/C++ Source or Header  |  1989-03-05  |  10KB  |  437 lines

  1. /* program for selectively displaying the mail queue. 
  2.  *
  3.  * usage:
  4.  *    mq [-w] [-n] [-v] [-f [name]] [-t [name]] [-d name]
  5.  *
  6.  * caveats/comments:
  7.  *    -> 1) no checking is done w.r.t. what other programs are doing 
  8.  *          to the mail queue files.
  9.  *       2) items in the queue without a control file are ignored and 
  10.  *          not counted. 
  11.  *       3) one might also want to sort by priority.
  12.  *
  13.  * author:
  14.  *    Kevin Sweet ---------------------------------- sweet@scubed.arpa
  15.  *    S-CUBED, 3398 Carmel Mountain,  San Diego, CA 92121-1095
  16.  *    (home)  12205 Carmel Vista 242, San Diego, CA 92130-2237
  17.  *    ------- [ames,att,harvard,rutgers,ucsd,uunet]scubed!sweet ------
  18.  *
  19.  * This work is copyright 1988 by Kevin Sweet. Permission is granted 
  20.  * to modify and distribute this work under the provision that the 
  21.  * author is informed of any non-cosmetic changes to the code and that 
  22.  * the author's name remain part of the documentaion. 
  23.  */
  24.  
  25. #ifndef VOID
  26. # define VOID
  27. #endif
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #ifdef SYSV
  31. # include <string.h>
  32. # define index        strchr
  33. # define rindex        strrchr
  34. # include <ndir.h>    /* see Makefile... */
  35. #else /* SYSV */
  36. # include <strings.h>
  37. # include <sys/dir.h>
  38. #endif
  39. #include <stdio.h>
  40. #include <ctype.h>
  41.  
  42. int order();
  43. extern int free(), qsort();
  44. extern long atol();
  45. extern char *ctime(), *getenv(), *malloc();
  46. static int gethelp();
  47.  
  48. #define FALSE        0
  49. #define LSIZE        256
  50. #define MALLOC(a)    (char *) malloc( (unsigned) sizeof(char) * \
  51.                              ((a) + 1) )
  52. #define NUMQ        128
  53. /* #define SORT_BY_ID    /**/
  54. #define SORT_BY_TIME    /**/
  55. #define SWITCHAR    '-'
  56. #define TRUE        1
  57.  
  58. struct mqueue {
  59.     long l;        /* location in directory stream */
  60.     long t;        /* time entered queue */
  61.     char q[8];    /* queue id */
  62. };
  63. typedef unsigned short int BOOLEAN;
  64.  
  65. main(argc, argv)
  66. int argc;
  67. char *argv[];
  68. {
  69.     BOOLEAN DONT, FROM, NUMBER, TO, VERBOSE, WIDE;
  70.     DIR *dp;
  71.     FILE *fp;
  72.     char dont[80], from[80], line[LSIZE], to[80];
  73.     register char *cp, *fg, *message, *qdir, *user;
  74.     register int i, icnt, ldont, lfrom, lto, mcnt, qcnt, qdlen;
  75.     register long size;
  76.     struct direct *dirp;
  77.     struct mqueue qinfo[NUMQ];
  78.     struct stat sbuf;
  79.  
  80.     /* find the print options
  81.      */
  82. #ifdef SYSV
  83.     user = getenv("LOGNAME");
  84. #else
  85.     user = getenv("USER");
  86. #endif
  87.     DONT = FROM = NUMBER = TO = VERBOSE = WIDE = FALSE;
  88.     for (i = 1, cp = argv[1]; i < argc; i++, cp = argv[i]) 
  89.     if (cp[0] == SWITCHAR) 
  90.     switch (cp[1]) {
  91.         case 'h': case 'H': 
  92.             gethelp(argv[0], 0);
  93.         case 'n': case 'N': 
  94.             NUMBER = TRUE;
  95.             break;
  96.         case 'w': case 'W': 
  97.             WIDE = TRUE;
  98.             break;
  99.         case 'v': case 'V': 
  100.             VERBOSE = TRUE;
  101.             break;
  102.         case 'f': case 'F': 
  103.             FROM = TRUE;
  104.             if (cp[2]) 
  105.                 sprintf(from, "%.79s", &argv[i][2]);
  106.             else 
  107.             if (i != argc-1 && argv[i+1][0] != SWITCHAR) {
  108.                 sprintf(from, "%.79s", argv[i+1]);
  109.                 i++;
  110.             }
  111.             else
  112.             sprintf(from, "%.79s", user);
  113.             lfrom = strlen(from);
  114.             break;
  115.         case 't': case 'T': 
  116.             TO = TRUE;
  117.             if (cp[2]) 
  118.                 sprintf(to, "%.79s", &argv[i][2]);
  119.             else 
  120.             if (i != argc-1 && argv[i+1][0] != SWITCHAR) {
  121.                 sprintf(to, "%.79s", argv[i+1]);
  122.                 i++;
  123.             }
  124.             else
  125.             sprintf(to, "%.79s", user);
  126.             lto = strlen(to);
  127.             break;
  128.         case 'd': case 'D': 
  129.             DONT = TRUE;
  130.             if (cp[2]) 
  131.                 sprintf(dont, "%.79s", &argv[i][2]);
  132.             else 
  133.             if (i != argc-1 && argv[i+1][0] != SWITCHAR) {
  134.                 sprintf(dont, "%.79s", argv[i+1]);
  135.                 i++;
  136.             }
  137.             else 
  138.             sprintf(dont, "%c", '\0');
  139.             ldont = strlen(dont);
  140.             if (!ldont) DONT = FALSE;
  141.             break;
  142.         default: 
  143.             printf("invalid option '%c': ", cp[1]);
  144.             gethelp(argv[0], -1);
  145.     }    /* end switch */
  146.     else 
  147.     {
  148.         gethelp(argv[0], 0);
  149.     }    /* end for/if */
  150.  
  151.     /* find the mqueue directory. 
  152.      */
  153.     qcnt = 0;
  154. #ifndef DEBUG
  155.     if ( !(fp = fopen("/usr/lib/sendmail.cf", "r")) ) {
  156.         printf("fatal error: ");
  157.         printf("unable to read /usr/lib/sendmail.cf\n");
  158.         gethelp(argv[0], 1);
  159.     }
  160.     while ((fg = fgets(line, LSIZE, fp)) != (char *) NULL) {
  161.         if (strncmp(fg, "OQ", 2)) continue;
  162.         fg[strlen(line)-1] = '\0';
  163.         fg += 2;
  164.         qcnt++;
  165.         qdlen = strlen(fg) + 1;
  166.         qdir = MALLOC(qdlen);
  167.         strncpy(qdir, fg, qdlen - 1);
  168.         break;
  169.     }
  170.     fclose(fp);
  171. #endif /* DEBUG */
  172.     if (!qcnt) {
  173.         qdlen = strlen(MQUEUE) + 1;
  174.         qdir = MALLOC(qdlen);
  175.         strncpy(qdir, MQUEUE, qdlen - 1);
  176.     }
  177.  
  178.     /* find queue files in the mqueue directory: 
  179.      * save the location in the directory stream, the queue id and 
  180.      * the time for each vaild (non-zero length) queue control file.
  181.      */
  182.     if ( !(dp = opendir(qdir)) ) {
  183.         printf("fatal error: ");
  184.         printf("unable to open directory %s\n", qdir);
  185.         gethelp(argv[0], 2);
  186.     }
  187.     mcnt = qcnt = 0;
  188.     for (dirp = readdir(dp); dirp != (struct direct *) NULL; 
  189.          dirp = readdir(dp)) 
  190.     if (!strncmp(dirp->d_name, "qf", 2)) {
  191.         /*
  192.          * open the file and test it for validity 
  193.          */
  194.         cp = MALLOC(qdlen + 1 + strlen(dirp->d_name));
  195.         sprintf(cp, "%s/%s", qdir, dirp->d_name);
  196.         fp = fopen(cp, "r");
  197.         VOID stat(cp, &sbuf);
  198.         VOID free(cp);
  199.         if (!fp) continue;
  200.         if (!sbuf.st_size) {
  201.             fclose(fp);
  202.             continue;
  203.         }
  204.         /* 
  205.          * do book-keeping
  206.          */
  207.         icnt = 0;
  208.         mcnt++;
  209.         if (qcnt < NUMQ) 
  210.         /*
  211.          * check to see if we are supposed to print the entry
  212.          */
  213.         while ( fg = fgets(line, LSIZE, fp) ) {
  214.             fg[strlen(line)-1] = '\0';
  215.             if (*fg == 'S') {
  216.                 if (FROM) {
  217.                     for (; *fg; *fg++) 
  218.                     if (!strncmp(fg, from, lfrom)) 
  219.                     icnt |= 0x001;
  220.                 } else 
  221.                 icnt |= 0x001;
  222.             } else
  223.             if (*fg == 'R') {
  224.                 if (TO) {
  225.                     for (; *fg; *fg++) 
  226.                     if (!strncmp(fg, to, lto)) 
  227.                     icnt |= 0x002;
  228.                 } else 
  229.                 icnt |= 0x002;
  230.                 if (DONT) {
  231.                     for (; *fg; *fg++) 
  232.                     if (!strncmp(fg, dont, ldont)) 
  233.                     icnt |= 0x004;
  234.                 } 
  235.             }
  236.         }    /* end while loop */
  237.  
  238.         if ( (icnt & 0x004) || 
  239.             !(icnt & 0x002) || 
  240.             !(icnt & 0x001) ) {
  241.             /*
  242.              * either DONT was specified _and_ we found 
  243.              * the dont field in the Receiver field, 
  244.              * or TO was specified _and_ we did not find 
  245.              * the to field in the Receiver field, 
  246.              * or FROM was specified _and_ we did not find 
  247.              * the from field in the Sender field; 
  248.              * or we have exceeded the array dimension for 
  249.              * holding queue information. 
  250.              */
  251.             fclose(fp);
  252.             continue;
  253.         }
  254.         /*
  255.          * save the location in the directory stream
  256.          */
  257.         qinfo[qcnt].l = telldir(dp);
  258.         /*
  259.          * save the queue id
  260.          */
  261.         sprintf(qinfo[qcnt].q, "%.7s", 
  262.                 index(dirp->d_name, 'f')+1);
  263.         /*
  264.          * save the queue time
  265.          */
  266.         VOID fseek(fp, 0L, 0);
  267.         while ((fg = fgets(line, LSIZE, fp)) && *fg != 'D') 
  268.         if (*fg == 'T') qinfo[qcnt].t = atol(&line[1]);
  269.         /*
  270.          * increment the valid queue file counter
  271.          */
  272.         qcnt++;
  273.         fclose(fp);
  274.     }
  275.     closedir(dp);
  276.  
  277.     /* print the requisite header 
  278.      */
  279.     if (!qcnt) {
  280.         if (!mcnt) printf("Mail queue is empty\n");
  281.         else {
  282.             printf("Mail Queue (%d request%c", 
  283.                    mcnt, mcnt > 1 ? 's' : '\0');
  284.             printf(", none %s)\n", 
  285.                    NUMBER == TRUE ? "applied" : "printed");
  286.         }
  287.         exit(0);
  288.     } 
  289.     printf("%sMail Queue (%d request%c", NUMBER == TRUE ? "" : 
  290.            ( VERBOSE == TRUE ? "      " : "\t\t" ), 
  291.            mcnt, mcnt > 1 ? 's' : '\0');
  292.     if (qcnt != mcnt) 
  293.     printf(", only %d %s", qcnt, 
  294.            NUMBER == TRUE ? "applied" : "printed");
  295.     printf(")\n");
  296.  
  297.     if (NUMBER) exit(0);
  298.  
  299.     if (VERBOSE == FALSE) 
  300.     printf("%s%s\n", "--QID-- --Size-- -----Q-Time----- ", 
  301.            "------------Sender/Recipient-----------------");
  302.  
  303.     /* sort the queue files
  304.      */
  305.     VOID qsort(qinfo, qcnt, sizeof(struct mqueue), order);
  306.  
  307.     /* loop through the valid queue files: 
  308.      */
  309.     for (icnt = 0; icnt < qcnt; icnt++) {
  310.         cp = MALLOC(qdlen + 2 + strlen(qinfo[icnt].q));
  311.         sprintf(cp, "%s/qf%s", qdir, qinfo[icnt].q);
  312.         fp = fopen(cp, "r");
  313.         VOID free(cp);
  314.  
  315.         /* read in everything up to the first header line
  316.          */
  317.         mcnt = 0;
  318.         while ( fg = fgets(line, LSIZE, fp) ) {
  319.  
  320.             /* get rid of the trailing newline
  321.              */
  322.             fg[strlen(line)-1] = '\0';
  323.  
  324.             /* get the size of the data file (long)
  325.              */
  326.             if (*fg == 'D') {
  327.                 cp = MALLOC(qdlen + strlen(fg));
  328.                 sprintf(cp, "%s/%s", qdir, &line[1]);
  329.                 VOID stat(cp, &sbuf);
  330.                 size = (long) sbuf.st_size;
  331.                 VOID free(cp);
  332.             } else 
  333.             /*
  334.              * get the error message (char *)
  335.              */
  336.             if (*fg == 'M') {
  337.                 message = MALLOC(strlen(fg));
  338.                 sprintf(message, "%s", &line[1]);
  339.                 mcnt++;
  340.             } else 
  341.             /*
  342.              * get the sender (char *)
  343.              */
  344.             if (*fg == 'S') {
  345. /*
  346.  * print out what we have so far 
  347.  */
  348. if (VERBOSE) {
  349.     if (WIDE) printf("from: %s\n", &line[1]);
  350.     else printf("from: %.73s\n", &line[1]);
  351. } else {
  352.     printf("%-7.7s %8ld %.16s ", 
  353.            qinfo[icnt].q, size, ctime(&qinfo[icnt].t));
  354.     if (WIDE) {
  355.         printf("%s\n", &line[1]);
  356.         if (mcnt) printf("\t\t\t\t  (%s)\n", message);
  357.     } else {
  358.         printf("%.45s\n", &line[1]);
  359.         if (mcnt) printf("\t\t\t\t  (%.43s)\n", message);
  360.     }
  361. }
  362.                 size = 0L;
  363.                 if (mcnt) VOID free(message);
  364.             } else 
  365.             /*
  366.              * get the recipients (char *)
  367.              */
  368.             if (*fg == 'R') {
  369.                 /*
  370.                  * print out the rest
  371.                  */
  372.                 if (VERBOSE) {
  373.                     printf("      to: ");
  374.                     if (WIDE) 
  375.                     printf("%s\n", &line[1]);
  376.                     else 
  377.                     printf("%.69s\n", &line[1]);
  378.                 } else {
  379.                     printf("\t\t\t\t  ");
  380.                     if (WIDE) 
  381.                     printf("%s\n", &line[1]);
  382.                     else 
  383.                     printf("%.45s\n", &line[1]);
  384.                 }
  385.             }
  386.  
  387.         }    /* end fp loop */
  388.         fclose(fp);
  389.  
  390.         if (VERBOSE) printf("      in queue since: %.16s\n", 
  391.                             ctime(&qinfo[icnt].t));
  392.  
  393.     }    /* end valid queue file loop */
  394.  
  395.     exit(0);
  396. }
  397.  
  398. /* qsort comparison function. 
  399.  */
  400. int 
  401. order(e1, e2)
  402. struct mqueue *e1;
  403. struct mqueue *e2;
  404. {
  405. #ifdef SORT_BY_TIME
  406.     if (e1->t < e2->t) return(-1);
  407.     else if (e1->t > e2->t) return(1);
  408.     else return(0);
  409. #endif
  410. #ifdef SORT_BY_ID
  411.     return(strcmp(e1->q, e2->q));
  412. #endif
  413. }
  414.  
  415. /* the help/usage message 
  416.  */
  417. static 
  418. int 
  419. gethelp(program, exit_status)
  420. char *program;
  421. int exit_status;
  422. {
  423.     register char *name;
  424.  
  425.     name = rindex(program, '/');
  426.     if (name) *name++;
  427.     else {
  428.         name = rindex(program, '\\');
  429.         if (name) *name++;
  430.         else name = program;
  431.     }
  432.     printf("usage: %s [-w] [-n] [-v]", name);
  433.     printf(" [-f [name]] [-t [name]] [-d name]\n");
  434.     exit(exit_status);
  435. }
  436.  
  437.