home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / mail / qwkrep.zip / QWK.C < prev    next >
C/C++ Source or Header  |  1992-09-17  |  16KB  |  741 lines

  1. /*
  2.  * qwk.c - main module for qwk
  3.  */
  4.  
  5. #include    <stdio.h>
  6. #include    <time.h>
  7. #include    <malloc.h>
  8. #include    <clib.h>
  9.  
  10. FILE *cfp;
  11. FILE *mfp;
  12. FILE *ifp;
  13. struct tm *tmp;
  14. int num;
  15. char **args;
  16.  
  17. char buff[1024];
  18. char *lines[100];
  19. int numline;
  20.  
  21. char subject[26];
  22. char from[26];
  23. char to[26];
  24. char confname[11];
  25. char m_date[9];
  26. char m_time[6];
  27. char bbsname[9];
  28. char bbstitle[40];
  29. char bbsuser[25];
  30. int msgnum;
  31. int type;
  32.  
  33. char o_date[11];
  34. char o_time[6];
  35.  
  36. int lmsgnum;
  37.  
  38. #pragma pack(1)
  39.  
  40. /*
  41.  * QWK packet message header
  42.  */
  43. struct _header_
  44.  {
  45.     char _status;
  46.     char _msgnum[7];
  47.     char _date[8];
  48.     char _time[5];
  49.     char _to[25];
  50.     char _from[25];
  51.     char _subject[25];
  52.     char _passwd[12];
  53.     char _refer[8];
  54.     char _size[6];
  55.     char _alive;
  56.     int _conf;
  57.     char _filler[3];
  58.  } header;
  59.  
  60. /*
  61.  * storage for 100 index entries
  62.  */
  63. struct _index_
  64.  {
  65.     struct _index_ *_next;
  66.     char _data[500];
  67.     int _count;
  68.  } *personal = (struct _index_ *) NULL;
  69.  
  70. /*
  71.  * linked list chain of conference structures
  72.  */
  73. struct _conf_
  74.  {
  75.     struct _conf_ *_next;
  76.     char _name[11];
  77.     struct _index_ *_indices;
  78.  } *confs = (struct _conf_ *) NULL;
  79.  
  80. int numconf;
  81.  
  82. /*
  83.  * 128 byte "Sparkyheader"
  84.  */
  85. char *msghdr =
  86. "Produced by Qmail...Copyright (c) 1987 by Sparkware.  All Rights Reserved\
  87.        Above for Compatibility with Qmail              ";
  88.  
  89. long msgpos;
  90. int msgsize;
  91. int thispos;
  92. int inmsg;
  93.  
  94. /*
  95.  * needed to do msbin <--> ieee fp format conversion
  96.  */
  97. union converter
  98.  {
  99.     unsigned char _uc[10];
  100.     unsigned int _ui[5];
  101.     unsigned long _ul[2];
  102.     float _f[2];
  103.     double _d[1];
  104.  };
  105.  
  106. /*
  107.  * known splitter modules
  108.  */
  109. extern int geni_split(char *, int);
  110. extern int mail_split(char *, int);
  111.  
  112. /*
  113.  * placed in an array of function pointers
  114.  */
  115. int (* split_funcs[])(char *, int) =
  116.  {
  117.     geni_split,
  118.     mail_split,
  119.  };
  120.  
  121. /*
  122.  * now, how many of them were there?
  123.  */
  124. #define NUM_SPLIT (sizeof(split_funcs) / sizeof(split_funcs[0]))
  125.  
  126. /*
  127.  * fp conversion routine
  128.  */
  129. float ieeetomsbin(f)
  130. float f;
  131.  {
  132.     union converter t;
  133.     int sign, exp;
  134.  
  135.     t._f[0] = f;
  136.     sign = t._uc[3] / 0x80;
  137.     exp = ((t._ui[1] >> 7) - 0x7f + 0x81) & 0xff;
  138.     t._ui[1] = (t._ui[1] & 0x7f) | (sign << 7) | (exp << 8);
  139.     return(t._f[0]);
  140.  }
  141.  
  142. /*
  143.  * need a void type unlink for scnwld
  144.  */
  145. void delete(s)
  146. char *s;
  147.  {
  148.     unlink(s);
  149.  }
  150.  
  151. /*
  152.  * mkqwk does the work, but all it does is to call out to the split routines
  153.  * these in turn call back into code here when they find messages
  154.  */
  155. void mkqwk(s)
  156. char *s;
  157.  {
  158.     int i;
  159.  
  160.     if ((ifp = fopen(s, "r")) == (FILE *) NULL)
  161.      {
  162.         printf("Can't open %s\n", s);
  163.         return;
  164.      }
  165.     /*
  166.      * no-one's claimed it yet
  167.      */
  168.     type = -1;
  169.  
  170.     /*
  171.      * keep on getting lines
  172.      */
  173.     while (fgets(buff, 1022, ifp) != (char *) NULL)
  174.      {
  175.         strip(buff);
  176.         /*
  177.          * if it's unclaimed, pass it to everyone
  178.          */
  179.         if (type == -1)
  180.          {
  181.             for (i = 0; i < NUM_SPLIT; i++)
  182.               (* split_funcs[i])(buff, i);
  183.          }
  184.         else
  185.           /*
  186.            * otherwise just pass it to the owner
  187.            */
  188.           (* split_funcs[type])(buff, type);
  189.      }
  190.     fclose(ifp);
  191.     /*
  192.      * final cleanup
  193.      */
  194.     if (inmsg)
  195.       finish_msg();
  196.     reset();
  197.  }
  198.  
  199. main(n, a)
  200. char **a;
  201.  {
  202.     int x;
  203.     time_t now;
  204.  
  205.     /*
  206.      * get the current date and time
  207.      */
  208.     time(&now);
  209.     tmp = localtime(&now);
  210.  
  211.     if (n < 2)
  212.       usage();
  213.     /*
  214.      * try to make control.dat
  215.      */
  216.     if ((cfp = fopen("control.dat", "w")) == (FILE *) NULL)
  217.      {
  218.         printf("Can't create CONTROL.DAT\n");
  219.         exit(3);
  220.      }
  221.     /*
  222.      * and messages.dat
  223.      */
  224.     if ((mfp = fopen("messages.dat", "w+b")) == (FILE *) NULL)
  225.      {
  226.         fclose(cfp);
  227.         printf("Can't create MESSAGES.DAT\n");
  228.         exit(4);
  229.      }
  230.     /*
  231.      * current position is at start of file
  232.      */
  233.     msgpos = 0L;
  234.     /*
  235.      * write the "Sparkyheader"
  236.      */
  237.     msgwrt(msghdr, 128);
  238.     /*
  239.      * build current date and time as strings
  240.      */
  241.     sprintf(o_date, "%02d-%02d-%04d", tmp->tm_mon + 1, tmp->tm_mday,
  242.                                                         tmp->tm_year + 1900);
  243.     sprintf(o_time, "%02d:%02d", tmp->tm_hour, tmp->tm_min);
  244.  
  245.     numconf = numline = lmsgnum = msgsize = 0;
  246.     reset();
  247.  
  248.     ++a;
  249.     num = n - 2;
  250.     args = &a[1];
  251.  
  252.     /*
  253.      * XXX it occurs to me that using scnwld is not that bright an idea
  254.      * since we only ever make one QWK packet per run
  255.      */
  256.     if (scnwld(*a, mkqwk, 0) == 0)
  257.       printf("Warning: no text files matched\n");
  258.  
  259.     /*
  260.      * clean up: dump the control info into control.dat
  261.      */
  262.     dump_ctrl();
  263.     /*
  264.      * close the files
  265.      */
  266.     fclose(mfp);
  267.     fclose(cfp);
  268.     fclose(ifp);
  269.     /*
  270.      * figure the PKZIP command and execute it
  271.      */
  272.     sprintf(buff, "pkzip -a %s.qwk *.dat *.ndx", bbsname);
  273.     system(buff);
  274.     /*
  275.      * and toss the files we just put in the zip
  276.      */
  277.     scnwld("*.dat", delete, 0);
  278.     scnwld("*.ndx", delete, 0);
  279.     return(0);
  280.  }
  281.  
  282. usage()
  283.  {
  284.     printf("Usage: MKQWK textfiles .....\n");
  285.     exit(1);
  286.  }
  287.  
  288. /*
  289.  * make everything clean
  290.  */
  291. reset()
  292.  {
  293.     padcpy(subject, "", 25);
  294.     padcpy(from, "", 25);
  295.     padcpy(to, "", 25);
  296.     sprintf(m_date, "%02d-%02d-%02d", tmp->tm_mon + 1, tmp->tm_mday,
  297.                                                         tmp->tm_year % 100);
  298.     sprintf(m_time, "%02d:%02d", tmp->tm_hour, tmp->tm_min);
  299.     msgnum = -1;
  300.  }
  301.  
  302. /*
  303.  * external entry to dump a line
  304.  */
  305. writemsg(buff)
  306. char *buff;
  307.  {
  308.     /*
  309.      * add the line
  310.      */
  311.     addline(buff);
  312.     if (numline == 97)
  313.      {
  314.         /*
  315.          * split a message at 100 lines
  316.          */
  317.         addline(">>> Continued in next message");
  318.         finish_msg();
  319.         addline(">>> Continued from last message");
  320.      }
  321.  }
  322.  
  323. /*
  324.  * external entry to complete a message
  325.  */
  326. finish_msg()
  327.  {
  328.     int i;
  329.     int j;
  330.     int x;
  331.     int y;
  332.     struct _conf_ *work;
  333.     char ndx[10];
  334.  
  335.     /*
  336.      * not in a message any more
  337.      */
  338.     inmsg = 0;
  339.     /*
  340.      * add the conference name, and get back the conf number
  341.      */
  342.     j = addconf(confname);
  343.     /*
  344.      * sataus is unread
  345.      */
  346.     header._status = ' ';
  347.     /*
  348.      * update message number
  349.      */
  350.     lmsgnum++;
  351.     if (msgnum == -1)
  352.       msgnum = lmsgnum;
  353.     sprintf(header._msgnum, "%-7d", ++msgnum);
  354.     /*
  355.      * set up fields for header
  356.      */
  357.     upper(from);
  358.     upper(to);
  359.     m_date[2] = m_date[5] = '-';
  360.     m_time[2] = ':';
  361.     strcpy(header._date, m_date);
  362.     strcpy(header._time, m_time);
  363.     padcpy(header._to, to, 25);
  364.     padcpy(header._from, from, 25);
  365.     padcpy(header._subject, subject, 25);
  366.     padcpy(header._passwd, "", 12);
  367.     padcpy(header._refer, "", 8);
  368.     sprintf(header._size, "%-6d", x = (msgsize + 255) / 128);
  369.     header._alive = 0xe1;
  370.     header._conf = j;
  371.     padcpy(header._filler, "", 3);
  372.     /*
  373.      * and write it
  374.      */
  375.     msgwrt((char *) &header, 128);
  376.  
  377.     /*
  378.      * save current position
  379.      */
  380.     y = thispos + x;
  381.     /*
  382.      * output all the text, and release the buffers
  383.      */
  384.     for (i = 0; i < numline; i++)
  385.      {
  386.         msgwrt(lines[i], strlen(lines[i]));
  387.         free(lines[i]);
  388.         msgwrt("\xe3", 1);
  389.      }
  390.     /*
  391.      * pad with spaces to 128 byte boundary
  392.      */
  393.     while (msgpos & 127L)
  394.       msgwrt(" ", 1);
  395.     /*
  396.      * internal check - this better not ever happen!
  397.      */
  398.     if (msgpos / 128 != y)
  399.       printf("WARNING: possible corruption in created MESSAGES.DAT");
  400.     /*
  401.      * go find the conf again
  402.      */
  403.     for (i = 0, work = confs; work != (struct _conf_ *) NULL && i < j; i++)
  404.       work = work->_next;
  405.     if (work == (struct _conf_ *) NULL)
  406.       /*
  407.        * another internal error
  408.        */
  409.       printf("Internal error: conference list corrupt\n");
  410.     else
  411.      {
  412.         /*
  413.          * add the position to the current index
  414.          */
  415.         wrtndx(&work->_indices, thispos, j);
  416.         if (strcmp(bbsuser, to) == 0)
  417.           /*
  418.            * and to the personal index if it's for us
  419.            */
  420.           wrtndx(&personal, thispos, j);
  421.         /*
  422.          * save next message position
  423.          */
  424.         thispos = y;
  425.         /*
  426.          * and reset
  427.          */
  428.         numline = 0;
  429.         msgsize = 0;
  430.      }
  431.  }
  432.  
  433. /*
  434.  * external entry to start a new message
  435.  */
  436. newmsg()
  437.  {
  438.     /*
  439.      * save the sector number
  440.      */
  441.     thispos = msgpos / 128L;
  442.     /*
  443.      * upper case the bbs name and user
  444.      */
  445.     upper(bbsname);
  446.     upper(bbsuser);
  447.     /*
  448.      * flag we're in a message
  449.      */
  450.     inmsg = 1;
  451.  }
  452.  
  453. /*
  454.  * external entry for a splitter module to claim the text file
  455.  */
  456. mine(n)
  457.  {
  458.     type = n;
  459.  }
  460.  
  461. /*
  462.  * output the entire CONTROL.DAT file
  463.  */
  464. dump_ctrl()
  465.  {
  466.     struct _conf_ *work;
  467.     int i;
  468.     char cxdat[20];
  469.     FILE *cxfp;
  470.  
  471.     if (numconf == 0)
  472.      {
  473.         /*
  474.          * barf and exit if we didn't find anything
  475.          */
  476.         printf("No messages found\n");
  477.         exit(0);
  478.      }
  479.     /*
  480.      * output the BBS title and some fillers
  481.      */
  482.     fprintf(cfp, "%s\nx\ny\nz\n", bbstitle);
  483.     /*
  484.      * and the bbs name
  485.      */
  486.     fprintf(cfp, "00000,%s\n", bbsname);
  487.     /*
  488.      * date and time
  489.      */
  490.     fprintf(cfp, "%s,%s:00\n", o_date, o_time);
  491.     /*
  492.      * user name, and number of confs
  493.      */
  494.     fprintf(cfp, "%s\n\n0\n0\n%d\n", bbsuser, numconf - 1);
  495.     /*
  496.      * build the .INF file at the same time so that REP can do the
  497.      * reverse conversion from conference number to name
  498.      */
  499.     sprintf(cxdat, "%s.INF", bbsname);
  500.     if ((cxfp = fopen(cxdat, "w")) == (FILE *) NULL)
  501.       printf("Warning - couldn't create %s, REP processing may fail\n", cxdat);
  502.     /*
  503.      * now run down the conferences
  504.      */
  505.     for (i = 0, work = confs; work != (struct _conf_ *) NULL;
  506.                                                 work = work->_next, i++)
  507.      {
  508.         /*
  509.          * output name and number to CONTROL.DAT
  510.          */
  511.         fprintf(cfp, "%d\n%s\n", i, work->_name);
  512.         if (cxfp != (FILE *) NULL)
  513.           /*
  514.            * and name to .INF file
  515.            */
  516.           fprintf(cxfp, "%s\n", work->_name);
  517.         /*
  518.          * lastly dump index info to the appropriate index filename
  519.          */
  520.         sprintf(cxdat, "%03d.NDX", i);
  521.         dumpndx(cxdat, work->_indices);
  522.      }
  523.     /*
  524.      * and the personal index data
  525.      */
  526.     dumpndx("personal.ndx", personal);
  527.     if (cxfp != (FILE *) NULL)
  528.       fclose(cxfp);
  529.  }
  530.  
  531. /*
  532.  * write a buffer to MESSAGES.DAT
  533.  */
  534. msgwrt(buff, size)
  535. char *buff;
  536.  {
  537.     while (size--)
  538.      {
  539.         putc(*buff++, mfp);
  540.         msgpos++;
  541.      }
  542.  }
  543.  
  544. /*
  545.  * save a line of text for later writing to MESSAGES.DAT
  546.  */
  547. addline(bp)
  548. char *bp;
  549.  {
  550.     char *work;
  551.  
  552.     /*
  553.      * grab some memory
  554.      */
  555.     if ((work = malloc(strlen(bp) + 1)) == (char *) NULL)
  556.      {
  557.         printf("ERROR: out of memory");
  558.         exit(101);
  559.      }
  560.     /*
  561.      * save text in line array
  562.      */
  563.     lines[numline++] = work;
  564.     strcpy(work, bp);
  565.     msgsize += strlen(work) + 1;
  566.  }
  567.  
  568. /*
  569.  * write an entry to an index chain
  570.  */
  571. wrtndx(ndxp, pos, conf)
  572. struct _index_ **ndxp;
  573. /*
  574.  * double indirect pointer in case we have to add an entry
  575.  */
  576.  {
  577.     int i;
  578.     float x;
  579.     char *cp;
  580.     struct _index_ *ndx;
  581.     struct _ixentry_
  582.      {
  583.         float _pos;
  584.         char _iconf;
  585.      } ixentry;
  586.  
  587.     /*
  588.      * find the end of the chain
  589.      */
  590.     while ((ndx = *ndxp) != (struct _index_ *) NULL && ndx->_count == 100)
  591.       ndxp = &(ndx->_next);
  592.     if (ndx == (struct _index_ *) NULL)
  593.      {
  594.         /*
  595.          * no data in chain, or last entry is full
  596.          * so grab some memory
  597.          */
  598.         if ((ndx = (struct _index_ *) malloc(sizeof(struct _index_))) ==
  599.                                                     (struct _index_ *) NULL)
  600.          {
  601.             printf("ERROR: out of memory");
  602.             exit(101);
  603.          }
  604.         /*
  605.          * and make a new link
  606.          */
  607.         ndx->_next = (struct _index_ *) NULL;
  608.         ndx->_count = 0;
  609.         *ndxp = ndx;
  610.      }
  611.     /*
  612.      * convert to the dreaded msbin format
  613.      */
  614.     x = pos + 1;
  615.     x = ieeetomsbin(x);
  616.     /*
  617.      * drop the data into the index entry structure
  618.      */
  619.     ixentry._pos = x;
  620.     ixentry._iconf = conf;
  621.     cp = (char *) &ixentry;
  622.     /*
  623.      * and copy to the correct place in the index link list node
  624.      */
  625.     for (i = 0; i < 5; i++)
  626.       ndx->_data[ndx->_count * 5 + i] = *cp++;
  627.     ndx->_count++;
  628.  }
  629.  
  630. /*
  631.  * copy from src to dest, exactly len bytes, pad with spaces if needed
  632.  */
  633. padcpy(dest, src, len)
  634. char *dest, *src;
  635.  {
  636.     while (*src && len)
  637.      {
  638.         *dest++ = *src++;
  639.         len--;
  640.      }
  641.     while (len--)
  642.       *dest++ = ' ';
  643.  }
  644.  
  645. /*
  646.  * get the conference number for this conf, add it to chain if it doesn't
  647.  * already exist
  648.  */
  649. addconf(conf)
  650. char *conf;
  651.  {
  652.     int j;
  653.     struct _conf_ *work;
  654.     struct _conf_ **workp;
  655.  
  656.     work = confs;
  657.     workp = &confs;
  658.     /*
  659.      * look for the entry
  660.      */
  661.     for (j = 0; work != (struct _conf_ *) NULL; j++)
  662.      {
  663.         if (strcmp(work->_name, conf) == 0)
  664.           break;
  665.         workp = &work->_next;
  666.         work = work->_next;
  667.      }
  668.     /*
  669.      * didn't find it
  670.      */
  671.     if (work == (struct _conf_ *) NULL)
  672.      {
  673.         /*
  674.          * get some memory
  675.          */
  676.         if ((work = (struct _conf_ *) malloc(sizeof(struct _conf_))) ==
  677.                                                      (struct _conf_ *) NULL)
  678.          {
  679.             printf("ERROR: out of memory");
  680.             exit(102);
  681.          }
  682.         /*
  683.          * one more conf
  684.          */
  685.         numconf++;
  686.         /*
  687.          * save the name
  688.          */
  689.         strcpy(work->_name, conf);
  690.         /*
  691.          * drop it in the linked list
  692.          */
  693.         *workp = work;
  694.         work->_next = (struct _conf_ *) NULL;
  695.         /*
  696.          * no index entries yet
  697.          */
  698.         work->_indices = (struct _index_ *) NULL;
  699.      }
  700.     /*
  701.      * return it's number
  702.      */
  703.     return(j);
  704.  }
  705.  
  706. /*
  707.  * dump a chain of index structures to a file
  708.  */
  709. dumpndx(file, indices)
  710. char *file;
  711. struct _index_ *indices;
  712.  {
  713.     int i;
  714.     FILE *fp;
  715.  
  716.     /*
  717.      * only do it if there really is data
  718.      */
  719.     if (indices != (struct _index_ *) NULL)
  720.      {
  721.         /*
  722.          * open the file, and barf if we failed
  723.          */
  724.         if ((fp = fopen(file, "wb")) == (FILE *) NULL)
  725.           printf("Can't create %s, .QWK will probably be corrupt.\n", file);
  726.         else
  727.          {
  728.             /*
  729.              * run down the index chain, writing the data
  730.              */
  731.             while (indices != (struct _index_ *) NULL)
  732.              {
  733.                 for (i = 0; i < indices->_count * 5; i++)
  734.                   putc(indices->_data[i], fp);
  735.                 indices = indices->_next;
  736.              }
  737.             fclose(fp);
  738.          }
  739.      }
  740.  }
  741.