home *** CD-ROM | disk | FTP | other *** search
/ World of Ham Radio 1994 January / AMSOFT_1994.iso / packet / pbbs / cbbs / prog / mbmail.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-31  |  41.3 KB  |  1,857 lines

  1. /*
  2.  *  MBMAIL.C - 7/20/89 The message file stuff, except for forwarding.
  3.  */
  4.  
  5. #include "mb.h"
  6.  
  7. #define btmax 112   /* Max text in beacon line */
  8.  
  9. char  orgmsg[6], orgbbs[7], orgtime[5], orgdate[7];
  10.  
  11. char  *mbfile, *mbbfile, *msgdir, *bidfile, *stfile;
  12.  
  13. char  *ufwd;  /* Calls with unread msgs, for BT */
  14. char  *bfwd;  /* Calls with unread msgs, for forwarding */
  15.  
  16. short ufwdm, ufwdn, bfwdm, bfwdn;
  17. short tstaleb, tstalen, tstaleu;
  18. int bidok, hidok, hasbid, needbid, holdit;
  19.  
  20. char  *mm[num_mm];
  21. char  wpcall[ln_call];
  22. XBBS  *xbbs;
  23. HOLD  *hold;
  24.  
  25. MAIL_HDR  *mfhs;
  26. MSG_HDR   *tmmhs;
  27.  
  28. FILE *bfl;
  29.  
  30. int mfl, mflb;
  31.  
  32. msgfile(p, n)
  33. char *p;
  34. word n;
  35. {
  36.   sprintf(p, "%s%u", msgdir, n);
  37. }
  38.  
  39. /*
  40.  *  Open file to hold BIDs
  41.  */
  42.  
  43. opnbid()
  44. {
  45.   if ((bfl = fopen(bidfile, "a+")) is NULL) { nofile(bidfile); exit(1); }
  46.   fclose(bfl);
  47. }
  48.  
  49. /*
  50.  *  Write message header.
  51.  */
  52.  
  53. wt_mmhs()
  54. {
  55.   if (port->mmhs->rn) write_rec (mfl, port->mmhs->rn, (char *)port->mmhs);
  56. }
  57.  
  58.  
  59. /*
  60.  *  Get message title.
  61.  */
  62.  
  63. get_title()
  64. {
  65.   while(!getdat());
  66.   remnl(port->line);
  67.   strncpy(port->mmhs->title, port->line, mhtitl);
  68. }
  69.  
  70. /*
  71.  *  Parse the [@ bbs] and [< from] fields of a command.
  72.  */
  73.  
  74. atfrom(i)
  75. int i;
  76. {
  77.   if (*port->fld[i] is '<') pcall(port->mmhs->from, port->fld[i + 1]);
  78.   else if (*port->fld[i] is '@')
  79.   {
  80.     pcall(port->mmhs->bbs, port->fld[i +1]);
  81.     if ((strchr(port->fld[i + 1], '.')) is NULL)
  82.     { chkhier(); return; }
  83.     port->mmhs->ext = 2;
  84.     fill (port->mmhs->call, '\0', 125);
  85.     strncpy(port->mmhs->call[0], port->fld[i + 1], 64);
  86.   }
  87. }
  88.  
  89. /*
  90.  *  Parse the fields of a send command.
  91.  */
  92.  
  93. pfld()
  94. {
  95.   hasbid = false;
  96.  
  97.   port->mmhs->type = port->opt2;
  98.   pcall(port->mmhs->to, port->fld[1]);
  99.   strncpy(port->mmhs->from, port->user->call, ln_call);
  100.   fill(port->mmhs->bbs, ' ', ln_call);
  101.   fill(port->mmhs->bid, ' ', ln_bid);
  102.   port->mmhs->ext = 0;
  103.  
  104.   if (port->flds > 3) atfrom(port->flds - 2);
  105.   if (port->flds > 5) atfrom(port->flds - 4);
  106.  
  107.   if (port->flds > 2)
  108.   if(*port->fld[port->flds-1] is '$')
  109.   {
  110.     if (*(port->fld[port->flds - 1] + 1) isnt NULL)
  111.     {
  112.     strncpy(port->mmhs->bid, port->fld[port->flds - 1] + 1, ln_bid);
  113.     hasbid = true;
  114.     }
  115.     if (port->flds > 4) atfrom(port->flds - 3);
  116.     if (port->flds > 6) atfrom(port->flds - 5);
  117.   }
  118.  
  119.   initmsg(true);  
  120.   if(!bidok) {
  121.     if (port->user->options & (u_bbs | u_expert)) outstr("Sj:\n");
  122.     else prtx(mm[0]);
  123.     get_title();
  124.     return;
  125.   }
  126.   else {  
  127.     if (hasbid) {
  128.       checkbid();
  129.       if (!needbid) {
  130.         outstr("No - Already have it\n");
  131.         sprintf(port->mmhs->title, "<<%6.6s - %s>>",
  132.                   port->user->call, port->fld[port->flds-1]);
  133.         wt_mmhs();
  134.         return;
  135.       }
  136.       prtx("OK $C\n");
  137.       get_title();
  138.       return;
  139.     }
  140.     else {
  141.       prtx("OK $C\n");
  142.       get_title();
  143.       needbid = true;     /* will check and may assign one later */
  144.       return;
  145.     }
  146.   }
  147. }
  148.  
  149. /*
  150.  *  Create the header line.
  151.  */
  152.  
  153. makehdr()
  154. {
  155.   register char st,ef;
  156.  
  157.   st = 'N';
  158.   if (port->mmhs->stat & m_stale) st = 'O';
  159.   if (port->mmhs->stat & m_fwd)   st = 'F';
  160.   if (port->mode & ops) if (port->mmhs->stat & m_bull) st = '$';
  161.   if (port->mmhs->stat & m_read)  st = 'Y';
  162.   if (port->mmhs->stat & m_hold)  st = 'H';
  163.   if (port->mmhs->stat & m_kill)  st = 'K';
  164.   if (port->mmhs->stat & m_busy)  st = 'B';
  165.   if (port->mmhs->ext is 2) ef = '*'; else ef = ' ';
  166.   sprintf(tmp->scr,"%5u %c%c %5u %6.6s %6.6s %6.6s%c%3u %4.4s/%4.4s %s\n",
  167.     port->mmhs->number, port->mmhs->type, st, port->mmhs->size,
  168.     port->mmhs->to,port->mmhs->from,port->mmhs->bbs,ef,port->mmhs->read,
  169.     port->mmhs->date + 2, port->mmhs->time, port->mmhs->title);
  170. }
  171.  
  172. /*
  173.  * Write mail.dat header into text file
  174.  */
  175.  
  176. makehdr2()
  177. {
  178.   register char st, c;
  179.   int msfl;
  180.   char flags[mmesn];
  181.   fill (flags, ' ',mmesn);
  182.   fill (tmp->scr, '\0', 256);
  183.   tmp->scr[254] = '\r'; tmp->scr[255] = '\n';
  184.   if (port->mmhs->ext is 1)
  185.   {
  186.     for (c=0; c < port->mmhs->count; c++)
  187.     flags[c] = port->mmhs->flag[c] + '0';
  188.   }
  189.   st = 'N';
  190.   if (port->mmhs->stat & m_stale) st = 'O';
  191.   if (port->mmhs->stat & m_fwd)   st = 'F';
  192.   if (port->mmhs->stat & m_bull)  st = '$';
  193.   if (port->mmhs->stat & m_hold)  st = 'H';
  194.   if (port->mmhs->stat & m_read)  st = 'Y';
  195.   if (port->mmhs->stat & m_kill)  st = 'K';
  196.   sprintf(tmp->scr,
  197.            "%5u %c%c %5u %6.6s %6.6s %6.6s %6.6s %4.4s %-12.12s %5u\r\n",
  198.     port->mmhs->number, port->mmhs->type, st, port->mmhs->size,
  199.     port->mmhs->to, port->mmhs->from, port->mmhs->bbs,
  200.     port->mmhs->date, port->mmhs->time, port->mmhs->bid, port->mmhs->read);
  201.   if (port->mmhs->ext is 2)
  202.        sprintf(tmp->scr+68, "%c %s\r\n%s\r\n", port->mmhs->ext +'0',
  203.        port->mmhs->call, port->mmhs->title);
  204.   else sprintf(tmp->scr+68, "%c %16.16s\r\n%s\r\n", port->mmhs->ext +'0',
  205.        flags, port->mmhs->title);
  206.  
  207.   msgfile(port->cmd, port->mmhs->number);
  208.   if ((msfl = open(port->cmd, O_WRONLY | O_BINARY)) < 0) return;
  209.   write_rec(msfl, 0, (char *)tmp->scr);
  210.   close(msfl);
  211. }
  212.  
  213. /*
  214.  *  Print a message header.
  215.  */
  216.  
  217. prthdr(tit, max_title)
  218. int tit, max_title;
  219. {
  220.   char *a, *b;
  221.  
  222.   register short i;
  223.   register short docc;
  224.  
  225.   if (tit) prtx(mm[3]);
  226.   makehdr();
  227.   if ((!max_title) and (strlen(tmp->scr) > 79))
  228.   {
  229.     tmp->scr[79] = '\n';
  230.     tmp->scr[80] = '\0';
  231.   }
  232.   outstr(tmp->scr);
  233.   if (pgck() is 'Q') return('Q');
  234.   if((port->opt1 is'L')and((*port->fld[1]isnt';')and(*port->fld[2]isnt';')))
  235.      return;
  236.   if (port->mmhs->ext is 2)
  237.   {
  238.     outstr("    EF:");
  239.     outstr(port->mmhs->call);
  240.     outchar('\n');
  241.   }
  242.   if (port->mmhs->ext is 1) if (port->mode & ops)
  243.   {
  244.     docc = false;
  245.     for (i = 0; i < port->mmhs->count; i++) if (port->mmhs->flag[i])
  246.      docc = true;
  247.  
  248.     if (docc)
  249.     {
  250.       outstr("    cc:");
  251.       for (i = 0; i < port->mmhs->count; i++)
  252.       {
  253.         if (port->mmhs->flag[i]) outchar(' '); else outstr(" *");
  254.         outnb(port->mmhs->call[i], ln_call);
  255.       }
  256.       outchar('\n');
  257.     }
  258.   }
  259.   if (port->mode & ops) if (*port->mmhs->bid isnt ' ')
  260.     {
  261.     outstr("   BID: ");
  262.     a = port->line;
  263.     b = port->mmhs->bid;
  264.     unbl(a, b, ln_bid);
  265.     outstr(port->line);  outchar('\n');
  266.   }
  267. }
  268.  
  269. /*
  270.  *  Read the message, look for the last bbs header.
  271.  *  Set the @ field of the current message to the "at bbs" in that header.
  272.  */
  273.  
  274. findat()
  275. {
  276.   register short i;
  277.  
  278.   fill(port->mmhs->bbs, ' ', ln_call);
  279.   msgfile(port->line, port->mmhs->number);
  280.   if ((port->fl = fopen(port->line, "r")) is NULL) { nofile(port->line); return; }
  281.   fseek(port->fl, (long)RECSIZE, 0);
  282.   while(fgets(port->line, linelen, port->fl) isnt NULL)
  283.   {
  284.     if (!parsehd(port->line)) break;
  285.     pcall(port->mmhs->bbs, orgbbs);
  286.   }
  287.   fclose (port->fl);
  288.   chkhier();
  289. }
  290.  
  291. /*
  292.  *  Parse a message header line.
  293.  */
  294.  
  295. parsehd(in)
  296. char *in;
  297. {
  298.   register char *p;
  299.   register int count, n;
  300.  
  301.   if (!ishead(in)) return false;
  302.  
  303.   if ((p = strchr(in, 'R')) is NULL) return false;
  304.   {
  305.     p++;
  306.  
  307.     if (*p is ':') p++;
  308.     if (*p is ' ') p++;
  309.     count = 6;
  310.     n = 0;
  311.     while (*p and count--)
  312.     {
  313.       if (!isalnum(*p)) break;
  314.       orgdate[n++] = *p++;
  315.     }
  316.     orgdate[n] = '\0';
  317.  
  318.     if (*p is '/') p++;
  319.  
  320.     count = 4;
  321.     n = 0;
  322.     while (*p and count--)
  323.     {
  324.       if (!isalnum(*p)) break;
  325.       orgtime[n++] = *p++;
  326.     }
  327.     orgtime[n] = '\0';
  328.   }
  329.  
  330.   if ((p = strchr(in, '@')) is NULL) return false;
  331.   {
  332.     p++;
  333.  
  334. /* skip colon or a space in @:call  OR @ call */
  335.  
  336.     if (*p is ':') p++;
  337.     if (*p is ' ') p++;
  338.     count = ln_call;
  339.     n = 0;
  340.     while (*p and count--)
  341.     {
  342.       if (!isalnum(*p)) break;
  343.       toupper(*p);
  344.       orgbbs[n++] = *p++;
  345.     }
  346.     orgbbs[n] = '\0';
  347.   }
  348.  
  349.   if ((p = strrchr(in, '#')) isnt NULL)
  350.   {
  351.     p++;
  352.  
  353.     if (*p is ':') p++;
  354.     if (*p is ' ') p++;
  355.     count = 5;
  356.     n = 0;
  357.     while (*p and count--)
  358.     {
  359.       if (!isalnum(*p)) break;
  360.       orgmsg[n++] = *p++;
  361.     }
  362.     orgmsg[n] = '\0';
  363.   }
  364.   else
  365.   {
  366.     p = strchr(in, '@');
  367.     p--; count = 5;
  368.     while(count-- and *p isnt ' ') p--;
  369.     p++;
  370.     if (*p is '<') p++;
  371.     count = 5;
  372.     n = 0;
  373.     while (*p and count--)
  374.     {
  375.       if (*p is '@') break;
  376.       orgmsg[n++] = *p++;
  377.     }
  378.     orgmsg[n] = '\0';
  379.   }
  380.   return true;
  381. }
  382.  
  383.  
  384. /*
  385.  *  Find a message given it's number.
  386.  */
  387.  
  388. findmsg(nr)
  389. word nr;
  390. {
  391.   register word i;
  392.  
  393.   for (i = mfhs->last; i; i--)
  394.   {
  395.     read_rec(mfl, i, (char *)port->mmhs);
  396.     if (port->mmhs->number is nr) return true;
  397.     if (port->mmhs->number < nr)  return false;
  398.   }
  399.   return false;
  400. }
  401.  
  402. /*
  403.  *  Create the distribution list, if required.
  404.  */
  405.  
  406. dodis()
  407. {
  408.   register FILE *dfl;
  409.   if (port->mmhs->ext is 2) return;
  410.   port->mmhs->ext = 0;
  411.   if (*port->mmhs->bbs is ' ') return;
  412.  
  413.   unbl(tmp->scr, port->mmhs->bbs, ln_call);
  414.  
  415.   strcpy(port->line, msgdir);
  416.   strcat(port->line, tmp->scr);
  417.   strcat(port->line, ".DIS");
  418.  
  419.   if ((dfl = fopen(port->line, "r")) is NULL) return;
  420.  
  421.   port->mmhs->ext = 1 ;
  422.  
  423.   for (port->mmhs->count = 0;
  424.     (port->mmhs->count < mmesn) and (fgets(tmp->scr, scrmax, dfl) isnt NULL);
  425.     port->mmhs->count++)
  426.   {
  427.     strupr(tmp->scr);
  428.     pcall(port->mmhs->call[port->mmhs->count], tmp->scr);
  429.     if(matchn(port->mmhs->call[port->mmhs->count], port->user->call, ln_call))
  430.          port->mmhs->flag[port->mmhs->count] = false;
  431.     else port->mmhs->flag[port->mmhs->count] = true;
  432.   }
  433.   if (port->mmhs->count is 1) if (!port->mmhs->flag[0])
  434.     port->mmhs->stat setbit m_bull;
  435.   fclose(dfl);
  436. }
  437.  
  438. /*
  439.  *  Do we hold this message?
  440.  */
  441.  
  442. ishold(c)
  443. char *c;
  444. {
  445.   register HOLD *hp;
  446.  
  447.   for (hp = hold; hp isnt NULL; hp = hp->next)
  448.   if (matchn(hp->call, c, ln_call)) return true;
  449.  
  450.   return false;
  451. }
  452.  
  453. /*
  454.  *  Create message utilities - initmsg and cremsg.
  455.  *  Used by "send message", "make message from file",
  456.  *  "kill msg" (service messages), "copy message".
  457.  */
  458.  
  459. initmsg(h)
  460. int h;
  461. {
  462.   if (s_flag & s_dv) begin_lock();
  463.   read_rec(mfl, 0, (char *)mfhs);
  464.  
  465.   port->mmhs->rn = mfhs->next++;
  466.   port->mmhs->number = mfhs->next_msg++;
  467.   port->mmhs->stat = m_busy;
  468.   strncpy(port->mmhs->date, l_date, ln_date);
  469.   strncpy(port->mmhs->time, l_time, ln_time);
  470.   port->mmhs->read = 0;
  471.   port->mmhs->size = 0;
  472.   if(port->mmhs->ext isnt 2) fill(port->mmhs->call, '\0', 125);
  473.   if(h)sprintf(port->mmhs->title, "<<%6.6s -- disconnected>>",port->user->call);
  474.  
  475.  
  476. /*
  477.  *  Clean up the file header.
  478.  */
  479.  
  480.   if (!mfhs->first) mfhs->first = port->mmhs->rn;
  481.   mfhs->last = port->mmhs->rn;
  482.   mfhs->count++;
  483.   write_rec(mfl, 0, (char *)mfhs);
  484.   wt_mmhs();
  485.   mfhs->next_msg--;
  486.   if (s_flag & s_dv) end_lock();
  487. }
  488.  
  489. cremsg()
  490. {
  491.   char *a, *b;
  492.  
  493.   register short i;
  494.   register XBBS *xp;
  495.   register FILE *out;
  496.  
  497.   port->mmhs->stat   = 0;
  498.   strncpy(port->mmhs->date, l_date, ln_date);
  499.   strncpy(port->mmhs->time, l_time, ln_time);
  500.   port->mmhs->read = 0;
  501.   port->mmhs->size = filesize;
  502.  
  503.   for (xp = xbbs; xp isnt NULL; xp = xp->next)
  504.   if (wcm(xp->from, port->mmhs->bbs))
  505.   {
  506.     strncpy(port->mmhs->bbs, xp->to, ln_call);
  507.     if (port->mmhs->ext is 2) port->mmhs->ext = 0;
  508.     break;
  509.   }
  510.  
  511.   if (ishold(port->mmhs->to))   port->mmhs->stat = m_hold;
  512.   if (ishold(port->mmhs->from)) port->mmhs->stat = m_hold;
  513.   if (ishold(port->mmhs->bbs))  port->mmhs->stat = m_hold;
  514.  
  515.   if (holdit) port->mmhs->stat = m_hold;
  516.  
  517.   if (*port->mmhs->bid isnt ' ') {
  518.     checkbid();
  519.     if (hasbid) if (!holdit) if (needbid) {
  520.       if ((out = fopen(bidfile,"a")) is NULL) {
  521.         port->msg = mcant; return;
  522.       }
  523.  
  524.       a = port->cmd;
  525.       b = port->mmhs->bid;
  526.       unbl(a, b, ln_bid);
  527.  
  528.       sprintf(port->line, "%4.4s%s\n", port->mmhs->date + 2, port->cmd);
  529.       if (s_flag & s_dv) begin_lock();
  530.       fputs(port->line, out);
  531.       if (s_flag & s_dv) end_lock();
  532.       fclose(out);
  533.     }
  534.   }
  535.   dodis();
  536.  
  537.   if ((port->mmhs->ext is 1) and (*port->mmhs->bid is ' '))
  538.   port->mmhs->stat = m_hold;
  539.  
  540.   wt_mmhs();
  541.   makehdr2();
  542.  
  543.   if (*port->fld[port->flds-1] isnt '$') port->fld[port->flds-1] = nullstr;
  544.  
  545.   sprintf(port->line, "%u %-.6s@%-.6s %s %s", port->mmhs->number,
  546.    port->mmhs->to, port->mmhs->bbs, port->fld[port->flds-1], port->mmhs->title);
  547.  
  548.   log('M', port->opt1, port->opt2, port->line);
  549.   mfhs->next_msg++;
  550. }
  551.  
  552. /*
  553.  *  Set up the beacon line.
  554.  */
  555.  
  556. setfwd()
  557. {
  558.   register char *cp, *lp;
  559.   register short i;
  560.  
  561.   bldfwd();
  562.   if (ufwdm > 1)
  563.   {
  564.     strcpy(port->line, "BT Mail for:");
  565.     cp = ufwd;
  566.     lp = port->line + strlen(port->line);
  567.     while ((cp < ufwd + ln_call * ufwdn) and (lp < port->line + btmax))
  568.     {
  569.       *lp++ = ' ';
  570.       for (i = 0; i < ln_call; i++, cp++) if (*cp isnt ' ') *lp++ = *cp;
  571.     }
  572.     *lp++ = '\n';
  573.     *lp = '\0';
  574.     alltnc(port->line);
  575.   }
  576. }
  577.  
  578. /*
  579.  *  General permission check: sysop or TO or FROM.
  580.  */
  581.  
  582. permit()
  583. {
  584.   if (port->mmhs->stat & (m_kill | m_busy)) return false;
  585.   if (matchn(port->user->call, port->mmhs->to,   ln_call)) return true;
  586.   if (matchn(port->user->call, port->mmhs->from, ln_call)) return true;
  587.   return false;
  588. }
  589.  
  590. /*
  591.  *  Return true if user has kill permission for current message.
  592.  */
  593.  
  594. kpermit()
  595. {
  596.   if (port->mmhs->stat & m_kill) return false;
  597.   if (port->mode & ops) return true;
  598.   if (permit()) return true;
  599.   return ((port->mmhs->type is 'T') and (port->opt2 is 'T'));
  600. }
  601.  
  602. /*
  603.  *  Return true if user has list permission for current message.
  604.  */
  605.  
  606. lpermit()
  607. {
  608.   if (port->user->options & u_sysop) return true;
  609.   if (permit()) return true;
  610.   return ((port->mmhs->type isnt 'P')
  611.       and !(port->mmhs->stat & (m_fwd | m_kill | m_busy)));
  612. }
  613.  
  614. /*
  615.  *  Return true if user has read permission for current message.
  616.  */
  617.  
  618. rpermit()
  619. {
  620.   if ( port->mode & ops) return true;
  621.   if (permit()) return true;
  622.   return (port->mmhs->type isnt 'P');
  623. }
  624.  
  625. /*
  626.  *  Clean the mail file.
  627.  *  Force drain of buffers, update of directory item.
  628.  */
  629.  
  630. clnmsg()
  631. {
  632.   close(mfl);
  633.   mfl = open(mbfile, O_RDWR | O_BINARY);
  634. }
  635.  
  636. /*
  637.  *  Close the mail file.
  638.  */
  639.  
  640. clsmsg()
  641. {
  642.   close (mfl);
  643. }
  644.  
  645. /*
  646.  *  Open the mail file.
  647.  */
  648.  
  649. opnmsg()
  650. {
  651.   register char *tp;
  652.  
  653. /*
  654.  *  Allocate space for the mail file records.
  655.  */
  656.  
  657.   mfhs  =  (MAIL_HDR *) malloc(sizeof(MAIL_HDR));
  658.   tmmhs =  (MSG_HDR *)  malloc(sizeof(MSG_HDR));
  659.  
  660. /*
  661.  *  Allocate the "who has mail" lists.
  662.  */
  663.  
  664.   ufwd = (char *) malloc (ln_call * ufwdm);
  665.   bfwd = (char *) malloc (ln_call * bfwdm);
  666.   if (bfwd is NULL) errall();
  667.  
  668. /*
  669.  *  Open the file. If it does not exist, make one.
  670.  */
  671.  
  672.   if ((mfl = open(mbfile, O_RDWR | O_BINARY)) < 0)
  673.   {
  674.     if ((mfl = open(mbfile, O_CREAT | O_RDWR | O_BINARY, pmode)) < 0)
  675.       { nofile(mbfile); exit(1); }
  676.     inithdr();
  677.     mfhs->next_msg = 1;
  678.     write_rec(mfl, 0, (char *)mfhs);
  679.   }
  680.  
  681. /*
  682.  *  Read the mail file header.
  683.  */
  684.  
  685.   read_rec(mfl, 0, (char *)mfhs);
  686.  
  687. /*
  688.  *  If wrong version mail file, quit now.
  689.  */
  690.  
  691.   if (mfhs->version isnt mb_version)
  692.   {
  693.     printf("Expected version %d, got version %d\n",
  694.       mb_version, mfhs->version);
  695.     nofile(mbfile);
  696.     exit(1);
  697.   }
  698.  
  699. }
  700.  
  701. /*
  702.  *  Initialize the mail file header.
  703.  */
  704.  
  705. inithdr()
  706. {
  707.   mfhs->next    = 1;
  708.   mfhs->first   = 0;
  709.   mfhs->last    = 0;
  710.   mfhs->version = mb_version;
  711.   mfhs->free    = 0;
  712.   mfhs->count   = 0;
  713.   mfhs->unt_msg = 1;
  714.  
  715.   curtim();
  716.   strncpy(mfhs->date, l_date, ln_date);
  717.   strncpy(mfhs->time, l_time, ln_time);
  718.   fill(mfhs->unu, '\0', mfhsunu);
  719. }
  720.  
  721. /*
  722.  *  Open mail file and read first record.
  723.  */
  724.  
  725. readmsg()
  726. {
  727.   mfl = open(mbfile, O_RDWR | O_BINARY);
  728.   read_rec(mfl, 0, (char *)mfhs);
  729. }
  730.  
  731. /*
  732.  *  Does this station want us to send BIDs ?
  733.  */
  734.  
  735. isbid()
  736. {
  737.   register char *f;
  738.  
  739. /*  Is this a sid? It must have a '-' and end with a ']'  */
  740.  
  741.   if ((port->line[strlen(port->line) - 2] isnt ']' ) or
  742.      ((f =  strrchr(port->line, '-')) is NULL))
  743.      return;
  744.  
  745. /*  Look for specal characters in the last field.  */
  746.  
  747.   f++;
  748.   for (; *f isnt ']';f++)
  749.   switch(*f)
  750.   {
  751.      case 'H' : hidok = true; break;
  752.      case '$' : if(*(f+1) is ']') bidok = true; break;
  753.   }
  754. }
  755.  
  756. /*
  757.  *  Check to see whether we already have this BID.
  758.  */
  759.  
  760. checkbid()
  761. {
  762.   FILE *out;
  763.   char *a, *b;
  764.  
  765.   if (*port->mmhs->bid is ' ') { needbid = true; return; }
  766.   if ((out = fopen(bidfile, "r")) is NULL) {
  767.     nofile(bidfile); return; 
  768.   }
  769.   while (fgets(port->line, linelen, out) isnt NULL) {
  770.  
  771.     /* the first 4 characters are the date */
  772.  
  773.     strcpy(port->cmd, port->line + 4);
  774.     a = port->cmd;
  775.     remnl(a);
  776.  
  777.     a = port->line;
  778.     b = port->mmhs->bid;
  779.     unbl(a, b, ln_bid);
  780.  
  781.     if (match(port->cmd, port->line)) {
  782.       needbid = false; 
  783.       fclose(out);
  784.       return;
  785.     }
  786.   }
  787.   needbid = true;
  788.   fclose(out);
  789. }
  790.  
  791. /****************************************
  792.  *                                      *
  793.  *  Code for the commands starts here   *
  794.  *                                      *
  795.  ****************************************/
  796.  
  797. /*
  798.  *  GM or GR command: backup the mail file.
  799.  */
  800.  
  801. untmsg()
  802. {
  803.   register word inhdr, me;
  804.   if (port->opt2 isnt 'A') { if (sure()) return; }
  805.   if (!mfhs->count) { port->msg = mm[5]; return; }
  806.   prtx(mm[6]);
  807.  
  808.   close(mfl);         /*  Close current.  */
  809.  
  810.   unlink(mbbfile);    /*  Delete backup   */
  811.  
  812. /*
  813.  *  Copy current to backup.
  814.  */
  815.  
  816.   if (samedir(mbfile, mbbfile)) rename(mbfile, mbbfile);
  817.   else copy(mbfile, mbbfile, false);
  818.  
  819.   unlink(mbfile);     /*  Delete current.  */
  820.  
  821. /*
  822.  *  Open new current and backup.
  823.  */
  824.  
  825.   mfl  = open(mbfile,  O_CREAT  | O_RDWR | O_BINARY, pmode);
  826.   mflb = open(mbbfile, O_RDONLY | O_BINARY);
  827.  
  828.   read_rec(mflb, 0, (char *)mfhs);
  829.   me = mfhs->last;
  830.   inhdr = mfhs->first;
  831.   inithdr();
  832.  
  833.   if (port->opt2 is 'R')
  834.   {
  835.     if (port->flds is 1) mfhs->next_msg = 1;
  836.     else mfhs->next_msg = atoi(port->fld[1]);
  837.   }
  838.  
  839.  
  840.   while(inhdr <= me)        /*  For each message header ... */
  841.   {
  842.     read_rec(mflb, inhdr, (char *)port->mmhs); /* Read the header. */
  843.  
  844. /*
  845.  *  Tell the sysop about this message.
  846.  */
  847.  
  848.     sprintf(port->line, "Hdr %6u Size %6u # %6u Read %6u",
  849.       inhdr, port->mmhs->size, port->mmhs->number, port->mmhs->read);
  850.     outstr(port->line);
  851.  
  852.     inhdr++;
  853.  
  854.     if (!(port->mmhs->stat & ( m_kill | m_busy)))
  855.     {
  856.        outstr("\n");
  857.  
  858. /*
  859.  *  If renumbering messages, renumber this message.
  860.  */
  861.  
  862.        if (port->opt2 is 'R')
  863.        {
  864.          msgfile(port->line, port->mmhs->number);
  865.          msgfile(port->cmd,  mfhs->next_msg);
  866.          rename(port->line, port->cmd);
  867.          port->mmhs->number = mfhs->next_msg++;
  868.        }
  869.  
  870. /*
  871.  *  Write the header.
  872.  */
  873.  
  874.        port->mmhs->rn = ++mfhs->count;
  875.        wt_mmhs();
  876.     }
  877.     else arcmsg();
  878.   }
  879.  
  880.  
  881. /*
  882.  *  Write the file header.
  883.  */
  884.   if (mfhs->count) mfhs->first = 1;
  885.   mfhs->next = mfhs->count + 1;
  886.   mfhs->last = mfhs->count;
  887.   mfhs->unt_msg = mfhs->next_msg;
  888.   write_rec(mfl, 0, (char *)mfhs);
  889.   close(mflb);
  890.   clnmsg();
  891. }
  892.  
  893.  
  894. /*
  895.  *  Print headers of unread messages for this user.
  896.  */
  897.  
  898. newmsg()
  899. {
  900.   if (findfwd(port->user->call, ufwd, ufwdn) or
  901.       findfwd(port->user->call, bfwd, bfwdn))
  902.   {
  903.     prtx(mm[2]);
  904.     port->opt2 = '\0';
  905.     port->flds = 1;
  906.     lstmsg();
  907.   }
  908. }
  909.  
  910. /*
  911.  *  L command, list messages.
  912.  */
  913.  
  914. lstmsg()
  915. {
  916.   register char *p;
  917.   register short done, ok;
  918.   word h, found, more;
  919.   int max_title;
  920.  
  921.   if(port->mode & ops) max_title = false;
  922.   else max_title = true;
  923.  
  924. /*
  925.  *  First set up arguments.
  926.  */
  927.  
  928.   found = 0; more = 0; done = false;
  929.   if ((*port->fld[1] is ';') or (*port->fld[2] is ';'))
  930.   { port->flds--; max_title = true; }
  931.   switch(port->opt2)
  932.   {
  933.     case '@' :
  934.     case '<' :
  935.     case '>' : pcall(tcall, port->fld[1]); break;
  936.     case '\0': break;
  937.     case 'E' :
  938.     case ' ' : if (port->flds is 1) more = port->user->msg_number;
  939.     default  : if (port->flds is 2)
  940.       {
  941.         if (!num(port->fld[1])) { port->msg = mwhat; return; }
  942.         more = atoi(port->fld[1]);
  943.       }
  944.   }
  945.  
  946. /*
  947.  *  Log it, unless is initial login check for msgs.
  948.  */
  949.  
  950.   if (port->opt2)
  951.   {
  952.     sprintf(port->line, "%u", more);
  953.     log('M', 'L', port->opt2, port->line);
  954.   }
  955.  
  956. /*
  957.  *  Paw through the messages and show what requested.
  958.  */
  959.  
  960.   for (h = mfhs->last; h and !done; h--)
  961.   {
  962.     read_rec(mfl, h, (char *)port->mmhs);
  963.     if ((port->opt2 is 'L') or ((port->opt2 is 'E') and (port->flds is 2)))
  964.       done = (found is more); else done = (port->mmhs->number < more);
  965.  
  966.     ok = !done;
  967.  
  968. /*
  969.  *  Does this user have read permission for this message?
  970.  */
  971.  
  972.     if (ok) ok = lpermit();
  973.     if (ok) if (port->mmhs->stat & m_kill)
  974.     ok = ((port->opt2 is 'K') or (port->opt2 is 'E'));
  975.     if (ok) if (port->mmhs->stat & m_busy) ok = (port->opt2 is 'E');
  976.  
  977. /*
  978.  *  Is this message wanted?
  979.  */
  980.  
  981.     if (ok) switch(port->opt2)
  982.     {
  983.       case '\0': ok = matchn(port->user->call, port->mmhs->to, ln_call); break;
  984.       case 'E' : break;
  985.       case 'K' : ok = (port->mmhs->stat & m_kill); break;
  986.       case 'F' : ok = (port->mmhs->stat & m_fwd);  break;
  987.       case 'H' : ok = (port->mmhs->stat & m_hold); break;
  988.       case 'L' : break;
  989.       case 'M' : ok = matchn(port->user->call, port->mmhs->to, ln_call);
  990.                 if (!ok) ok = matchn(port->user->call, port->mmhs->from, ln_call);
  991.                 break;
  992.  
  993.       case 'O' : ok = (port->mmhs->stat & m_stale); break;
  994.       case 'U' : ok = !((port->mmhs->type is 'B')or(port->mmhs->type is 'A')
  995.                        or (port->mmhs->stat & (m_fwd | m_read))); break;
  996.       case 'Y' : ok = (port->mmhs->stat & m_read);  break;
  997.       case '@' : ok = matchn(tcall, port->mmhs->bbs, ln_call); break;
  998.       case '<' : ok = matchn(tcall, port->mmhs->from, ln_call); break;
  999.       case '>' : ok = matchn(tcall, port->mmhs->to, ln_call); break;
  1000.       default  : ok = ((port->mmhs->type is port->opt2) or
  1001.                        (port->opt2 is ' '));
  1002.     }
  1003.     if (ok) if (prthdr(!found++, max_title) is 'Q') return;
  1004.   }
  1005.   if (!found) port->msg = mfind;
  1006.   s_flag setbit s_update;
  1007. }
  1008.  
  1009. /*
  1010.  *  CM command: duplicate a message.
  1011.  */
  1012.  
  1013. dupmsg()
  1014. {
  1015.   word tmpsize;
  1016.   if (!findmsg(atoi(port->fld[2]))) { port->msg = mnmsg; return; }
  1017.   port->opt1 = 'S';
  1018.  
  1019.   prthdr(true, true);
  1020.   pcall(port->mmhs->to, port->fld[1]);
  1021.   fill(port->mmhs->bbs, ' ', ln_call);
  1022.   port->mmhs->ext = 0;
  1023.  
  1024.   if (port->flds > 3) atfrom(port->flds - 2);
  1025.   if (port->flds > 5) atfrom(port->flds - 4);
  1026.   tmpsize = port->mmhs->size;
  1027.  
  1028.   msgfile(port->cmd, port->mmhs->number);
  1029.   initmsg(false);
  1030.   msgfile(port->line, mfhs->next_msg);
  1031.   copy(port->cmd, port->line, false);
  1032.   filesize = tmpsize;
  1033.   cremsg();
  1034. }
  1035.  
  1036. /*
  1037.  *  F command: copy a message to a file.
  1038.  */
  1039.  
  1040. filmsg()
  1041. {
  1042.   register char *p;
  1043.   register short hdr, append;
  1044.   register FILE *out;
  1045.  
  1046.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1047.  
  1048.   hdr = true;
  1049.   append = false;
  1050.  
  1051.   if (port->flds is 4) for (p = port->fld[3]; *p; p++) switch (*p)
  1052.   {
  1053.     case 'A' : append = true; break;
  1054.     case 'N' : hdr    = false; break;
  1055.     default: ;
  1056.   }
  1057.  
  1058.   if (port->opt2 is ' ') strcpy(port->line, port->fld[2]);
  1059.   else if (getdir(port->fld[2]) is NULL) { port->msg = mndir; return; }
  1060.  
  1061.   if (append) out = fopen (port->line, "a"); else
  1062.   {
  1063.     if ((out = fopen (port->line, "r")) isnt NULL)
  1064.       { fclose(out); port->msg = mexst; return; }
  1065.     out = fopen (port->line, "w");
  1066.   }
  1067.  
  1068.   if (out is NULL) { port->msg = mcant; return; }
  1069.  
  1070.   sprintf(tmp->scr, "%s %s", port->fld[1], port->line);
  1071.   log('M', 'D', port->opt2, tmp->scr);
  1072.  
  1073.   prthdr(true, true);
  1074.  
  1075.   if (hdr) fputs(tmp->scr, out);
  1076.  
  1077.   msgfile(port->cmd, port->mmhs->number);
  1078.  
  1079.   if ((port->fl = fopen(port->cmd, "r")) is NULL)
  1080.     { fclose(out); nofile(port->cmd); return; }
  1081.   fseek( port->fl, (long)RECSIZE, 0);
  1082.   while (fgets(tmp->scr, scrmax, port->fl) isnt NULL) fputs(tmp->scr, out);
  1083.  
  1084.   fclose(port->fl);
  1085.   fclose(out);
  1086. }
  1087.  
  1088. /*
  1089.  *  Upload the message text file.
  1090.  */
  1091.  
  1092. uloadm(tname)
  1093. char *tname;
  1094. {
  1095.   register char *tp;
  1096.   register PORTS *p;
  1097.   short first;
  1098.  
  1099.   p = port;
  1100.  
  1101.   if ((p->fl = fopen(tname, "w")) is NULL) { p->msg = mcant; return false; }
  1102.   fseek( p->fl, (long)RECSIZE, 0);
  1103.  
  1104.   first = true;
  1105.   filesize = 0;
  1106.   while (true)
  1107.   {
  1108.     while(!getdat());
  1109.  
  1110. /*
  1111.  *  If user disconnected, timed out, or forced off, zap the file.
  1112.  */
  1113.  
  1114.     if (p->mode & gone)
  1115.     {
  1116.       fclose(p->fl);
  1117.       return false;
  1118.     }
  1119.  
  1120. /*
  1121.  *  If the first line is not a header (thus it is a human entering
  1122.  *  the message), make sure there is an initial blank line before
  1123.  *  the body of the message.
  1124.  */
  1125.  
  1126.     if (first)
  1127.     {
  1128.       first = false;
  1129.       if (!ishead(p->line)) if (*p->line isnt '\n') fputs("\n", p->fl);
  1130.     }
  1131.  
  1132. /*
  1133.  *  Stuff the line into the file.
  1134.  */
  1135.  
  1136.     if (match(p->line, "/EX\n") or match(p->line,"/ex\n"))
  1137.     {
  1138.       fclose(p->fl);
  1139.       return true;
  1140.     }
  1141.  
  1142.  
  1143.     if ((tp = strchr(p->line, cpmeof)) is NULL)
  1144.     {
  1145.       filesize += strlen(p->line);
  1146.       fputs(p->line, p->fl);
  1147.     }
  1148.     else
  1149.     {
  1150.       if (tp isnt p->line)
  1151.       {
  1152.         *tp++ = '\n';
  1153.         *tp   = '\0';
  1154.         filesize += strlen(p->line);
  1155.         fputs(p->line, p->fl);
  1156.       }
  1157.       fclose(p->fl);
  1158.       return true;
  1159.     }
  1160.   }
  1161. }
  1162.  
  1163. /*
  1164.  *  "Display the message text" utility.
  1165.  */
  1166.  
  1167. dloadm(sh)
  1168. short sh;
  1169. {
  1170.   short first;
  1171.  
  1172.   sprintf(port->line, "%u", port->mmhs->number);
  1173.   log('M', 'R', port->opt2, port->line);
  1174.   port->mmhs->read++;
  1175.   if (matchn(port->user->call, port->mmhs->to, ln_call))
  1176.     port->mmhs->stat setbit m_read;
  1177.   wt_mmhs();
  1178.   makehdr2();
  1179.   prthdr(true, true);
  1180.  
  1181.   msgfile(port->line, port->mmhs->number);
  1182.  
  1183.   if ((port->fl = fopen(port->line, "r")) is NULL)
  1184.     { nofile(port->line); return; }
  1185.  
  1186.   fseek( port->fl, (long)RECSIZE, 0 );
  1187.   pgck();   /* First line of header */
  1188.   pgck();   /* Second line of header */
  1189.   pgck();   /* Path line */
  1190.   if (port->mmhs->ext) pgck();
  1191.   if (*port->mmhs->bid isnt ' ') pgck();
  1192.  
  1193.   strcpy(tmp->scr, "  Path: ");
  1194.   first = true;
  1195.  
  1196.   while(fgets(port->line, linelen, port->fl) isnt NULL)
  1197.   {
  1198.     if (!sh)
  1199.     {
  1200.       sh = !parsehd(port->line);
  1201.       if (sh)
  1202.       {
  1203.         if (!first)
  1204.         {
  1205.           strcat(tmp->scr, "\n\n");
  1206.           outstr(tmp->scr);
  1207.           pgck();
  1208.           prtx("Date: $j/$k\n");  pgck();
  1209.           prtx("From: $P @ $a\n");  pgck();
  1210.           prtx("Message-Id: <$m@$a>\n");  pgck();
  1211.           prtx("To: $G @ ");
  1212.           if (*port->mmhs->bbs is ' ')  prtx("$O\n");
  1213.           else if (port->mmhs->ext is 2) prtx("$h\n");
  1214.           else prtx("$A\n");  pgck();
  1215.           prtx("Subject: $E\n\n");  pgck();
  1216.         }
  1217.       }
  1218.       else
  1219.       {
  1220.         if (!first) strcat(tmp->scr, "!");
  1221.         strcat(tmp->scr, orgbbs);   
  1222.         first = false;
  1223.       }
  1224.     }
  1225.  
  1226.     if (sh)
  1227.     {
  1228.       outstr(port->line);
  1229.       if ((pgck() is 'Q') or (chkdis())) { fclose(port->fl); return; }
  1230.     }
  1231.   }
  1232.   fclose (port->fl);
  1233. }
  1234.  
  1235. /*
  1236.  *  RM command: read my messages.
  1237.  */
  1238.  
  1239. rdmsgm()
  1240. {
  1241.   register short found;
  1242.   register word h;
  1243.  
  1244.   found = false;
  1245.   for (h = mfhs->first; h and h <= mfhs->last; h++)
  1246.   {
  1247.     read_rec(mfl, h, (char *)port->mmhs);
  1248.     if (!(port->mmhs->stat & (m_read | m_fwd | m_hold | m_busy)) and
  1249.       matchn(port->user->call, port->mmhs->to, ln_call))
  1250.     {
  1251.       dloadm(false);
  1252.       found = true;
  1253.       if (pause() is 'Q') return;
  1254.     }
  1255.   }
  1256.   if (!found) port->msg = mfind;
  1257. }
  1258.  
  1259. /*
  1260.  *  R command: read one message.
  1261.  */
  1262.  
  1263. rdmsg()
  1264. {
  1265.   if (!num(port->fld[1]))           { port->msg = mwhat; return; }
  1266.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1267.   if (!rpermit())                   { port->msg = mprot; return; }
  1268.  
  1269.   dloadm(port->opt2 is 'H');
  1270. }
  1271.  
  1272. /*
  1273.  *  KF, KM, KO, KY, KK commands, kill multiple messages.
  1274.  */
  1275.  
  1276. klmsgm()
  1277. {
  1278.   register short ok;
  1279.   register short found;
  1280.   word h, next;
  1281.  
  1282.   if (port->flds is 2) pcall(tcall, port->fld[1]);
  1283.  
  1284.   found = false;
  1285.   for (h = mfhs->first; h and h <= mfhs->last; h++)
  1286.   {
  1287.     read_rec(mfl, h, (char *)port->mmhs);
  1288.  
  1289.     ok = kpermit();
  1290.     if (ok) ok = !(port->mmhs->stat & m_hold);
  1291.  
  1292.     if (ok) if (port->flds is 2) ok = matchn(tcall, port->mmhs->to, ln_call);
  1293.  
  1294.     if (ok) switch(port->opt2)
  1295.     {
  1296.       case 'F' : ok = (port->mmhs->stat & m_fwd); break;
  1297.       case 'M' :
  1298.         ok = ((port->mmhs->stat & m_read) and
  1299.           matchn(port->user->call, port->mmhs->to, ln_call));
  1300.         break;
  1301.       case 'O' : ok = (port->mmhs->stat & m_stale); break;
  1302.       case 'Y' : ok = (port->mmhs->stat & m_read);  break;
  1303.     }
  1304.  
  1305.     if (ok)
  1306.     {
  1307.       sprintf(port->line, "%u", port->mmhs->number);
  1308.       log('M', 'K', port->opt2, port->line);
  1309.       prtx(mm[7]);
  1310.       found = true;
  1311.       port->mmhs->stat setbit m_kill;
  1312.       write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
  1313.       makehdr2();
  1314.     }
  1315.   }
  1316.   if (!found) port->msg = mfind;
  1317. }
  1318.  
  1319. /*
  1320.  *  Kill multiple messages.
  1321.  */
  1322.  
  1323. klmult()
  1324. {
  1325.   static char msgn[25];
  1326.   int i;
  1327.  
  1328.   strncpy(&msgn[0], port->fld[2], 5);
  1329.   strncpy(&msgn[6], port->fld[3], 5);
  1330.   strncpy(&msgn[12], port->fld[4], 5);
  1331.   outstr(port->fld[1]); klmsg();
  1332.   prtx(port->msg);
  1333.   for ( i=0; msgn[i]; i += 6)
  1334.   {
  1335.     strcpy(port->fld[1], &msgn[i]);
  1336.     outstr(port->fld[1]); klmsg();
  1337.     prtx(port->msg); port->msg = NULL;
  1338.   }
  1339. }
  1340.  
  1341. /*
  1342.  *  K command, kill a message.
  1343.  */
  1344.  
  1345. klmsg()
  1346. {
  1347.   register short dosvc;
  1348.   unsigned int org_num;
  1349.  
  1350.   if (!num(port->fld[1]))           { port->msg = mwhat; return; }
  1351.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1352.   if (port->mmhs->stat & m_kill)    { port->msg = mnmsg; return; }
  1353.   if (!kpermit())                   { port->msg = mprot; return; }
  1354.  
  1355.   log('M', 'K', port->opt2, port->fld[1]);
  1356.  
  1357.   dosvc = (port->opt2 is 'T') and
  1358.           (port->mmhs->type is 'T') and
  1359.           (s_param & s_svc);
  1360.  
  1361.   if (dosvc) org_num = atoi(port->fld[1]);
  1362.  
  1363. /*
  1364.  *  Marked the message as  Killed.
  1365.  */
  1366.  
  1367.   if(port->opt2 is 'A') port->mmhs->stat setbit m_noarc;
  1368.   port->mmhs->stat setbit m_kill;
  1369.   write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
  1370.   makehdr2();
  1371.  
  1372. /*
  1373.  *  If this is KT of T type message, and we do service messages,
  1374.  *  do the service message.
  1375.  */
  1376.  
  1377.   if (dosvc)
  1378.   {
  1379.     port->mmhs->ext = 0;
  1380.     findat();
  1381.     port->opt1 = 'S';
  1382.     strncpy(port->mmhs->to, port->mmhs->from, ln_call);
  1383.     strncpy(port->mmhs->from, cport->user->call, ln_call);
  1384.     port->mmhs->type = 'S';
  1385.     fill(port->mmhs->bid, ' ', ln_bid);
  1386.     initmsg(false);
  1387.     msgfile(port->line, mfhs->next_msg);
  1388.     port->fl = fopen(port->line, "w");
  1389.     fseek(port->fl, (long)RECSIZE, 0);
  1390.     fprintf(port->fl, "Msg %5u taken from %6.6s by %6.6s at %4.4s on %6.6s\n",
  1391.       org_num, cport->user->call, port->user->call, l_time, l_date);
  1392.     fclose(port->fl);
  1393.  
  1394.     filesize = 56;
  1395.     cremsg();
  1396.   }
  1397.   port->msg = mdone;
  1398. }
  1399.  
  1400. /*
  1401.  *  S command: send a message.
  1402.  */
  1403.  
  1404. sndmsg()
  1405. {
  1406.   FILE *out;
  1407.   char *a, *b;
  1408.  
  1409.   holdit = false;   /* initialize it to something */
  1410.  
  1411.   pfld();
  1412.   if (port->mode & gone) return;
  1413.  
  1414.   if (bidok) {
  1415.     if (!needbid) return;
  1416.   }
  1417.   else {
  1418.     if (port->user->options & (u_bbs | u_expert)) outstr("Msg:\n");
  1419.     else prtx(mm[1]);
  1420.   }
  1421.  
  1422.   msgfile(port->cmd, mfhs->next_msg);
  1423.   if (!uloadm(port->cmd)) return;
  1424.  
  1425. /*
  1426.  *  If this is a Bulletin and has no BID, 
  1427.  *  parse the headers and give it one.
  1428.  */
  1429.   if (!hasbid)
  1430.   if (!iscall(port->mmhs->to))
  1431.   if (port->mmhs->type is 'B')
  1432.   {
  1433.         msgfile(port->cmd, mfhs->next_msg);
  1434.         a = port->line;
  1435.         b = cport->user->call;
  1436.         unbl(a, b, 6);
  1437.  
  1438. /* Default the BID as to coming from this BBS with our msg number. */
  1439.  
  1440.         sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
  1441.  
  1442. /* Now parse the headers if it came from another BBS. */
  1443.  
  1444.         if ((out = fopen(port->cmd, "r")) is NULL)
  1445.         {
  1446.            nofile(port->cmd); return;
  1447.         }
  1448.         fseek(out, (long)RECSIZE, 0);
  1449.         while (fgets(port->line, linelen, out) isnt NULL)
  1450.         {
  1451.            if (parsehd(port->line))
  1452.            {
  1453.              sprintf(tmp->scr, "%s_%s", orgmsg, orgbbs);
  1454.            }
  1455.         }
  1456.         fclose(out);
  1457.         strncpy(port->mmhs->bid, tmp->scr, ln_bid);
  1458.         hasbid = true;
  1459.   }
  1460.   checkbid(); 
  1461.   if (!needbid) holdit = true;
  1462.   else holdit = false;
  1463.   
  1464.   /*  If a message is to an individual, 
  1465.    *  automatically make it a private message.
  1466.    */
  1467.  
  1468.   if (port->opt2 is ' ')
  1469.   if (iscall(port->mmhs->to)) port->mmhs->type = 'P';
  1470.  
  1471.   cremsg();
  1472. }
  1473.  
  1474. /*
  1475.  *  SM command, send a message to a distribution list.
  1476.  */
  1477.  
  1478. sndmlt()
  1479. {
  1480.   register FILE *fl;
  1481.   char fn[80];
  1482.   register short first = true;
  1483.   word tmpsize;
  1484.   
  1485.   holdit = false;
  1486.   fill(port->mmhs->bid, ' ', ln_bid);
  1487.  
  1488.   if ((fl = fopen(port->fld[1], "r")) is NULL)
  1489.     { nofile(port->fld[1]); return; }
  1490.  
  1491.   prtx(mm[0]);
  1492.   get_title();
  1493.   if (port->mode & gone) { fclose(fl); return; }
  1494.  
  1495.   if (port->flds is 3) if (*port->fld[port->flds-1] is '$')
  1496.   {
  1497.     if (*(port->fld[port->flds-1] + 1) isnt NULL)
  1498.     {
  1499.       strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
  1500.       hasbid = true;
  1501.     }
  1502.   }
  1503.  
  1504.   prtx(mm[1]);
  1505.  
  1506.   strncpy(port->mmhs->from, port->user->call, ln_call);
  1507.   port->mmhs->ext = 0;
  1508.   initmsg(false);
  1509.   msgfile(fn, mfhs->next_msg);
  1510.   if (!uloadm(fn)) { fclose(fl); return; }
  1511.   tmpsize = filesize;
  1512.  
  1513.   while (fgets(port->line, linelen, fl) isnt NULL)
  1514.   {
  1515.     parse();
  1516.     if (!first)
  1517.     {
  1518.       port->mmhs->ext = 0;
  1519.       initmsg(false);
  1520.       msgfile(port->line, mfhs->next_msg);
  1521.       copy(fn, port->line, false);
  1522.     }
  1523.     port->mmhs->type = port->opt2;
  1524.     pcall(port->mmhs->to, port->fld[1]);
  1525.     fill(port->mmhs->bbs, ' ', ln_call);
  1526.  
  1527.     if(port->flds > 3) atfrom(2);
  1528.     if(port->flds > 5) atfrom(4);
  1529.     filesize = tmpsize;
  1530.     cremsg();
  1531.     first = false;
  1532.   }
  1533.   fclose(fl);
  1534. }
  1535.  
  1536. /*
  1537.  *  M command, make a message from a file.
  1538.  */
  1539.  
  1540. makmsg()
  1541. {
  1542.   if ((port->fl = fopen(port->fld[2], "r")) is NULL)
  1543.     { nofile(port->fld[2]); return; }
  1544.   fclose(port->fl);
  1545.   pfld();
  1546.   if (port->mode & gone) return;
  1547.   msgfile(port->line, mfhs->next_msg);
  1548.   copy(port->fld[2], port->line, true);
  1549.   cremsg();
  1550. }
  1551.  
  1552. /*
  1553.  *  MM command, make multiple messages from a file.
  1554.  */
  1555.  
  1556. makmlt()
  1557. {
  1558.   register FILE *dfl;
  1559.   char tnm[80];
  1560.  
  1561.   holdit = false;
  1562.   fill(port->mmhs->bid, ' ', ln_bid);
  1563.  
  1564.   if ((port->fl = fopen(port->fld[2], "r")) is NULL)
  1565.     { nofile(port->fld[2]); return; }
  1566.   fclose(port->fl);
  1567.  
  1568.   if ((dfl = fopen(port->fld[1], "r")) is NULL)
  1569.     { nofile(port->fld[1]); return; }
  1570.  
  1571.   strcpy(tnm, port->fld[2]);
  1572.  
  1573.   if (port->flds is 4) if (*port->fld[port->flds-1] is '$')
  1574.   {
  1575.     if (*(port->fld[port->flds - 1] + 1) isnt NULL)
  1576.     {
  1577.       strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
  1578.       hasbid = true;
  1579.     }
  1580.   }
  1581.  
  1582.   prtx(mm[0]);
  1583.   get_title();
  1584.   if (port->mode & gone) { fclose(dfl); return; }
  1585.  
  1586.   while (fgets(port->line, linelen, dfl) isnt NULL)
  1587.   {
  1588.     parse();
  1589.     port->mmhs->type = port->opt2;
  1590.     pcall(port->mmhs->to, port->fld[1]);
  1591.     strncpy(port->mmhs->from, port->user->call, ln_call);
  1592.     fill(port->mmhs->bbs, ' ', ln_call);
  1593.     port->mmhs->ext = 0;
  1594.  
  1595.     if (port->flds > 3) atfrom(2);
  1596.     if (port->flds > 5) atfrom(4);
  1597.     initmsg(false);
  1598.     msgfile(port->line, mfhs->next_msg);
  1599.     copy(tnm, port->line, true);
  1600.     cremsg();
  1601.   }
  1602.   fclose(dfl);
  1603. }
  1604.  
  1605. /*
  1606.  *  Mark stale messages.
  1607.  */
  1608.  
  1609. stale()
  1610. {
  1611.   register word i;
  1612.   register int ts, ks;
  1613.  
  1614.   for (i = mfhs->first; i and i <= mfhs->last; i++)
  1615.   {
  1616.     read_rec(mfl, i, (char *)port->mmhs);
  1617.  
  1618.     ts = tstaleb; ks = (s_flag & s_bkill);
  1619.     if (port->mmhs->type is 'T') {ts = tstalen;ks = (s_flag & s_nkill);}
  1620.     else if (iscall(port->mmhs->to)) {ts = tstaleu;ks = (s_flag & s_ukill);}
  1621.  
  1622.     if (!(port->mmhs->stat & m_stale))
  1623.     if (ddiff(port->mmhs->date, l_date) > ts)
  1624.     {
  1625.       if (ks and !(port->mmhs->stat & m_hold)) port->mmhs->stat setbit m_kill;
  1626.       else port->mmhs->stat setbit m_stale;
  1627.       write_rec(mfl, i, (char *)port->mmhs);
  1628.     }
  1629.   }
  1630. }
  1631.  
  1632. /*
  1633.  *  DW command: make wp message from user file.
  1634.  */
  1635.  
  1636. dwuser()
  1637. {
  1638.   register int i;
  1639.   register short first = true;
  1640.   short doall;
  1641.  
  1642.   if (*wpcall is ' ') return;
  1643.  
  1644.   doall = port->flds is 2;
  1645.   port->opt1 = 'S';
  1646.   filesize = 0;
  1647.  
  1648.   for (i = 1; i <= ufhs->count; i++)
  1649.   {
  1650.     read_rec(ufl, i, (char *)tuser);
  1651.     if ((tuser->state & u_home) and (tuser->state & u_zip))
  1652.     if (doall or !(tuser->state & u_sent))
  1653.     {
  1654.       if (first)
  1655.       {
  1656.         first = false;
  1657.         port->mmhs->type = 'P';
  1658.         strncpy(port->mmhs->to, "WP    ", ln_call);
  1659.         strncpy(port->mmhs->from, cport->user->call, ln_call);
  1660.         strncpy(port->mmhs->bbs, wpcall, ln_call);
  1661.         strcpy(port->mmhs->title, "WP Update");
  1662.         fill(port->mmhs->bid, ' ', ln_bid);
  1663.         port->mmhs->ext = 0;
  1664.         initmsg(false);
  1665.         msgfile(port->line, mfhs->next_msg);
  1666.         port->fl = fopen(port->line, "w");
  1667.         fseek(port->fl, (long)RECSIZE, 0);
  1668.       }
  1669.  
  1670.       filesize += 29;
  1671.       fprintf(port->fl, "%6.6s qth %6.6s zip %6.6s\n",
  1672.           tuser->call, tuser->home_bbs, tuser->zip);
  1673.       tuser->state setbit u_sent;
  1674.       write_rec(ufl, i, (char *)tuser);
  1675.       if (i is port->user->rn) port->user->state setbit u_sent;
  1676.     }
  1677.   }
  1678.  
  1679.   if (!first)
  1680.   {
  1681.     fclose(port->fl);
  1682.     chkhier();
  1683.     cremsg();
  1684.   }
  1685. }
  1686.  
  1687. /*
  1688.  *  E command, edit a message header.
  1689.  */
  1690.  
  1691. edmsg()
  1692. {
  1693.   FILE *out;
  1694.   char *a, *b;
  1695.  
  1696.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1697.   while (*port->fld[0] isnt '\0')
  1698.   {
  1699.     prthdr(true, true);
  1700.     outstr("t(Y)pe, (S)tatus, (T)o, (F)rom, (B)bs, t(I)tle, bi(D)\n");
  1701.     getcmd();
  1702.     if (port->mode & gone) return;
  1703.     switch (*port->fld[0])
  1704.     {
  1705.       case 'T' : pcall(port->mmhs->to, port->fld[1]); break;
  1706.       case 'F' : pcall(port->mmhs->from, port->fld[1]); break;
  1707.       case 'B' : edbbs(1); break;
  1708.       case 'I' : if (*port->fld[1])
  1709.                  {
  1710.                    remnl(port->line);
  1711.                    strncpy(port->mmhs->title, port->line+2, mhtitl);
  1712.                  }
  1713.                  else *port->mmhs->title = '\0';
  1714.                  break;
  1715.       case 'S' : switch(*port->fld[1])
  1716.                  {
  1717.                    case 'F' : port->mmhs->stat = m_fwd;   break;
  1718.                    case 'H' : port->mmhs->stat = m_hold;  break;
  1719.                    case 'N' : port->mmhs->stat = 0;       break;
  1720.                    case 'O' : port->mmhs->stat = m_stale; break;
  1721.                    case 'Y' : port->mmhs->stat = m_read;  break;
  1722.                  }
  1723.                  break;
  1724.       case 'Y' : if(*port->fld[1]) port->mmhs->type = *port->fld[1];
  1725.                  else port->mmhs->type = ' '; break;
  1726.  
  1727.       case 'D' : if(*port->fld[1]) strncpy(port->mmhs->bid, port->fld[1], ln_bid);
  1728.                  else fill(port->mmhs->bid, ' ', ln_bid);
  1729.                  break;
  1730.     }
  1731.   }
  1732.   wt_mmhs();
  1733.   makehdr2();
  1734.   if (*port->mmhs->bid isnt ' ')
  1735.   {
  1736.     checkbid();
  1737.     if  (needbid)
  1738.     {
  1739.       if ((out = fopen(bidfile,"a")) is NULL)
  1740.       {
  1741.         port->msg = mcant; return; 
  1742.       }
  1743.  
  1744.       a = port->cmd;
  1745.       b = port->mmhs->bid;
  1746.       unbl(a, b, ln_bid);      
  1747.  
  1748.       sprintf(port->line, "%4.4s%s\n", port->mmhs->date + 2, port->cmd);
  1749.       if (s_flag & s_dv) begin_lock();
  1750.       fputs(port->line, out);
  1751.       if (s_flag & s_dv) end_lock();
  1752.       fclose(out);
  1753.     }
  1754.   }
  1755. }
  1756.  
  1757. /*
  1758.  *  ET command, edit an NTS traffic message header.
  1759.  */
  1760.  
  1761. edtfc()
  1762. {
  1763.   register short ok;
  1764.  
  1765.   if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  1766.   prthdr(true, true);
  1767.  
  1768.   ok = (port->mmhs->type is 'T');
  1769.   if (!ok) ok = ((port->mmhs->type is ' ') and matchn(port->mmhs->to, "NTS", 3));
  1770.   if (!ok) { port->msg = mm[12]; return; }
  1771.  
  1772.   prtx(mm[8]);
  1773.   getcmd();
  1774.   if (port->mode & gone) return;
  1775.   if (port->flds) pcall(port->mmhs->to, port->fld[0]);
  1776.  
  1777.   prtx(mm[9]);
  1778.   getcmd();
  1779.   if (port->mode & gone) return;
  1780.   edbbs(0);
  1781.  
  1782.   prtx(mm[10]);
  1783.   getcmd();
  1784.   if (port->mode & gone) return;
  1785.   if (port->flds)
  1786.   {
  1787.     remnl(port->line);
  1788.     strncpy(port->mmhs->title, port->line, mhtitl);
  1789.   }
  1790.   else if (*port->line is ' ') *port->mmhs->title = '\0';
  1791.  
  1792.   prtx(mm[11]);
  1793.   getcmd();
  1794.   if (port->mode & gone) return;
  1795.   if (port->flds) port->mmhs->type = *port->fld[0];
  1796.   else if (*port->line is ' ') port->mmhs->type = ' ';
  1797.  
  1798.   port->mmhs->stat = 0;
  1799.   prthdr(true, true);
  1800.   wt_mmhs();
  1801.   makehdr2();
  1802.   sprintf(port->line, "%u %-.6s %s",
  1803.     port->mmhs->number, port->mmhs->to, port->mmhs->title);
  1804.   log('M', 'E', port->opt2, port->line);
  1805. }
  1806.  
  1807. edbbs(f)
  1808. int f;
  1809. {
  1810.   fill(port->mmhs->call, '\0', 125);
  1811.   port->mmhs->ext = 0;
  1812.   fill(port->mmhs->bbs, ' ', ln_call);
  1813.   if(*port->fld[f])
  1814.   {
  1815.     pcall(port->mmhs->bbs, port->fld[f]);
  1816.     if (strchr(port->fld[f], '.') is NULL) dodis();
  1817.     else
  1818.     {
  1819.       port->mmhs->ext = 2;
  1820.       strncpy(port->mmhs->call[0], port->fld[f], 64);
  1821.     }
  1822.     if (port->mmhs->ext is 0) chkhier();
  1823.   }
  1824. }
  1825.  
  1826. /*
  1827.  *  Check to see if bbs has match in STATES.MB file and add state code
  1828.  *  to hierarchical call.
  1829.  */
  1830.  
  1831. chkhier()
  1832. {
  1833.   FILE *hier;
  1834.   char hiercall[ln_call], bbs[ln_call+1];
  1835.   char *p;
  1836.  
  1837.   if (*port->mmhs->bbs is ' ') return;
  1838.   if(( hier = fopen( stfile, "r")) is NULL) return;
  1839.   while( fgets( tmp->scr, linelen, hier) isnt NULL)
  1840.   {
  1841.     pcall(hiercall, tmp->scr);
  1842.     if( wcm(hiercall, port->mmhs->bbs))
  1843.     {
  1844.       remnl(tmp->scr);
  1845.       p = strchr(tmp->scr, '.');
  1846.       unbl(bbs, port->mmhs->bbs, ln_call);
  1847.       port->mmhs->ext = 2;
  1848.       fill( port->mmhs->call[0], '\0', 125);
  1849.       sprintf( port->mmhs->call[0], "%s%s", bbs, p);
  1850.       fclose(hier);
  1851.       return;
  1852.     }
  1853.    }
  1854.    fclose(hier);
  1855.    return;
  1856.  }
  1857.