home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / gigop806.zip / LISTSERV.CPP < prev    next >
C/C++ Source or Header  |  1994-04-25  |  15KB  |  480 lines

  1. /*
  2.  *  LISTSERV
  3.  *
  4.  *  Sample program that takes a GIGO function request file (FUNCTION.REQ),
  5.  *  checks it, and then modifies the appropriate .ML files (for mailing lists).
  6.  *
  7.  *  Jason Fesler  December, 1990    jfesler@wmeonlin.sacbbx.com
  8.  */
  9.  
  10. /*
  11.  *
  12.  * Modification by:
  13.  *  David Gibbs (gibbs@midrange.com)  April 25, 1994
  14.  *  Added basic activity logging
  15.  *
  16.  */
  17.  
  18. /*  For simplicity sake, I include everything, so that I don't have
  19.  *  any problems with the compiler knowing what I am talking about.
  20.  */
  21. #include <io.h>
  22. #include <fcntl.h>
  23. #include <sys\stat.h>
  24. #include <process.h>
  25. #include <share.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <malloc.h>
  30. #include <conio.h>
  31. #include <ctype.h>
  32. #include <direct.h>
  33. #include <dos.h>
  34. #include <dirent.h>
  35. #include <stdarg.h>
  36.  
  37.  
  38. /*
  39.  * Global variables are usually a bad programming practice.
  40.  * However, I don't give a damn.. :-)
  41.  *
  42.  */
  43.  
  44. extern unsigned int _stklen = 10000;    // Borland style stack declaration,
  45.  // ymmv
  46.  
  47. struct headers {
  48.     char            Apparently_To[256];
  49.     char            Apparently_From[256];
  50.     char            To[256];
  51.     char            From[256];
  52.     char            Subject[256];
  53. }               header;
  54.  
  55. FILE           *infile,
  56.                *outfile,
  57.                *file;
  58. int             amihere = 0;
  59. int             amiheremsg = 1;
  60.  
  61.  
  62.  
  63. /*
  64.  * cmpcopy looks to see if string at <source> compares to
  65.  * the string at <token>.  If it does, the parameters after
  66.  * <token> are going to be copied to <dest>.
  67.  */
  68.  
  69.  
  70. void            cmpcopy(char *token, char *source, char *dest)
  71. {
  72.     if (!strncmp(source, token, strlen(token))) {
  73.         source += strlen(token);// get past the token itself
  74.         while (*source == ' ')
  75.             source++;           // get past the spaces
  76.         strcpy(dest, source);
  77.     }
  78. }
  79. /*
  80.  * readheaders reads in the top part of the file until it reaches
  81.  * a newline character.
  82.  *
  83.  */
  84.  
  85.  
  86. void            readheaders(void)
  87. {
  88.     char            line[1024] = " ";
  89.     memset(&header, 0, sizeof(headers));
  90.     while ((*line) && (!feof(infile))) {
  91.  
  92.         /* remember, GIGO stands for garbage in, garbage out. */
  93.         memset(line, 0, sizeof(line));
  94.         fgets(line, sizeof(line) - 1, infile);
  95.  
  96.         /* fgets includes the line terminator; we need to remove it. */
  97.         if (*line)
  98.             if (line[strlen(line) - 1] == '\n')
  99.                 line[strlen(line) - 1] = 0;
  100.         if (*line)
  101.             if (line[strlen(line) - 1] == '\r')
  102.                 line[strlen(line) - 1] = 0;
  103.         if (!*line)
  104.             continue;           /* We got a blank line, or an eof */
  105.     cmpcopy("Apparently-To:", line, header.Apparently_To);
  106.         cmpcopy("Apparently-From:", line, header.Apparently_From);
  107.         cmpcopy("To:", line, header.To);
  108.     cmpcopy("From:", line, header.From);
  109.         cmpcopy("Subject:", line, header.Subject);
  110.     }
  111. }
  112.  
  113.  
  114. void            show_internal_help()
  115. {
  116.     fprintf(outfile,
  117.             "Simple help instructions for the GIGO listserv processor..\n"
  118.             "----------------------------------------------------------\n"
  119.             "HELP (or ?)           This help information\n"
  120.             "INDEX                 Shows the list of available lists\n"
  121.             "FAQ listname          Shows the FAQ (info) file for listname\n"
  122.             "SUBSCRIBE listname    Subscribes to listname\n"
  123.             "UNSUBSCRIBE listname  Unsubscribes to listname\n"
  124.      "QUERY                 Query the various lists to see which you are on\n"
  125.         "\n"
  126.             "DISCONNECT            Disconnects from ALL lists on this server\n"
  127.             "\n"
  128.         "Commands may be abbreviated down to a single character.\n"
  129.             "\n"
  130.     );
  131. }
  132. /* show_file dumps the file to the reply.  If it does not exist, returns a 1. */
  133.  
  134. int             show_file(char *filename)
  135. {                               // 1=error, 0=noerror
  136.     FILE           *hfile;
  137.     int             c;
  138.     hfile = fopen(filename, "rt");
  139.     if (!hfile)
  140.         return 1;
  141.     while (!feof(hfile)) {
  142.         c = fgetc(hfile);
  143.         fputc(c, outfile);
  144.     }
  145.     fclose(file);
  146.     return 0;
  147. }
  148. /* Shows the faq file for filename  (filename.FAQ).  If it does not
  149.    exist, it will print a message to that effect. */
  150.  
  151. void            show_faq(char *filename)
  152. {
  153.     char            buf[256];
  154.     sprintf(buf, "%s.faq", filename);
  155.     if (show_file(buf))
  156.         fprintf(outfile, "Sorry, no FAQ file for %s.\n", filename);
  157. }
  158. /* Attempts to dump LISTSERV.HLP to the reply; if that doesn't work,
  159.    then shows the internal help file instead. */
  160.  
  161. void            process_help(void)
  162. {
  163.     if (show_file("LISTSERV.HLP"))
  164.         show_internal_help();
  165. }
  166.  
  167.  
  168. /* Subscribes to filename.ML... (routine should only specify the 8 character
  169.    name, and not the extension).  If UNSUB==1, then the user is
  170.    unsubscribing instead.  We get to reuse most of the code this way. */
  171.  
  172. void            subscribe(char *filename, int unsub)
  173. {
  174.     char            buf[256];
  175.     char            line[512];
  176.     FILE           *oldfile,
  177.                    *newfile;
  178.     int             found = 0;
  179.     errno = 0;
  180.     unlink("LISTSERV.$$$");
  181.     errno = 0;
  182.     sprintf(buf, "%s.ml", filename);
  183.     rename(buf, "LISTSERV.$$$");
  184.     errno = 0;
  185.     oldfile = fopen("LISTSERV.$$$", "rt");
  186.     if (!oldfile) {
  187.         fprintf(outfile, "Could not access mailing list \"%s\".\n", filename);
  188.         return;
  189.     }
  190.     newfile = fopen(buf, "wt");
  191.     if (!newfile) {
  192.         fprintf(outfile, "Could not access mailing list \"%s\".\n", filename);
  193.         return;
  194.     }
  195.     if (!unsub)
  196.         fprintf(newfile, "%s\n", header.Apparently_From);
  197.  
  198.     while (!feof(oldfile)) {
  199.         memset(line, 0, sizeof(line));
  200.         fgets(line, sizeof(line), oldfile);
  201.         if (line[0])
  202.             if (line[strlen(line) - 1] == '\n')
  203.                 line[strlen(line) - 1] = 0;
  204.         if (line[0])
  205.         if (line[strlen(line) - 1] == '\r')
  206.                 line[strlen(line) - 1] = 0;
  207.         if (!line[0])
  208.             continue;
  209.         if (strcmp(header.Apparently_From, line) != NULL)
  210.             fprintf(newfile, "%s\n", line);
  211.         else
  212.             found = 1;
  213.     }
  214.     if (unsub) {
  215.         if (found)
  216.             fprintf(outfile, "List %s:  Unsubscribed.\n", filename);
  217.         else
  218.             fprintf(outfile, "List %s:  Already unsubscribed.\n", filename);
  219.     } else {
  220.         if (found)
  221.             fprintf(outfile, "List %s:  Already subscribed.\n", filename);
  222.         else
  223.             fprintf(outfile, "List %s:  Subscribed.\n", filename);
  224.         show_faq(filename);
  225.     }
  226.     fclose(oldfile);
  227.     fclose(newfile);
  228.     unlink("LISTSERV.$$$");
  229. }
  230.  
  231.  
  232. /* All of the answer_*() functions are used with the
  233.    check_multiple(function pointer) command.  check_multiple scans
  234.    the directory for all .ML files, and runs the routine specified
  235.    passing the parameter of the list name in question.
  236.  
  237.    */
  238.  
  239. /* answer_unsubscribe works with check_multiple to globally unsubscribe. */
  240.  
  241. void            answer_unsubscribe(char *filename)
  242. {
  243.     subscribe(filename, 1);
  244. }
  245. /* answer_amihere works with check_multiple to globally find out if
  246.    a person is in each list.  A message is displayed for each area that
  247.    the user is in; a global integer "amihere" is also updated. */
  248.  
  249. void            answer_amihere(char *filename)
  250. {
  251.     char            buf[256];
  252.     char            line[512];
  253.     sprintf(buf, "%s.ml", filename);
  254.     file = fopen(buf, "rt");
  255.     if (!file)
  256.         return;
  257.     while (!feof(file)) {
  258.         memset(line, 0, sizeof(line));
  259.         fgets(line, sizeof(line), file);
  260.         if (line[0])
  261.             if (line[strlen(line) - 1] == '\n')
  262.                 line[strlen(line) - 1] = 0;
  263.         if (line[0])
  264.         if (line[strlen(line) - 1] == '\r')
  265.         line[strlen(line) - 1] = 0;
  266.         if (!line[0])
  267.             continue;
  268.         if (strcmp(header.Apparently_From, line) == NULL) {
  269.             if (amiheremsg)
  270.         fprintf(outfile, "You are in the %s list.\n", filename);
  271.             amihere++;
  272.             break;
  273.         }
  274.     }
  275.     fclose(file);
  276. }
  277. /* answer_index works with check_multiple to tell the user what
  278.    mailing lists there are.  This is only used if the file
  279.    LISTSERV.IDX is not available (hence the manual check). */
  280.  
  281. void            answer_index(char *name)
  282. {
  283.     fprintf(outfile, "  %s\n", name);
  284. }
  285. /* check_multiple is a special function..
  286.  
  287.    It takes as it's parameter the address to another function(char*).
  288.  
  289.    All answer_*(char*) functions use this procedure.
  290.  
  291.    check_multiple will run that function once for every mailing list
  292.    in the current directory.  It has multiple uses; it can make
  293.    an index of the lists, globally desubscribe, and check to see which
  294.    lists a user is in.  This method of handling it means that I don't
  295.    have to have 3-4 (maybe more in the future) copies of the
  296.    directory-reading code.
  297.  
  298.  */
  299.  
  300. void            check_multiple(void func(char *))
  301. {
  302.     DIR            *dir;
  303.     struct dirent  *ent;
  304.     char            buf[256];
  305.     errno = 0;
  306.     if ((dir = opendir("")) == NULL) {
  307.     fprintf(stdout, "Unable to open directory\n");
  308.         return;
  309.     }
  310.     while ((ent = readdir(dir)) != NULL) {
  311.         strcpy(buf, ent->d_name);
  312.         if (strstr(buf, ".ML")) {
  313.             if (strchr(buf, '.'))
  314.                 *strchr(buf, '.') = 0;
  315.         func(buf);
  316.         }
  317.     }
  318. }
  319.  
  320. void            process_query(void)
  321. {
  322.     amiheremsg = 1;
  323.     amihere = 0;
  324.     fprintf(outfile, "Checking to see which mailing lists you are in...\n");
  325.     check_multiple(answer_amihere);
  326.     if (amihere)
  327.     fprintf(outfile, "-----\n"
  328.                 "Total of %u lists.\n\n", amihere);
  329.     else
  330.     fprintf(outfile, "You are in no lists with your present email address.\n");
  331. }
  332. void            process_index(void)
  333. {
  334.     if (!show_file("LISTSERV.IDX"))
  335.     return;                 // we had an ascii one handy
  336.  
  337.     fprintf(outfile, "Checking to see which mailing lists are available...\n");
  338.     check_multiple(answer_index);
  339.     fprintf(outfile, "End of lists.\n");
  340. }
  341.  
  342. void            processline(char *cmd, char *parm)
  343. {
  344.     char            buf[256];
  345.     struct date d;
  346.     struct time t;
  347.     FILE *logfile;
  348.     logfile = fopen("LISTSERV.LOG", "at");
  349.  
  350.     getdate(&d);
  351.     gettime(&t);
  352.     fprintf(logfile,"%2d-%02d-%02d %2d:%02d:%02d  Userid: %s, command: %s %s\n",
  353.         d.da_mon,d.da_day,d.da_year/100,
  354.         t.ti_hour,t.ti_min,t.ti_sec,
  355.         header.Apparently_From,cmd,parm);
  356.     fclose(logfile);
  357.     strupr(cmd);
  358.     strupr(parm);
  359.     switch (cmd[0]) {
  360.       case '?':
  361.       case 'H':
  362.     process_help();
  363.     break;
  364.       case 'I':
  365.     process_index();
  366.     break;
  367.       case 'F':
  368.         show_faq(parm);
  369.         break;
  370.       case 'S':
  371.     subscribe(parm, 0);
  372.         break;
  373.       case 'U':
  374.         subscribe(parm, 1);
  375.     break;
  376.       case 'Q':
  377.         process_query();
  378.         break;
  379.       case 'D':
  380.     fprintf(outfile, "Disconnecting you from all lists.\n");
  381.         check_multiple(answer_unsubscribe);
  382.         break;
  383.       case '-':
  384.         fprintf(outfile, "Signature or tearline detected, end of process.\n");
  385.         return;
  386.       default:
  387.     fprintf(outfile, "I don't recognize that command.  HELP will give you more information.\n");
  388.     }
  389. }
  390.  
  391. void            processlines(void)
  392. {
  393.     char            line[256];
  394.     char           *cmd;
  395.     char           *parm;
  396.     char           *genpurpose;
  397.     while (!feof(infile)) {
  398.         memset(line, 0, sizeof(line));
  399.         fgets(line, sizeof(line), infile);
  400.     if (line[0])
  401.             if (line[strlen(line) - 1] == '\n')
  402.                 line[strlen(line) - 1] = 0;
  403.         if (line[0])
  404.             if (line[strlen(line) - 1] == '\r')
  405.                 line[strlen(line) - 1] = 0;
  406.         if (!line[0])
  407.             continue;
  408.         fprintf(outfile, "\n>%s\n", line);
  409.         printf(">%s\n", line);
  410.         cmd = strtok(line, " \x09");
  411.     parm = strtok(NULL, " \x09");
  412.         if (!cmd)
  413.             cmd = "";
  414.         if (!parm)
  415.         parm = "";
  416.     while (genpurpose = strpbrk(parm, ":/\\"))
  417.             parm = genpurpose + 1;
  418.         while (genpurpose = strpbrk(parm, "?*"))
  419.             *genpurpose = '_';
  420.     if (genpurpose = strchr(parm, '.'))
  421.             *genpurpose = 0;    // truncate
  422.         processline(cmd, parm);
  423.     }
  424. }
  425.  
  426. void            needhelp(char *errmsg)
  427. {
  428.     fprintf(stderr, "Error! %s\n", errmsg);
  429.     fprintf(stderr, "LISTSERV is meant to be run as a function request under GIGO.\n"
  430.             "Please see the LISTSERV documentation for proper usage.\n\n\n(Pausing 2 seconds)\n");
  431.  
  432.     delay(2000);
  433.     exit(1);
  434. }
  435.  
  436. void            main(void)
  437. {
  438.     int             i;
  439.     fprintf(stderr, "LISTSERV processor for GIGO compile " __DATE__ ".\n");
  440.  
  441.     infile = fopen("FUNCTION.REQ", "rt");
  442.     if (!infile)
  443.         needhelp("FUNCTION.REQ not available for input.");
  444.     outfile = fopen("FUNCTION.REP", "wt");
  445.     if (!outfile)
  446.         needhelp("FUNCTION.REP not available for output.");
  447.     readheaders();
  448.  
  449.     if (header.Apparently_From[0] == 0)
  450.         needhelp("Apparently-From: line missing from FUNCTION.REQ file");
  451.     printf("Function request for: %s\n", header.Apparently_From);
  452.  
  453.     if (show_file("LISTSERV.TXT"))
  454.     fprintf(outfile,
  455.         "Thank you for using GIGO's listserv processor. Your commands are being quoted\n"
  456.         "below, followed by the processor's responses.  For this process, we are using\n"
  457.                 "your email address of \"%s\".\n\n", header.Apparently_From);
  458.     else
  459.         fprintf(outfile, "\nFor this process, we are using\n"
  460.         "your email address of \"%s\".\n\n", header.Apparently_From);
  461.  
  462.  
  463.     // if there are command line parameters..
  464.     if (_argc > 2) {
  465.         if (toupper(_argv[1][0]) == 'S') {
  466.             for (i = 2; i < _argc; i++)
  467.                 processline("S", _argv[i]);
  468.         } else if (toupper(_argv[1][0]) == 'U') {
  469.             for (i = 2; i < _argc; i++)
  470.                 processline("U", _argv[i]);
  471.         } else
  472.             needhelp("Invalid command line option (rtfm).");
  473.     } else if (_argc == 2)
  474.         needhelp("Not enough parameters or invalid command line option.");
  475.     else
  476.         processlines();
  477.     fclose(infile);
  478.     fclose(outfile);
  479. }
  480.