home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / BSRC_250.LZH / MAILOVLY.C < prev    next >
C/C++ Source or Header  |  1991-09-15  |  33KB  |  1,192 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                          */
  3. /*                                                                          */
  4. /*      ------------         Bit-Bucket Software, Co.                       */
  5. /*      \ 10001101 /         Writers and Distributors of                    */
  6. /*       \ 011110 /          Freely Available<tm> Software.                 */
  7. /*        \ 1011 /                                                          */
  8. /*         ------                                                           */
  9. /*                                                                          */
  10. /*  (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
  11. /*                                                                          */
  12. /*                                                                          */
  13. /*                 This module was written by Bob Hartman                   */
  14. /*                                                                          */
  15. /*                                                                          */
  16. /*                   BinkleyTerm Mail Control Routines                      */
  17. /*                                                                          */
  18. /*                                                                          */
  19. /*    For complete  details  of the licensing restrictions, please refer    */
  20. /*    to the License  agreement,  which  is published in its entirety in    */
  21. /*    the MAKEFILE and BT.C, and also contained in the file LICENSE.250.    */
  22. /*                                                                          */
  23. /*    USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  24. /*    BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  25. /*    THIS  AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,  OR IF YOU DO    */
  26. /*    NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  27. /*    SOFTWARE CO.  AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  28. /*    SHOULD YOU  PROCEED TO USE THIS FILE  WITHOUT HAVING  ACCEPTED THE    */
  29. /*    TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  30. /*    AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.      */
  31. /*                                                                          */
  32. /*                                                                          */
  33. /* You can contact Bit Bucket Software Co. at any one of the following      */
  34. /* addresses:                                                               */
  35. /*                                                                          */
  36. /* Bit Bucket Software Co.        FidoNet  1:104/501, 1:343/491             */
  37. /* P.O. Box 460398                AlterNet 7:491/0                          */
  38. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  39. /*                                Internet f491.n343.z1.fidonet.org         */
  40. /*                                                                          */
  41. /* Please feel free to contact us at any time to share your comments about  */
  42. /* our software and/or licensing policies.                                  */
  43. /*                                                                          */
  44. /*--------------------------------------------------------------------------*/
  45.  
  46. /* Include this file before any other includes or defines! */
  47.  
  48. #include "includes.h"
  49.  
  50. char mail_stat (MAILP);
  51. int xmit_install (MAILP, ADDRP);
  52. MAILP xmit_find (MAILP, ADDRP);
  53. long netsize (MAILP);
  54. int any_mail (MAILP);
  55. void do_xmit_line (char *, MAILP);
  56. void xmit_sort (void);
  57. char *numdisp (long);
  58.  
  59. #ifdef MILQ
  60. static char *HoldFmtStr = "%16.16s %4.4s %5.5s %c";
  61. static char *HoldNoSize = "%21.21s %5.5s %c";
  62. #else
  63. static char *HoldFmtStr = "%-16.16s %4.4s %5.5s %c";
  64. static char *HoldNoSize = "%-21.21s %5.5s %c";
  65. #endif
  66.  
  67. void xmit_sameplace ()
  68. {
  69.    MAILP p, p1;
  70.  
  71.    /* Find the guy we just gave mail to */
  72.    p = find_mail (&remote_addr);
  73.    remote_addr.Zone = remote_addr.Net = remote_addr.Node = remote_addr.Point = 0;
  74.    remote_addr.Domain = NULL;
  75.    if (p == NULL)
  76.       {
  77.       /* He is not there */
  78.       return;
  79.       }
  80.  
  81.    /* Save our current pointer */
  82.    p1 = next_mail;
  83.    if (p != next_mail)
  84.       {
  85.       /* If it is not the one we just gave mail to, save ptr and delete */
  86.       next_mail = p;
  87.       xmit_delete ();
  88.       next_mail = p1;
  89.       }
  90.    else
  91.       {
  92.       /* It was the guy at the head of the list, so just delete him */
  93.       xmit_delete ();
  94.       }
  95.  
  96.    /* If we came in with a null, leave with a null */
  97.    if (p1 == NULL)
  98.       next_mail = NULL;
  99.  
  100.    return;
  101. }
  102.  
  103. MAILP find_mail (ADDRP address)
  104. {
  105.    MAILP p;
  106.  
  107.    p = mail_top;
  108.    while (p != NULL)
  109.       {
  110.       if ((no_zones || (p->mail_addr.Zone == address->Zone)) &&
  111.           (p->mail_addr.Net == address->Net) &&
  112.           (p->mail_addr.Node == address->Node) &&
  113.           (p->mail_addr.Point == address->Point) &&
  114.           ((p->mail_addr.Domain == address->Domain) ||
  115.            ((p->mail_addr.Domain == my_addr.Domain) &&
  116.             (address->Domain == NULL))))
  117.          break;
  118.       p = p->next;
  119.       }
  120.  
  121.    return (p);
  122. }
  123.  
  124. int xmit_install (MAILP p, ADDRP addr)
  125. {
  126.    MAILP p1, p2;
  127.    int rettype;
  128.    long sztemp;
  129.  
  130.    p2 = find_mail (addr);
  131.  
  132.    if (p2 == NULL)
  133.       {
  134.       /* We didn't find it in what we have already */
  135.       p1 = p;
  136.       p1->mail_addr = *addr;
  137.       rettype = 0;
  138.       }
  139.    else
  140.       {
  141.       /* We found it, so we have to make sure the higher level routine knows */
  142.       p1 = p2;
  143.       rettype = 1;
  144.       }
  145.  
  146. /*
  147.  * Get the size of the entry. If it's a FLO-type file,
  148.  * call netsize to find out how big the stuff contained in it
  149.  * actually is. If it's a packet, just take its size.
  150.  *
  151.  * Hold packets don't count.
  152.  */
  153.  
  154.    if (!no_size)
  155.       {
  156.       sztemp = 0L;
  157.  
  158.       if (!strncmp (&(dta_str.name[10]), "LO", 2))
  159.          p1->mailsize += (sztemp = netsize (p1));
  160.  
  161.       else
  162.       if (!strncmp (&(dta_str.name[10]), "UT", 2))
  163.          p1->mailsize += (sztemp = dta_str.size);
  164.  
  165.       if (dta_str.name[9] != 'H')
  166.          p1->callsize += sztemp;
  167.       }
  168.  
  169.    switch (dta_str.name[9])
  170.       {
  171.       case 'C':      /* Crash */
  172.          p1->mailtypes |= MAIL_CRASH;
  173.          break;
  174.  
  175.       case 'H':      /* Hold */
  176.          p1->mailtypes |= MAIL_HOLD;
  177.          break;
  178.  
  179.       case 'F':      /* Normal */
  180.       case 'O':
  181.          p1->mailtypes |= MAIL_NORMAL;
  182.          break;
  183.  
  184.       case 'D':      /* Direct */
  185.          p1->mailtypes |= MAIL_DIRECT;
  186.          break;
  187.  
  188.       case 'R':      /* Request */
  189.          p1->mailtypes |= MAIL_REQUEST;
  190.          break;
  191.       }
  192.  
  193.    if (!nodefind (&(p1->mail_addr), 0))
  194.       {
  195.       p1->mailtypes |= MAIL_UNKNOWN;
  196.       return (rettype);
  197.       }
  198.  
  199.    /* Don't call for "HOLD" or "REQ" stuff. */
  200.    if ((dta_str.name[9] == 'H') || (dta_str.name[9] == 'R'))
  201.       {
  202.       return (rettype);
  203.       }
  204.  
  205.    /* If there's no event, set mail to 'go' */
  206.    if (cur_event < 0)
  207.       {
  208.       p1->mailtypes &= ~MAIL_QSMALL;
  209.       p1->mailtypes |= MAIL_WILLGO;
  210.       return (rettype);
  211.       }
  212.  
  213.    /* If it is a crash only event and we have crashmail, set it to go */
  214.  
  215.    if (e_ptrs[cur_event].behavior & MAT_HIPRICM)
  216.       {
  217.       if ((dta_str.name[9] == 'C') && (newnodedes.NodeFlags & B_CM))
  218.          {
  219.          p1->mailtypes &= ~MAIL_QSMALL;
  220.          p1->mailtypes |= MAIL_WILLGO;
  221.          return (rettype);
  222.          }
  223.       }
  224.  
  225.    /* If it is a crash only event and this wasn't crash, return */
  226.    if ((dta_str.name[9] != 'C') && (e_ptrs[cur_event].behavior & MAT_CM))
  227.       {
  228.       return (rettype);
  229.       }
  230.  
  231.    /* Is this a local only event? */
  232.    if (e_ptrs[cur_event].behavior & MAT_LOCAL)
  233.       {
  234.       /*
  235.        * If this is supposed to be only local, then get out if it isn't 
  236.        */
  237.       if (e_ptrs[cur_event].node_cost >= 0)
  238.          {
  239.          if ((int) newnodedes.RealCost > e_ptrs[cur_event].node_cost)
  240.             {
  241.             return (rettype);
  242.             }
  243.          }
  244.       else
  245.          {
  246.          if ((int) newnodedes.RealCost < -(e_ptrs[cur_event].node_cost))
  247.             {
  248.             return (rettype);
  249.             }
  250.          }
  251.       }
  252.  
  253.    /* Is this a non-mail window event? */
  254.    if ((newnodelist || version7) && 
  255.        (!(e_ptrs[cur_event].behavior & MAT_NOMAIL24)))
  256.       {
  257.       /* If this guy can't handle crash, get out and try again */
  258.       if (!(newnodedes.NodeFlags & B_CM))
  259.          {
  260.          return (rettype);
  261.          }
  262.       }
  263.  
  264.    /* Is this a receive only event? */
  265.    if (e_ptrs[cur_event].behavior & MAT_NOOUT)
  266.       {
  267.       return (rettype);
  268.       }
  269.  
  270.    /* Is this a non-CM event? */
  271.    if ((newnodelist || version7) &&
  272.        (e_ptrs[cur_event].behavior & MAT_NOCM) &&
  273.        (newnodedes.NodeFlags & B_CM))
  274.       {
  275.       return (rettype);
  276.       }
  277.  
  278.    /* See if we spent too much calling him already */
  279.    if (bad_call (&(p1->mail_addr), 0))
  280.       {
  281.       p1->mailtypes |= MAIL_TOOBAD;
  282.       return (rettype);
  283.       }
  284.  
  285.    /* See if we have enough mail to send */
  286.    if (!no_size && e_ptrs[cur_event].mailqsize > p1->callsize)
  287.       {
  288.       p1->mailtypes |= MAIL_QSMALL;
  289.       return(rettype);
  290.       }
  291.  
  292.    p1->mailtypes &= ~MAIL_QSMALL;
  293.    p1->mailtypes |= MAIL_WILLGO;
  294.  
  295.    return (rettype);
  296. }
  297.  
  298. char mail_stat (MAILP p)
  299. {
  300.    if (p->mailtypes & MAIL_UNKNOWN)
  301.       return ('!');
  302.    if (p->mailtypes & MAIL_TOOBAD)
  303.       return ('x');
  304.    if (p->mailtypes & MAIL_TRIED)
  305.       return ('#');
  306.    if (p->mailtypes & MAIL_WILLGO)
  307.       return ('*');
  308.    if (p->mailtypes & MAIL_QSMALL)
  309.       return ('<');
  310.    return ('-');
  311. }
  312.  
  313. char *mail_status_chars (unsigned int);
  314.  
  315. char msc[10];
  316.  
  317. char *mail_status_chars (unsigned int p)
  318. {
  319.    char *q;
  320.  
  321.    q = msc;
  322.  
  323.    if (p & MAIL_CRASH  )
  324.       *q++ = 'C';
  325.    if (p & MAIL_HOLD   )
  326.       *q++ = 'H';
  327.    if (p & MAIL_DIRECT )
  328.       *q++ = 'D';
  329.    if (p & MAIL_NORMAL )
  330.       *q++ = 'N';
  331.    if (p & MAIL_REQUEST)
  332.       *q++ = 'R';
  333.    *q++ = '\0';
  334.  
  335.    return (msc);
  336. }
  337.  
  338. void xmit_window (MAILP p1)
  339. {
  340.    MAILP p;
  341.    int i;
  342.    char j1[32];
  343.    char                *jPtr;
  344.  
  345. #ifdef MILQ
  346.    RECT                 Rect;
  347.    int                  Width;
  348. #endif
  349.  
  350.    if (!fullscreen)
  351.       return;
  352.  
  353.    p = p1;
  354.  
  355.    sb_fillc (hold_hWnd, ' ');
  356.    jPtr = j1;
  357. #ifdef MILQ
  358.    GetClientRect( hold_hWnd, &Rect );
  359.    SB_ROW_HOLD = Rect.bottom + 2;
  360.    if ( 30 > ( Width = Rect.right - Rect.left ) )
  361.      jPtr += 30 - Width;
  362. #endif
  363.  
  364.    if (p == NULL)
  365.       {
  366.       sb_move (hold_hWnd, 3, 5);
  367.       SendMessage( hold_hWnd, WM_COMMAND, GD_MODE, 0L );
  368.       SendMessage( hold_hWnd, WM_COMMAND, GD_CLR, 0L );
  369.       sb_puts( hold_Init, MSG_TXT(M_NOTHING_IN_OUTBOUND) );
  370.       return;
  371.       }
  372.  
  373.    SendMessage( hold_hWnd, WM_COMMAND, GD_MODE, 1L );
  374.    SendMessage( hold_hWnd, WM_COMMAND, GD_CLR, 0L );
  375.  
  376. #ifdef MILQ
  377.    if ( hold_hWnd == GetFocus() )
  378.      SendMessage( node_hWnd, WM_COMMAND, GD_PND, (long)&p->mail_addr );
  379. #endif
  380.  
  381.    strcpy( j1, MSG_TXT(M_OUTBOUND_HEADER) );
  382.    sb_move (hold_hWnd, 1, 2);
  383.    sb_puts( hold_Hdr, jPtr);
  384.    for (i = 2; i < SB_ROW_HOLD; i++)
  385.       {
  386.       if (p == NULL)
  387.          break;
  388.  
  389.       do_xmit_line (j1, p);
  390.  
  391.       sb_move (hold_hWnd, i, 2);
  392.       sb_puts( HoldWndDtl(i), jPtr);
  393.       p = p->next;
  394.       }
  395.  
  396.    p = mail_top;
  397.  
  398.    for (; i < SB_ROW_HOLD; i++)
  399.       {
  400.       if ((p == p1) || (p == NULL))
  401.          break;
  402.  
  403.       do_xmit_line (j1, p);
  404.  
  405.       sb_move (hold_hWnd, i, 2);
  406.       sb_puts( HoldWndDtl(i), jPtr);
  407.       p = p->next;
  408.       }
  409.    SendMessage( hold_hWnd, WM_COMMAND, GD_CLR, (long)i );
  410.    sb_show ();
  411. }
  412.  
  413. void do_xmit_line (char *line, MAILP p)
  414. {
  415.    if (no_size)
  416.       {
  417.       (void) sprintf (line, HoldNoSize,
  418.          Full_Addr_Str (&(p->mail_addr)),
  419.          mail_status_chars (p->mailtypes),
  420.          mail_stat (p));
  421.       }
  422.    else
  423.       {
  424.       (void) sprintf (line, HoldFmtStr,
  425.          Full_Addr_Str (&(p->mail_addr)),
  426.          numdisp (p->mailsize),
  427.          mail_status_chars (p->mailtypes),
  428.          mail_stat (p));
  429.       }
  430. }
  431.  
  432.  
  433. void xmit_sort ()
  434. {
  435.    MAILP p, p1, p2;
  436.  
  437.    p = mail_top;
  438.  
  439.    /* Find the first that is sendable */
  440.    while (p != NULL)
  441.       {
  442.       if ((p->mailtypes & MAIL_WILLGO) &&
  443.          (!(p->mailtypes & MAIL_TOOBAD)) &&
  444.          (!(p->mailtypes & MAIL_UNKNOWN)))
  445.          break;
  446.       p = p->next;
  447.       }
  448.  
  449.    if (p == NULL)
  450.       return;
  451.  
  452.    /* Put the first sendable one on top */
  453.    if (p != mail_top)
  454.       {
  455.       p->prev->next = p->next;
  456.       if (p->next != NULL)
  457.          p->next->prev = p->prev;
  458.       p->prev = NULL;
  459.       p->next = mail_top;
  460.       mail_top->prev = p;
  461.       mail_top = p;
  462.       }
  463.  
  464.    p1 = p;
  465.    p = p1->next;
  466.    while (p != NULL)
  467.       {
  468.       if ((p->mailtypes & MAIL_WILLGO) &&
  469.          (!(p->mailtypes & MAIL_TOOBAD)) &&
  470.          (!(p->mailtypes & MAIL_UNKNOWN)))
  471.          {
  472.          if (p->prev == p1)
  473.             {
  474.             p1 = p;
  475.             p = p->next;
  476.             continue;
  477.             }
  478.          p2 = p->next;
  479.          p->prev->next = p->next;
  480.          if (p->next != NULL)
  481.             p->next->prev = p->prev;
  482.          p->next = p1->next;
  483.          if (p1->next != NULL)
  484.             p1->next->prev = p;
  485.          p->prev = p1;
  486.          p1->next = p;
  487.          p1 = p;
  488.          p = p2;
  489.          }
  490.       else
  491.          {
  492.          p = p->next;
  493.          }
  494.       }
  495. }
  496.  
  497. void xmit_reset ()
  498. {
  499.    MAILP p;
  500.    int j, k, done, zone;
  501.    char *q, *s;
  502.    char *domain;
  503.    char *HoldName;
  504.    char pointspec[128];
  505.    ADDR tmp;
  506.    struct FILEINFO zone_dir;
  507.    struct FILEINFO pnt_dir;
  508.    long longzone;
  509.  
  510.    /* First get rid of all the old junk */
  511.    p = mail_top;
  512.    if (p != NULL)
  513.       {
  514.       while (p->next != NULL)
  515.          p = p->next;
  516.       while (p->prev != NULL)
  517.          {
  518.          p = p->prev;
  519.          free (p->next);
  520.          }
  521.       if (p != NULL)
  522.          free (p);
  523.       }
  524.  
  525.    p = mail_top = NULL;
  526.  
  527. /*
  528.  * Initialize domain to scan. Choose (of course) the
  529.  * domain of our primary address.
  530.  *
  531.  * This domain is special in that its outbound is hold_area.
  532.  * All the other domains use their abbreviation as the name
  533.  * of their outbounds.
  534.  */
  535.  
  536.  
  537.    k = 0;
  538.    domain = domain_name[0];
  539.    (void) strcpy (pointspec, hold_area);
  540.    q = &(pointspec[strlen (pointspec)]) - 1;
  541.    do
  542.       {
  543. /*
  544.  * Initialize scan of zones in this domain. Using findfirst/findnext,
  545.  * get all the matching directories.
  546.  */
  547.       (void) strcpy (q, ".*");
  548.       j = 0;
  549.       while (!dfind (&zone_dir, pointspec, j))
  550.          {
  551.          j = 1;                 /* Flip findfirst/findnext to findnext */
  552. /*
  553.  * We have a match on the outbound spec. Make sure it's a directory.
  554.  *
  555.  * Then:
  556.  *
  557.  *       1) If no extension, we may only use it if this is alias 0
  558.  *       2) If an extension, it must be a 3-digit hex number
  559.  *
  560.  * If the extension passes one of these tests, get to work!
  561.  */
  562.          if (!(zone_dir.attr & FA_SUBDIR))
  563.             continue;
  564.  
  565.          q = strchr (zone_dir.name, '.');
  566.          if (q == NULL)
  567.             {
  568.             if (k != 0 && !no_zones)
  569.                continue;
  570.             zone = (int) alias[0].Zone;
  571.             }
  572.          else
  573.             {
  574.             if (no_zones)
  575.                continue;
  576.             s = ++q;
  577.             longzone = strtol (q, &q, 16);
  578.             if ((s + 3) != q)
  579.                continue;
  580.             zone = (int) longzone;
  581.             }
  582. /*
  583.  * OK. We have a domain, an outbound directory, and a zone.
  584.  * That means there's an outbound to scan.
  585.  *
  586.  * Start by scanning the nodes.               
  587.  */
  588.          tmp.Zone = zone;
  589.          tmp.Domain = domain;
  590.          tmp.Net = tmp.Node = tmp.Point = 0;
  591.          p = xmit_find (p, &tmp);
  592. /*
  593.  * Now we do the points contained in this outbound.
  594.  *
  595.  */
  596.          if (pvtnet <= 0)
  597.             {
  598.             HoldName = HoldAreaNameMunge (&tmp);
  599.             (void) sprintf (pointspec, "%s*.PNT", HoldName);
  600.             j = 0;
  601.             done = 0;
  602.  
  603.             while (!done)
  604.                {
  605.                /* See if we have any more at this level */
  606.                if (dfind (&pnt_dir, pointspec, j++))
  607.                   {
  608.                   /* No more at this level, so go to next level */
  609.                   done = 1;
  610.                   }
  611.                else
  612.                   {
  613.                   if (sscanf (pnt_dir.name, "%04x%04x.", &(tmp.Net), &(tmp.Node)) != 2)
  614.                      continue;
  615.                   tmp.Point = 1;
  616.                   p = xmit_find (p, &tmp);
  617.  
  618.                   } /* got one */
  619.                } /* while (!done) */
  620.             }
  621.          } /* while !dfind (...) to get outbounds */
  622. /*
  623.  * See if there are any more domains. If so, set up the right name
  624.  * for the outbound, so we can find 'em.
  625.  */
  626.       if ((domain = domain_name[++k]) != NULL)
  627.          {
  628.          *domain_loc = '\0';
  629.          (void) strcpy (pointspec, domain_area);
  630.          q = &(pointspec[strlen (pointspec)]);
  631.          s = domain_abbrev[k];
  632.          if (s != NULL)
  633.              while (*s)
  634.                  *q++ = *s++;
  635.          }
  636.       } while (domain != NULL);
  637.    next_mail = NULL;
  638.    xmit_sort ();
  639.    xmit_window (mail_top);
  640.    next_rescan = (long) time (NULL) + 600L; /* At least 10 min to next scan */
  641. }
  642.  
  643. MAILP xmit_find (MAILP p, ADDRP address)
  644. {
  645.    int j;
  646.    char next_one [127];
  647.    char *HoldName;
  648.    ADDR tmp;
  649.  
  650.    tmp = *address;
  651.  
  652.    HoldName = HoldAreaNameMunge (address);
  653.  
  654.    if (address->Point != 0)
  655.       {
  656.       (void) sprintf (next_one, "%s%04x%04x.PNT\\*.*",
  657.                 HoldName, address->Net, address->Node);
  658.       tmp.Point = 0;
  659.       }
  660.    else
  661.       {
  662.       (void) sprintf (next_one, "%s*.*", HoldName);
  663.       tmp.Net = 0;
  664.       tmp.Node = 0;
  665.       tmp.Point = 0;
  666.       }
  667.  
  668.    j = 0;
  669.  
  670.    while (!dfind (&dta_str, next_one, j))
  671.       {
  672.       j = 1;
  673.  
  674.       /* We have a match. Was it a .FLO file or a .OUT file? */
  675.       if (strncmp (&(dta_str.name[10]), "LO", 2) == 0)
  676.          {
  677.          /* FLO, DLO, CLO and HLO are the only ones! */
  678.          if (strchr ("FDCH", dta_str.name[9]) == NULL)
  679.              continue;
  680.          }
  681.       else
  682.       if (strncmp (&(dta_str.name[10]), "UT", 2) == 0)
  683.          {
  684.          /* OUT, DUT, CUT and HUT are the only ones! */
  685.          if (strchr ("ODCH", dta_str.name[9]) == NULL)
  686.              continue;
  687.          }
  688.       else
  689.       if (strncmp (&(dta_str.name[9]), "REQ", 3) != 0)
  690.          continue;
  691.  
  692.  
  693.       /* We found a name, remember it */
  694.       if (address->Point != 0)
  695.          {
  696.          if (sscanf (dta_str.name, "%08x.", &(tmp.Point)) != 1)
  697.             continue;
  698.          }
  699.       else if (sscanf (dta_str.name, "%04x%04x.", &(tmp.Net), &(tmp.Node)) != 2)
  700.               continue;
  701.  
  702.       if (p == NULL)
  703.          {
  704.          p = mail_top = (MAILP) calloc (sizeof (MAIL), 1);
  705.          }
  706.       else
  707.          {
  708.          p->next = (MAILP) calloc (sizeof (MAIL), 1);
  709.          p->next->prev = p;
  710.          p = p->next;
  711.          }
  712.  
  713.       if (xmit_install (p, &tmp))
  714.          {
  715.          /* No good */
  716.          if (p->prev != NULL)
  717.             {
  718.             p = p->prev;
  719.             free (p->next);
  720.             p->next = NULL;
  721.             }
  722.          else
  723.             {
  724.             free (p);
  725.             p = mail_top = NULL;
  726.             }
  727.          }
  728.  
  729.       } /* while (!done) */
  730.    return (p);
  731. }
  732.  
  733. int xmit_next (ADDRP xaddr)
  734. {
  735.    int i, j;
  736.  
  737.    for (i = 0; i < 2; i++)
  738.       {
  739.       /* Set up the proper pointer */
  740.       if ((next_mail == NULL) || (next_mail->next == NULL))
  741.          {
  742.          if (next_rescan < (long) time (NULL))
  743.             xmit_reset ();
  744.          next_mail = mail_top;
  745.          }
  746.       else
  747.          {
  748.          next_mail = next_mail->next;
  749.          }
  750.    
  751.       /* Loop through till we find something we can send */
  752.       while (next_mail != NULL)
  753.          {
  754.          if ((next_mail->mailtypes & MAIL_WILLGO) &&
  755.              (!(next_mail->mailtypes & MAIL_UNKNOWN)) &&
  756.              (!(next_mail->mailtypes & MAIL_TOOBAD)))
  757.             {
  758.             if (bad_call (&(next_mail->mail_addr), 0))
  759.                {
  760.                next_mail->mailtypes |= MAIL_TOOBAD;
  761.                }
  762.             else
  763.                {
  764.                /* If multitasking, check for mail before calling */
  765.                if ((TaskNumber != 0) && ((j = any_mail (next_mail)) <= 0))
  766.                   {
  767.                   if (j == 0)
  768.                      xmit_delete ();
  769.                   else next_mail = next_mail->next;
  770.                   continue;
  771.                   }
  772.                *xaddr = next_mail->mail_addr;
  773.                xmit_window (next_mail);
  774.                return (1);
  775.                }
  776.             }
  777.          next_mail = next_mail->next;
  778.          }
  779.       }
  780.    /* Oh well, we tried */
  781.    xmit_window (mail_top);
  782.    return (0);
  783. }
  784.  
  785. void xmit_delete ()
  786. {
  787.    MAILP p;
  788.  
  789.    if (next_mail == NULL)
  790.       return;
  791.  
  792.    if (any_mail (next_mail) != 0)
  793.          {
  794.          status_line (MSG_TXT(M_STILL_HAVE_MAIL), Full_Addr_Str (&(next_mail->mail_addr)));
  795.          /* We still have something for him */
  796.          next_mail->mailtypes &= ~MAIL_WILLGO;
  797.          next_mail->mailtypes |= MAIL_TRIED;
  798.          return;
  799.          }
  800.  
  801.    if (next_mail != mail_top)
  802.       {
  803.       p = next_mail->next;
  804.       next_mail = next_mail->prev;
  805.       free (next_mail->next);
  806.       next_mail->next = p;
  807.       if (p != NULL)
  808.          p->prev = next_mail;
  809.       xmit_window (next_mail);
  810.       }
  811.    else
  812.       {
  813.       mail_top = mail_top->next;
  814.       free (next_mail);
  815.       if (mail_top != NULL)
  816.          mail_top->prev = NULL;
  817.       xmit_window (mail_top);
  818.       next_mail = NULL;
  819.       }
  820. }
  821.  
  822. int bad_call (ADDRP baddr, int rwd)
  823. {
  824.    int res;
  825.    int i, j;
  826.    struct FILEINFO bad_dta;
  827.    FILE *bad_wazoo;
  828.    char *p;
  829.    char *HoldName;
  830.  
  831.    char fname[128];
  832.    char fname1[128];
  833.  
  834.    HoldName = HoldAreaNameMunge(baddr);
  835.    (void) sprintf (fname, "%s%s.$$?", HoldName, Hex_Addr_Str (baddr));
  836.    j = (int) strlen (fname) - 1;                 /* Point at ?          */
  837.    res = -1;                                     /* Initialize to fail  */
  838.  
  839.    i = 0;                                        /* This says findfirst */
  840.    while (!dfind (&bad_dta, fname, i))           /* as long as we match */
  841.       {
  842.       if (isdigit (bad_dta.name[11]))            /* is there a digit?   */
  843.          {
  844.          fname[j] = bad_dta.name[11];            /* Yes, copy to fname  */
  845.          res = fname[j] - '0';                   /* Save it for testing */
  846.          break;                                  /* Get out of while    */
  847.          }
  848.       else i = 1;                                /* Else use findnext   */
  849.       }
  850.  
  851.    if (res == -1)                                /* Successful search?  */
  852.       {
  853.       fname[j] = '0';                            /* No, base digit = 0  */
  854.       }
  855.  
  856.    if (rwd > 0)
  857.       {
  858.       /* Writing a bad call  */
  859.  
  860.       /* First create a filename that is one higher than what we've got */
  861.       (void) strcpy (fname1, fname);
  862.       fname1[j]++;
  863.       if (fname1[j] > '9')
  864.          fname1[j] = '9';
  865.  
  866.       if (res == -1)                             /* Did we have a file? */
  867.          {                                       /* No, make one.       */
  868.          if (rwd == 2)                           /* No carrier */
  869.             res = open (fname, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
  870.          else /* With carrier */
  871.             res = open (fname1, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
  872.          i = rwd - 1;                            /* zero-based count    */
  873.          (void) write (res, (char *) &i, sizeof (int)); /* write it out        */
  874.          (void) close (res);                            /* close the file      */
  875.          }
  876.       else
  877.          {                                       /* There was a file    */
  878.  
  879.          /*
  880.           * 2 = Unsuccessful, No carrier. Update contents of the file.
  881.           */
  882.  
  883.          if (rwd == 2)
  884.             {
  885.             i = open (fname, O_RDONLY|O_BINARY);
  886.             (void) read (i, (char *) &res, sizeof (int));
  887.             (void) close (i);
  888.  
  889.             ++res;
  890.  
  891.             i = open (fname, O_CREAT|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE);
  892.             (void) write (i, (char *) &res, sizeof (int));
  893.             (void) close (i);
  894.             }
  895.  
  896.          /*
  897.           * 1 = Unsuccessful, Carrier. Update file name to reflect the
  898.           * failure.
  899.           */
  900.  
  901.          else
  902.             {
  903.             (void) rename (fname, fname1);
  904.             }
  905.          }
  906.       }
  907.    else if (rwd == 0)
  908.       {
  909.  
  910.       /*
  911.        * 0 = We are reading a bad call status
  912.        */
  913.  
  914.       /* Is it automatically ok (no .$$ file there) ? */
  915.       if (res == -1)
  916.          return (0);
  917.  
  918.       /* Were there too many connects with carrier? */
  919.       if (res >= max_connects)
  920.          return (1);
  921.  
  922.       /* Ok, check for connects without carrier */
  923.       res = 0;
  924.       i = open (fname, O_RDONLY|O_BINARY);
  925.       (void) read (i, (char *) &res, sizeof (int));
  926.       (void) close (i);
  927.       return (res >= max_noconnects);
  928.       }
  929.    else
  930.       {
  931.  
  932.       /*
  933.        * -1 = Cleanup of bad call status. This happens in two steps:
  934.        * a) delete 'netnode.$$?' in hold area;
  935.        * b) if a 'netnode.Z' file exists in hold area,
  936.        *    1) delete all BADWAZOO.xxx files listed in the .Z file;
  937.        *    2) delete the 'netnode.z' file.
  938.        */
  939.  
  940.       if (res != -1)
  941.          {
  942.          (void) unlink (fname);
  943.          }
  944.  
  945.       if (!mail_finished)
  946.          return (0);
  947.  
  948.       (void) sprintf (fname, "%s%s.Z", HoldName, Hex_Addr_Str (baddr));
  949.       if (dexists (fname))
  950.          {
  951.          if ((bad_wazoo = fopen (fname, read_ascii)) == NULL)
  952.             {
  953.             (void) got_error (MSG_TXT(M_OPEN_MSG), fname);
  954.             }
  955.          else
  956.             {
  957.             while (!feof (bad_wazoo))
  958.                {
  959.                e_input[0] = '\0';
  960.                if (!fgets (e_input, 64, bad_wazoo))
  961.                   break;
  962.                /* Point to BADWAZOO.xxx */
  963.                p = strchr (e_input, ' ') + 1;
  964.                /* Then just past it and terminate */
  965.                p = strchr (p, ' ');
  966.                *p = '\0';
  967.                /* Back to where we were */
  968.                p = strchr (e_input, ' ') + 1;
  969.  
  970.                /* Build file name and delete file */
  971.                (void) strcpy (fname1, CURRENT.sc_Inbound);
  972.                (void) strcat (fname1, p);
  973.                (void) unlink (fname1);
  974.                }
  975.             (void) fclose (bad_wazoo);
  976.             }
  977.          (void) unlink (fname);
  978.          }
  979.       }
  980.    return (0);
  981. }
  982.  
  983. void set_up_outbound ()
  984. {
  985.    MAILP mp;
  986.  
  987.    xmit_reset ();
  988.  
  989.    /* and remember where we left off */
  990.    if (hist.next_addr.Net != 0)
  991.       {
  992.       next_addr = hist.next_addr;
  993.       next_addr.Domain = NULL;
  994.       mp = find_mail (&next_addr);
  995.       if ((mp == NULL) || (mp->prev == NULL))
  996.          {
  997.          next_mail = NULL;
  998.          xmit_window (mail_top);
  999.          }
  1000.       else
  1001.          {
  1002.          next_mail = mp->prev;
  1003.          xmit_window (next_mail);
  1004.          }
  1005.       }
  1006.    else
  1007.       {
  1008.       next_addr.Zone = 0;
  1009.       next_addr.Net = 0;
  1010.       next_addr.Node = 0;
  1011.       next_addr.Point = 0;
  1012.       next_addr.Domain = NULL;
  1013.       xmit_window (mail_top);
  1014.       }
  1015. }
  1016. /*
  1017.  * Calculate size of mail queued for outbound.
  1018.  * Used to determine whether or not we have enough
  1019.  * mail to merit an outbound call.
  1020.  *
  1021.  * The original version of this code was donated by Henry Clark.
  1022.  */
  1023.  
  1024. long netsize (MAILP p)
  1025. {
  1026.     struct stat stbuf;
  1027.     char net_path[127];
  1028.     char *ptr;
  1029.     FILE *temp;
  1030.     long accum = 0L;
  1031.     char *q;
  1032.  
  1033.     /* Append the ARCmail file name to the path line  */
  1034.     (void) sprintf (net_path, "%s%s.%s",
  1035.                HoldAreaNameMunge(&(p->mail_addr)),
  1036.                Hex_Addr_Str (&(p->mail_addr)),
  1037.                &dta_str.name[9]);
  1038.  
  1039.     temp = share_fopen (net_path, "rb", DENY_WRITE);
  1040.  
  1041.     if (temp == (FILE *)NULL)
  1042.         return (accum);
  1043.  
  1044.     while (!feof (temp))
  1045.         {
  1046. /*
  1047.  *      Make sure of a nice zero there if we're at an undetected EOF.
  1048.  *      Then try to read a line from the file.
  1049.  */
  1050.         net_path[0] = '\0';
  1051.         (void) fgets (net_path, 79, temp);
  1052. /*
  1053.  *      Clean up anything we don't want to see (blanks, tabs, CR, etc)
  1054.  */
  1055.         for (q = ptr = net_path; *q; q++)
  1056.             if (*q <= ' ')
  1057.                 *q = '\0';
  1058. /*
  1059.  *      File disposition commands should be skipped over to get to
  1060.  *      actual filenames.
  1061.  */
  1062.         if ((*ptr == TRUNC_AFTER)       ||
  1063.             (*ptr == DELETE_AFTER)      ||
  1064.             (*ptr == SHOW_DELETE_AFTER) ||
  1065.             (*ptr == NOTHING_AFTER))
  1066.             ptr++;
  1067. /*
  1068.  *      Now -- if what's left starts with a semicolon, it's a comment.
  1069.  *      If it starts with a tilde, the file has already been sent. If
  1070.  *      what we see is a zero, there's nothing on the line. In any one
  1071.  *      of these cases, we should skip this line.
  1072.  */
  1073.         if ((*ptr == '\0')              ||
  1074.             (*ptr == ';')               ||
  1075.             (*ptr == '~'))
  1076.             continue;
  1077. /*
  1078.  *      Get the file size by doing a stat call. If it's not there
  1079.  *      then we obviously need not add any size in.
  1080.  */
  1081.         if (stat (ptr, &stbuf))            /* file exist? */
  1082.             continue;
  1083.         else accum += stbuf.st_size;
  1084.         }
  1085.     (void) fclose (temp);
  1086.     return (accum);
  1087. }
  1088.  
  1089. /*
  1090.  * Figure out if there's any mail for the specified node.
  1091.  * Used to determine if we need to actually make a call.
  1092.  *
  1093.  * Returns 0 for no mail at all
  1094.  *         1 for non-hold mail
  1095.  *        -1 for hold mail only
  1096.  *
  1097.  * I can't remember who was the first to demand this. I've been
  1098.  * pummelled for a while and there's almost certainly been a loss
  1099.  * of grey matter.
  1100.  */
  1101.  
  1102. int any_mail (MAILP node)
  1103. {
  1104.    struct FILEINFO dta;
  1105.    char next_one [127];
  1106.    int ret = 0;
  1107.  
  1108.    (void) sprintf (next_one, "%s%s.*",
  1109.             HoldAreaNameMunge(&(node->mail_addr)),
  1110.             Hex_Addr_Str (&(node->mail_addr)));
  1111.  
  1112.    if (dfind (&dta, next_one, 0))
  1113.       return (0);
  1114.  
  1115.    do
  1116.       {
  1117. #ifndef JACK_DECKER
  1118.       if (dta.name[9] == 'H')
  1119.          {
  1120.          ret = -1;
  1121.          continue;
  1122.          }
  1123. #endif
  1124.       if (!strncmp (&(dta.name[10]), "LO", 2))
  1125.           return (1);
  1126.  
  1127.       if (!strncmp (&(dta.name[10]), "UT", 2))
  1128.           return (1);
  1129.       } while (!dfind (&dta, next_one, 1));
  1130.  
  1131.    return (ret);
  1132. }
  1133.  
  1134. /*
  1135.  * Create a small character string for mailsize.
  1136.  */
  1137.  
  1138. static char e_shit[6];
  1139. static char *descriptor = "bKMG";
  1140.  
  1141. char *numdisp (long number)
  1142. {
  1143.     int i = 0;
  1144.     char tempstr[6];
  1145.     long quotient, oldq;
  1146.     int intq;
  1147.  
  1148.     oldq = 0L;
  1149.     quotient = number;
  1150.  
  1151.     while (quotient >= 1024L)
  1152.         {
  1153.         oldq = quotient;
  1154.         quotient = oldq / 1024L;
  1155.         i++;
  1156.         }
  1157.  
  1158.     intq = (int) quotient;
  1159.  
  1160.   /*
  1161.    * If more than 999 but less than 1024, it's a big fraction of
  1162.    * the next power of 1024. Get top two significant digits
  1163.    * (so 1023 would come out .99K, for example)
  1164.    */
  1165.  
  1166.  
  1167.     if (intq > 999)
  1168.         {
  1169.         intq = (intq * 25) / 256; /* 100/1024 */
  1170.         (void) sprintf (e_shit, ".%2d%c", intq, descriptor[++i]);
  1171.         }
  1172.   /*
  1173.    * If less than 10 and not small units, then get some decimal
  1174.    * places (e.g. 1.2M)
  1175.    */
  1176.  
  1177.     else if ((intq < 10) && (i != 0))
  1178.        {
  1179.        intq = (int) ((oldq * 5L) / 512L); /* 10/1024 */
  1180.        (void) sprintf (tempstr, "%02d", intq);
  1181.        (void) sprintf (e_shit, "%c.%c%c", tempstr[0], tempstr[1], descriptor[i]);
  1182.        }
  1183.   /*
  1184.    * Simple case. Just do it.
  1185.    */
  1186.  
  1187.     else (void) sprintf (e_shit, "%3d%c", intq, descriptor[i]);
  1188.  
  1189.     return (e_shit);
  1190. }
  1191.  
  1192.