home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / duucp-1.17 / AU-117b4-src.lha / src / util / anymail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-24  |  13.5 KB  |  657 lines

  1. /*
  2.  *  AnyMail -x MailReadyFileName -c Command -e user/pattern -i user/pattern ...
  3.  *
  4.  *  (C) Copyright 1990 by Chris Hind Genly, chris@genly.uucp
  5.  *
  6.  *  1.0
  7.  *  ---
  8.  *  - Original version.  Written by Chris Hind Genly.  Major hacks by
  9.  *    Matt Dillon.
  10.  *
  11.  *  1.1
  12.  *  ---
  13.  *  - Empty mail files are no longer listed.
  14.  *  - Pattern matching is now case insensitive.
  15.  *  - LockFile() is used on files in uumail:
  16.  *  - Display is updated after each mail file is scanned, rather than after
  17.  *    all of uumail: is scanned.
  18.  */
  19.  
  20. #include <exec/types.h>
  21. #include <exec/lists.h>
  22. #include <exec/ports.h>
  23. #include <exec/memory.h>
  24. #include <dos/dos.h>
  25. #include <dos/exall.h>
  26. #include <intuition/classes.h>
  27. #include <intuition/intuition.h>
  28. #include <pragmas/intuition_pragmas.h>
  29.  
  30. #include <graphics/graphint.h>
  31. #include <graphics/scale.h>
  32. #include <graphics/gfxbase.h>
  33. #include <pragmas/graphics_pragmas.h>
  34.  
  35. #include <clib/dos_protos.h>
  36. #include <clib/exec_protos.h>
  37. #include <clib/intuition_protos.h>
  38. #include <clib/graphics_protos.h>
  39. #define LIBRARIES_MATHFFP_H
  40. #include <clib/alib_protos.h>
  41. #undef    LIBRARIES_MATHFFP_H
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46.  
  47. #include "protos.h"
  48. #include "config.h"
  49. #include "version.h"
  50. #include <owndevunit.h>
  51.  
  52. #ifndef __SASC
  53. char *strlwr(char *);
  54. #endif
  55.  
  56. typedef struct Node Node;
  57. typedef struct List List;
  58. typedef struct Window Window;
  59. typedef struct RastPort RPort;
  60. typedef struct MsgPort MsgPort;
  61.  
  62. /* 1.1 */
  63. #define LOWERCHAR(c) ('A' <= (c) && (c) <= 'Z' ? (c)-'A'+'a' : (c))
  64.  
  65. /*
  66.  *  ONode is used to track each file that has been scanned and contains
  67.  *  a list of messages already scanned for the file.
  68.  */
  69.  
  70. typedef struct ONode {
  71.     Node    on_Node;        /*    name of file / link node        */
  72.     List    on_List;        /*    message list for file            */
  73.     long    on_Offset;        /*    offset for last valid message        */
  74.     long    on_EndOffset;   /*    end of file (check if appended to)  */
  75.     long    on_MsgNo;        /*    last message #                */
  76. } ONode;
  77.  
  78. #define on_Succ on_Node.ln_Succ
  79. #define on_Name on_Node.ln_Name
  80.  
  81. Window    *Win;        /*    intuition window        */
  82. MsgPort *SigPort;   /*    signal port for sendmail    */
  83. List    FilList;    /*    file-name list            */
  84. List    Excludes;
  85. List    Includes;
  86. int    Count;
  87. BPTR    MailLock;
  88. char    Buf[256];
  89. char    Title[256];
  90.  
  91. struct Library *OwnDevUnitBase;
  92. struct IntuitionBase *IntuitionBase;
  93. struct GfxBase         *GfxBase;
  94.  
  95. IDENT(".05");
  96.  
  97. struct NewWindow Nw = {
  98.     40, 10, 560, 180, (unsigned char)-1, (unsigned char)-1,
  99.     IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_MOUSEBUTTONS,
  100.     WINDOWCLOSE | WINDOWDRAG | WINDOWSIZING | SIMPLE_REFRESH | WINDOWDEPTH,
  101.     NULL, NULL,
  102.     (UBYTE *) "AnyMail Version 1.0     You have mail",
  103.     NULL, /* Screen */
  104.     NULL, /* BitMap */
  105.     30, 30, (unsigned short)-1, (unsigned short)-1, WBENCHSCREEN
  106. };
  107.  
  108. int Init(void);
  109. int TimeToRepeat(int *);
  110. int OkToScan(struct FileInfoBlock *);
  111. void MakeNode(struct List *, char *);
  112. void Display(void);
  113. void Terminate(void);
  114. void SaveConfig(Window *);
  115. void LoadConfig(struct NewWindow *);
  116. long AnyMail(char *, ONode *);
  117. char *FromName(char *);
  118. char *ExtractPersonalName(char *);
  119. ONode *GetONode(char *);
  120. int amatch(char *, char *, int *);
  121.  
  122. /*
  123.  *  A FileInfoBlock structure MUST be longword aligned.
  124.  */
  125.  
  126. char *MailRdyName;
  127. struct FileInfoBlock *Fib;
  128.  
  129. int main (int argc, char **argv)
  130. {
  131.     int i;
  132.     char *command = 0;
  133.     int doCommand = FALSE;
  134.  
  135.     Fib = (struct FileInfoBlock *)malloc(sizeof(struct FileInfoBlock));
  136.     NewList(&Excludes);
  137.     NewList(&Includes);
  138.     NewList(&FilList);
  139.  
  140.     atexit(Terminate);
  141.  
  142.     if ((OwnDevUnitBase = OpenLibrary ((UBYTE *) ODU_NAME, 0)) == NULL) {
  143.     puts("Couldn't open lock library");
  144.     exit(20);
  145.     }
  146.  
  147.     for (i = 1; i < argc; ++i) {
  148.     if (stricmp(argv[i], "-x") == 0) {
  149.         MailRdyName = argv[++i];
  150.     } else if (stricmp(argv[i], "-e") == 0) {
  151.         MakeNode(&Excludes, argv[++i]);
  152.     } else if (stricmp(argv[i], "-i") == 0) {
  153.         MakeNode(&Includes, argv[++i]);
  154.     } else if (stricmp(argv[i], "-c") == 0) {
  155.         command = argv[++i];
  156.     } else {
  157.         fprintf(stderr, "AnyMail: Unknown keyword %s\n", argv[i]);
  158.     }
  159.     }
  160.     if (MailRdyName)
  161.     SigPort = CreatePort ((UBYTE *) MailRdyName, 1);
  162.  
  163.     if (Init()) {
  164.     while (TimeToRepeat(&doCommand)) {
  165.         ONode *onf;
  166.         long offset;
  167.  
  168.         MailLock = Lock ((UBYTE *) GetConfigDir (UUMAIL), ACCESS_READ);
  169.         if (!MailLock)    /*  unrecoverable error */
  170.         break;
  171.         if (Examine(MailLock, Fib)) {
  172.         while (ExNext(MailLock, Fib)) {
  173.             if (!OkToScan(Fib))
  174.             continue;
  175.             onf = GetONode(Fib->fib_FileName);
  176.             if (onf->on_EndOffset < Fib->fib_Size) {
  177.             onf->on_EndOffset = Fib->fib_Size;
  178.             offset = AnyMail(Fib->fib_FileName, onf);
  179.             if (onf->on_Offset != offset) {
  180.                 Display();
  181.                 onf->on_Offset = offset;
  182.             }
  183.             }
  184.         }
  185.         } else {
  186.         break;
  187.         }
  188.         UnLock(MailLock);
  189.         MailLock = 0;
  190.     }
  191.     }
  192.  
  193.     if (doCommand && command)
  194.     Execute ((UBYTE *) command, 0, 0);
  195.  
  196.     return(0);
  197. }
  198.  
  199. int
  200. OkToScan(struct FileInfoBlock *fib)
  201. {
  202.     Node *n;
  203.     char *fileName;
  204.     int cnt;
  205.  
  206.     if (fib->fib_DirEntryType >= 0)
  207.     return FALSE;
  208.  
  209.     for (n = Includes.lh_Head; n->ln_Succ; n = n->ln_Succ) {
  210.     fileName = fib->fib_FileName;
  211.     strlwr(fileName);
  212.     if (amatch(fileName, n->ln_Name, &cnt) && cnt == strlen(fileName))
  213.         return(TRUE);
  214.     }
  215.  
  216.     for (n = Excludes.lh_Head; n->ln_Succ; n = n->ln_Succ) {
  217.     fileName = fib->fib_FileName;
  218.     strlwr(fileName);
  219.     if (amatch(fileName, n->ln_Name, &cnt) && cnt == strlen(fileName))
  220.         return(FALSE);
  221.     }
  222.  
  223.     return(TRUE);
  224. }
  225.  
  226. int
  227. Init (void)
  228. {
  229.     IntuitionBase = (struct IntuitionBase *) OpenLibrary ((UBYTE *) "intuition.library", 0);
  230.     if (IntuitionBase == 0) {
  231.     fprintf(stderr, "AnyMail: Unable to open intuition.library\n");
  232.     return(0);
  233.     }
  234.  
  235.     GfxBase = (struct GfxBase *) OpenLibrary ((UBYTE *) "graphics.library", 0);
  236.     if (GfxBase == 0) {
  237.     fprintf(stderr, ": Unable to open graphics.library\n");
  238.     return(0);
  239.     }
  240.  
  241.     return(1);
  242. }
  243.  
  244. int
  245. TimeToRepeat(int *DoCommand)
  246. {
  247.     struct IntuiMessage *im;
  248.     int done   = FALSE;
  249.     int repeat = FALSE;
  250.     long windowMask;
  251.     long portMask;
  252.     long mask;
  253.  
  254.     if (Win == NULL) {
  255.     Display();
  256.     return(TRUE);
  257.     }
  258.  
  259.     windowMask = 1 << Win->UserPort->mp_SigBit;
  260.  
  261.     if (SigPort)
  262.     portMask = 1 << SigPort->mp_SigBit;
  263.     else
  264.     portMask = 0;
  265.  
  266.     while (!done) {
  267.     mask = Wait(windowMask|portMask|SIGBREAKF_CTRL_C);
  268.  
  269.     if (mask & windowMask) {
  270.         while (im = (struct IntuiMessage *)GetMsg(Win->UserPort)) {
  271.         switch(im->Class) {
  272.         case MOUSEBUTTONS:
  273.             if (im->Code == SELECTDOWN) {
  274.             *DoCommand = TRUE;
  275.             done = TRUE;
  276.             }
  277.             break;
  278.         case REFRESHWINDOW:
  279.             BeginRefresh(Win);
  280.             EndRefresh(Win, TRUE);
  281.             Display();
  282.             break;
  283.         case CLOSEWINDOW:
  284.             done = TRUE;
  285.             break;
  286.         }
  287.         ReplyMsg((struct Message *)im);
  288.         }
  289.     }
  290.     if (mask & portMask) {
  291.         repeat = TRUE;
  292.         done = TRUE;
  293.     }
  294.     if (mask & SIGBREAKF_CTRL_C)
  295.         exit(1);
  296.     }
  297.  
  298.     return repeat;
  299. }
  300.  
  301. long
  302. AnyMail (char *user, ONode *onf)
  303. {
  304.     static char FromLine[256];
  305.     static char SubjLine[256];
  306.     char *file = malloc(strlen(user) + 32);
  307.     FILE *fi;
  308.     long msgno = 0;
  309.     long offset = onf->on_Offset;
  310.  
  311.     if ('a' <= user[0] && user[0] <= 'z')
  312.     user[0] = user[0] - 'a' + 'A';
  313.  
  314.     strcpy(file, MakeConfigPath(UUMAIL, user));
  315.  
  316.     LockFile(file); /* 1.1 */
  317.  
  318.     if (fi = fopen(file, "r")) {
  319.     if (fseek(fi, offset, SEEK_SET) < 0) {
  320.         fclose(fi);
  321.         UnLockFile(file); /* 1.1 */
  322.         return offset;
  323.     }
  324.     while (fgets(Buf, sizeof(Buf), fi)) {
  325.         /*
  326.          *    Start of message
  327.          */
  328.  
  329.         if (strncmp(Buf, "From ", 5) != 0)
  330.         continue;
  331.  
  332.         ++msgno;
  333.  
  334.         /*
  335.          *    Scan headers for From: and Subject:
  336.          *    Headers end with a blank line.
  337.          */
  338.  
  339.         FromLine[0] = 0;
  340.         SubjLine[0] = 0;
  341.  
  342.         while (fgets(Buf, sizeof(Buf), fi) && Buf[0] != '\n') {
  343.         if (strncmp(Buf, "From:", 5) == 0)
  344.             strcpy(FromLine, Buf + 5);
  345.         if (strncmp(Buf, "Subject:", 8) == 0)
  346.             strcpy(SubjLine, Buf + 8);
  347.         }
  348.  
  349.         /* Remove the trailing new line from the subject */
  350.  
  351.         if (SubjLine[0])
  352.         SubjLine[strlen(SubjLine)-1] = 0;
  353.  
  354.         /*
  355.          *    (try) Make sure we didn't read the file just as sendmail
  356.          *    was appending to it.
  357.          */
  358.  
  359.         if (!feof(fi)) {
  360.         sprintf(Buf, "%-2d %-20.20s  %s",
  361.             ++onf->on_MsgNo,
  362.             FromName(FromLine),
  363.             SubjLine
  364.         );
  365.         MakeNode(&onf->on_List, Buf);
  366.         ++Count;
  367.         offset = ftell(fi);
  368.         }
  369.     }
  370.     fclose(fi);
  371.     }
  372.  
  373.     UnLockFile(file);      /* 1.1 */
  374.  
  375.     return offset;
  376. }
  377.  
  378. void
  379. Display(void)
  380. {
  381.     int xmin, xmax, ymin, ymax, x, y;
  382.     int len, lenmax;
  383.     ONode *onf;
  384.     Node *node;
  385.     RPort *rp;
  386.  
  387.     if (Win == NULL) {
  388.     LoadConfig(&Nw);
  389.     Win = OpenWindow(&Nw);
  390.     if (Win == NULL) {
  391.         Nw.LeftEdge = 40;
  392.         Nw.TopEdge = 10;
  393.         Nw.Width = 560;
  394.         Nw.Height= 180;
  395.         Win = OpenWindow(&Nw);
  396.     }
  397.     if (Win == NULL)
  398.         return;
  399.  
  400.     }
  401.     rp = Win->RPort;
  402.  
  403.     xmin = Win->BorderLeft;
  404.     ymin = Win->BorderTop;
  405.     xmax = Win->Width  - Win->BorderRight  - 1;
  406.     ymax = Win->Height - Win->BorderBottom - 1;
  407.  
  408.     if (xmin < xmax && ymin < ymax) {
  409.     SetAPen(rp, 0);
  410.     RectFill(rp, xmin, ymin, xmax, ymax);
  411.     }
  412.  
  413.     x = xmin + 2;
  414.     y = ymin + 4;
  415.     lenmax = (xmax-xmin+1)/GfxBase->DefaultFont->tf_XSize;
  416.  
  417.     SetAPen(rp, 1);
  418.     SetBPen(rp, 0);
  419.  
  420.     for (onf = (ONode *)FilList.lh_Head; onf->on_Succ; onf = (ONode *)onf->on_Succ) {
  421.  
  422.     if (onf->on_List.lh_Head->ln_Succ == 0)     /* 1.1 */
  423.        continue;                    /* 1.1 */
  424.  
  425.     /*
  426.      *  display 'To filename', then messages for this file
  427.      */
  428.  
  429.     {
  430.         if (y + GfxBase->DefaultFont->tf_YSize > ymax)
  431.         break;
  432.         sprintf(Buf, "To %s", onf->on_Name);
  433.         len = strlen(Buf);
  434.         if (len > lenmax)
  435.         len = lenmax;
  436.         Move(rp, x, y + GfxBase->DefaultFont->tf_Baseline);
  437.         SetDrMd(rp, COMPLEMENT);
  438.         Text (rp, (UBYTE *) Buf, len);
  439.         SetDrMd(rp, JAM2);
  440.         y += GfxBase->DefaultFont->tf_YSize;
  441.     }
  442.     for (node = onf->on_List.lh_Head; node->ln_Succ; node = node->ln_Succ) {
  443.         if (y + GfxBase->DefaultFont->tf_YSize > ymax)
  444.         break;
  445.         len = strlen(node->ln_Name);
  446.         if (len > lenmax)
  447.         len = lenmax;
  448.         Move (rp, x, y + GfxBase->DefaultFont->tf_Baseline);
  449.         Text (rp, (UBYTE *) node->ln_Name, len);
  450.         y += GfxBase->DefaultFont->tf_YSize;
  451.     }
  452.     }
  453.     sprintf(Title, "AnyMail Version 1.1    You have %d message%s waiting.",
  454.     Count,
  455.     (Count==1) ? "" : "s"
  456.     );
  457.     SetWindowTitles (Win, (UBYTE *) Title, 0);
  458. }
  459.  
  460. void
  461. Terminate(void)
  462. {
  463.     if (Win) {
  464.     SaveConfig(Win);
  465.     CloseWindow(Win);
  466.     Win = NULL;
  467.     }
  468.  
  469.     if (GfxBase) {
  470.     CloseLibrary ((struct Library *) GfxBase);
  471.     GfxBase = NULL;
  472.     }
  473.  
  474.     if (IntuitionBase) {
  475.     CloseLibrary ((struct Library *) IntuitionBase);
  476.     IntuitionBase = NULL;
  477.     }
  478.  
  479.     if (MailLock) {
  480.     UnLock(MailLock);
  481.     MailLock = 0;
  482.     }
  483.  
  484.     /*
  485.      *    delete sigport before removing file
  486.      */
  487.  
  488.     if (SigPort) {
  489.     DeletePort(SigPort);
  490.     SigPort = NULL;
  491.     }
  492.  
  493.     UnLockFiles();
  494.  
  495.     if (OwnDevUnitBase) {
  496.     CloseLibrary(OwnDevUnitBase);
  497.     OwnDevUnitBase = NULL;
  498.     }
  499.  
  500.     if (MailRdyName)
  501.     remove(MailRdyName);
  502. }
  503.  
  504. /*
  505.  * The real name is between parens.  If it can't be found, use the
  506.  * whole from line
  507.  */
  508.  
  509. char *
  510. FromName (char *fromLine)
  511. {
  512.     char *start;
  513.     char *end;
  514.  
  515.     start = strchr(fromLine, '(');
  516.     if (start) {
  517.     start++;
  518.     end = strchr(start, ')');
  519.     if (end) {
  520.         *end = 0;
  521.         return(start);
  522.     }
  523.     }
  524.     end = strchr(fromLine, '\n');
  525.     if (end)
  526.     *end = 0;
  527.     return(fromLine);
  528. }
  529.  
  530. void
  531. MakeNode (List *list, char *name)
  532. {
  533.     Node *node;
  534.  
  535.     if (node = malloc(sizeof(Node) + strlen(name) + 1)) {
  536.     node->ln_Name = (char *)(node + 1);
  537.     strcpy(node->ln_Name, name);
  538.     }
  539.     AddTail(list, node);
  540. }
  541.  
  542. ONode *
  543. GetONode (char *name)
  544. {
  545.     ONode *onf;
  546.  
  547.     for (onf = (ONode *) FilList.lh_Head; onf->on_Succ; onf = (ONode *)onf->on_Succ) {
  548.     if (stricmp(name, onf->on_Name) == 0)
  549.         break;
  550.     }
  551.     if (onf->on_Succ == NULL) {
  552.     onf = malloc (sizeof (ONode) + strlen (name) + 1);
  553.     setmem (onf, sizeof (ONode), 0);
  554.     onf->on_Name = (char *) (onf + 1);
  555.     strcpy (onf->on_Name, name);
  556.     NewList (&onf->on_List);
  557.     AddTail (&FilList, (struct Node *) onf);
  558.     }
  559.     return onf;
  560. }
  561.  
  562. int CfgLE;
  563. int CfgTE;
  564. int CfgW;
  565. int CfgH;
  566.  
  567. void
  568. LoadConfig (struct NewWindow *nw)
  569. {
  570.     FILE *fi;
  571.     if (fi = fopen("S:AnyMail.config", "r")) {
  572.     fscanf(fi, "%d %d %d %d", &CfgLE, &CfgTE, &CfgW, &CfgH);
  573.     nw->LeftEdge = CfgLE;
  574.     nw->TopEdge  = CfgTE;
  575.     nw->Width    = CfgW;
  576.     nw->Height   = CfgH;
  577.     fclose(fi);
  578.     }
  579. }
  580.  
  581. void
  582. SaveConfig (Window *win)
  583. {
  584.     FILE *fi;
  585.  
  586.     if (CfgLE != win->LeftEdge || CfgTE != win->TopEdge || CfgW != win->Width || CfgH != win->Height) {
  587.     if (fi = fopen("S:AnyMail.config", "w")) {
  588.         fprintf(fi, "%d %d %d %d\n", win->LeftEdge, win->TopEdge, win->Width, win->Height);
  589.         fclose(fi);
  590.     }
  591.     }
  592. }
  593.  
  594. /*
  595.  * Match the pattern, p, against the start of the string, s.
  596.  * Return TRUE if there is a match, FALSE if not.  If there is a match, set
  597.  * cnt to the number of characters matched.
  598.  *
  599.  *    ?  Matches any character
  600.  *    #p Maches zero or more ps, where p is a pattern not starting with #.
  601.  */
  602. int
  603. amatch(
  604.     char *s,       /* The string to match       */
  605.     char *p,       /* The pattern to match against */
  606.     int  *cnt
  607. )
  608. {
  609.     char *bas = s;
  610.     char buff[2];
  611.     int cnt1, cnt2;
  612.  
  613.     while(*p) {
  614.     switch(*p) {
  615.     default:
  616.         /* 1.1 uses LOWERCHAR() */
  617.         if (LOWERCHAR(*s) == LOWERCHAR(*p)) ++s, ++p;
  618.         else return FALSE;
  619.         break;
  620.     case '?':
  621.         if (*s) ++s, ++p;
  622.         else return FALSE;
  623.         break;
  624.     case '#':
  625.         if (p[1] == 0) return FALSE; /* Syntax error */
  626.  
  627.         buff[0] = p[1]; buff[1] = '\0';
  628.         if (amatch(s, buff, &cnt1) && amatch(s+cnt1, p, &cnt2)) {
  629.         *cnt = s-bas + cnt1 + cnt2;
  630.         return TRUE;
  631.         } else
  632.         p += 2;
  633.         break;
  634.     }
  635.     }
  636.  
  637.     *cnt = s-bas;
  638.  
  639.     return TRUE;
  640. }
  641.  
  642. #ifndef __SASC
  643.  
  644. char *
  645. strlwr(s)
  646. char *s;
  647. {
  648.     char *b;
  649.  
  650.     for (b = s; *b; ++b) {
  651.     if (*b >= 'A' && *b <= 'Z')
  652.         *b |= 0x20;
  653.     }
  654.     return(s);
  655. }
  656. #endif
  657.