home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / OSKBox.lzh / MAILBOX / CC / suck.c < prev    next >
C/C++ Source or Header  |  1991-10-21  |  14KB  |  716 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <direct.h>
  4. #include <setjmp.h>
  5. #include <signal.h>
  6. #include <modes.h>
  7. #include <errno.h>
  8. #include "mailbox.h"
  9.  
  10. #define REVERSE 1
  11.  
  12. #define MAXPATHS 6            /* maximum number of paths to mailbox */
  13. #define MAXCALLS 3500            /* maximum number of calls to be forwarded */
  14. #define TIMEOUT (3 * 60)    /* maximum # of seconds to wait for response */
  15. #define MAXTIME (20 * 60)    /* maximum # of seconds to forward */
  16. #define MAXBOX 30                /* maximum number of mailboxes */
  17. #define ALARM ((1 << 31) + 60 * 256)
  18.  
  19. struct userstruct user;
  20. char paths[MAXPATHS][80];
  21. char fwdcalls[MAXCALLS][7];
  22. int path_count = 0;
  23. int call_count = 0;
  24. int tnc_in, tnc_out, ctl_in, ctl_out;
  25. jmp_buf disconnected;
  26. int signalman(), quit = 0, interrupt = 0;
  27. int start_fwd, sec;
  28. int bigmail;
  29. char *fwdfile[MAXBOX];
  30. int fwdsize[MAXBOX];
  31. int bid_flag, mid_flag, ok_flag;
  32. extern struct dist_list *distboxes;
  33. char *maildir = "MAIL/";
  34.  
  35. main (argc, argv)
  36. char *argv[];
  37. {
  38.     int i;
  39.  
  40.     if (argc < 2) {
  41.         printf ("No port supplied.\n");
  42.         exit (0);
  43.         }
  44.     if (argc - 2 > MAXBOX) {
  45.         printf ("Too many mailboxes.\n");
  46.         exit (0);
  47.         }
  48.     chdir (HOME);
  49.     strcpy (user.uscall, "AUTOFW");
  50.     user.usopt = ISSUPER;
  51.     intercept (signalman);
  52.     start_fwd = tick();
  53.     read_dist_list ();
  54.     read_fwd_files (argc, argv);
  55.     for (i = 2; i < argc; i++) {
  56.         forward (argv[i], argv[1], fwdfile[i-2], fwdsize[i-2]);
  57.         if (quit) goto exit;
  58.         }
  59. exit: i = i;    /* dummy */
  60.     }
  61.  
  62. forward (mbox, port, file, size)
  63. char *mbox, *port, *file;
  64. int size;
  65. {
  66.     struct msg_header *head;
  67.     int i, flag;
  68.     char str[20], path[90];
  69.     
  70.     read_fwd_file (mbox, file, size);
  71.     open_mail ();
  72.     if (!open_channel (port)) {
  73.         close_mail ();
  74.         return -1;
  75.         }
  76.     bid_flag = mid_flag = ok_flag = 0;
  77.     if (connect (mbox, path)) {
  78.         get_prompt ();
  79.         if (ok_flag) {
  80.             sprintf (str, "%s\n", SID);
  81.             write_path (tnc_out, str);
  82.             get_prompt ();
  83.             }
  84.         if (setjmp (disconnected)) {
  85.             strcpy (user.uscall, "AUTOFW");
  86.             goto exit;
  87.             }
  88.         reverse (mbox);
  89.         disconnect ();
  90.         }
  91. exit:
  92.     close_channel (port);
  93.     close_mail (0);
  94.     }
  95.  
  96. get_prompt ()
  97. {
  98.     char str[256];
  99.     char *f1, *f2, *f3, *f4, *p;
  100.  
  101. printf ("get_prompt\n");
  102.     while (1) {
  103.         get_line (str);
  104.         if ((f1 = strchr (str, '[')) == str && (f2 = strrchr (f1, ']')) &&
  105.                (f3 = strchr (f1, '-')) && f3 < f2 && (f4 = strrchr (f1, '-')) &&
  106.                f4 > f3) {
  107.             ok_flag = 1;
  108.             for (p = f4 + 1; p < f2; p++)
  109.                 switch (*p) {
  110.     case '$':    bid_flag++;  break;
  111.     case 'M':    mid_flag++;  break;
  112.     default:        break;
  113.                     }
  114.             }
  115.         else if ((f1 = strchr (str, '[')) == str && (f2 = strchr (f1, ']'))) {
  116.             *(f1+4) = '\0';
  117.             if (strcmp (f1+1, "MBL" == 0))
  118.                 ok_flag = bid_flag = 1;
  119.             }
  120.         if (str[strlen (str) - 1] == '>')
  121.             return;
  122.         }
  123.     }
  124.  
  125. #ifdef REVERSE
  126. reverse (mbox)
  127. {
  128.     char str[100], *p, w[40], mcall[9];
  129.     struct msg_header *head;
  130.     int date, time, tick;
  131.     short day;
  132.     int f;
  133.     int fromflag, makebid;
  134.     char type, to[7], from[7], bbs[40], bid[13];
  135.  
  136.     strcpy (mcall, mbox);
  137.     get_ssid (mcall);
  138.     strcpy (user.uscall, mcall);
  139.     while (1) {
  140.         write_path (tnc_out, "F>\n");
  141.         get_line (str);
  142.         if (toupper (*str) != 'S') {
  143.             disconnect ();
  144.             return;
  145.             }
  146.         fromflag = 0;
  147.         makebid = 0;
  148.         bbs[0] = '\0';
  149.         bid[0] = '\0';
  150.         p = str;
  151.         p += scanword (p, w, 40);
  152.         type = (isalpha (w[1])) ? toupper (w[1]) : ' ';
  153.         strcpy (from, mcall);
  154.         p += scanword (p, w, 40);
  155.         if (! *w)
  156.             disconnect ();    /* no addressee */
  157.         upper (w);
  158.         get_ssid (w);
  159.         strncpy (to, w, 7);
  160.         p += scanword (p, w, 40);
  161. again:
  162.         while (*w) {
  163.             if (*w == '@') {
  164.                 p += scanword (p, w, 40);
  165.                 if (*w) {
  166.                     upper (w);
  167.                     get_ssid (w);
  168.                     strncpy (bbs, w, 40);
  169.                     p += scanword (p, w, 40);
  170.                     goto again;
  171.                     }
  172.                 }
  173.             else if (*w == '<') {
  174.                 p += scanword (p, w, 40);
  175.                 if (*w) {
  176.                     upper (w);
  177.                     get_ssid (w);
  178.                     if ((user.usopt & ISBBS) || (user.usopt & ISSUPER))
  179.                         strncpy (from, w, 7);
  180.                     p += scanword (p, w, 40);
  181.                     fromflag++;
  182.                     goto again;
  183.                     }
  184.                 }
  185.             else if (*w == '$') {
  186.                 if (strlen (w) == 1) {
  187.                     p += scanword (p, w, 40);
  188.                     if (!*w)
  189.                         makebid++;
  190.                     }
  191.                 else
  192.                     strcpy (w, w+1);
  193.                 if (*w) {
  194.                     upper (w);
  195.                     strncpy (bid, w, 13);
  196.                     p += scanword (p, w, 40);
  197.                     goto again;
  198.                     }
  199.                 }
  200.             }
  201.         if (type == 'T') {
  202.             bid[0] = '\0';
  203.             makebid = 0;
  204.             }
  205.         if (bid[0] && (head = find_bid (bid))) {
  206.             write_path (tnc_out, "NO - duplicate BID\n");
  207.             checkoff (head, mbox);
  208.             continue;
  209.             }
  210.         head = new_mail ();
  211.         head->mhtype = type;
  212.         strcpy (head->mhfrom, from);
  213.         strcpy (head->mhto, to);
  214.         strcpy (head->mhbbs, bbs);
  215.         strcpy (head->mhbid, bid);
  216.         if (ok_flag)
  217.             sprintf (str, "OK %d\n", head->mhnr);
  218.         else
  219.             sprintf (str, "Enter title of message:\n");
  220.         write_path (tnc_out, str);
  221.         get_line (str);
  222.         strncpy (head->mhtit, str, 81);
  223.         strcpy (w, maildir);
  224.         header_to_name (head, w + strlen (maildir));
  225.         if ((f = create (w, S_IWRITE, S_IREAD+S_IWRITE)) == -1) {
  226.             sprintf (str, "Error %d creating message file %s.\n", errno, w);
  227.             write_path (tnc_out, str);
  228.             continue;
  229.             }
  230.         if (!ok_flag) {
  231.             sprintf (str, "Enter the message, ^Z to end.  It will be number %d\n",
  232.                 head->mhnr);
  233.             write_path (tnc_out, str);
  234.             }
  235.         if (getfile (f))
  236.             write (f, "\n", 1);
  237.         head->mhsize = _gs_size (f);
  238.         close (f);
  239.         header_to_name (head, w);
  240.         head->mhstat = 'N';
  241.         if (makebid && !head->mhbid[0])
  242.             sprintf (head->mhbid, "%d_%s", head->mhnr, MYCALL);
  243.         checkoff (head, mbox);
  244.         update_mail ();
  245.         log_send (head, fromflag);
  246.         }
  247.     }
  248.  
  249. getfile (f)
  250. {
  251.     char line[300], *p;
  252.     int len, alarm, time = 0;
  253.  
  254.     time = tick ();
  255.     while (!quit) {
  256.         if (_gs_rdy (ctl_in) > 0)
  257.             check_status ();
  258.         if (_gs_rdy (tnc_in) > 0) {
  259.             time = tick ();
  260.             alarm = alm_set (SIGINT, ALARM);
  261.             len = readln (tnc_in, line, 256);
  262.             alm_delete (alarm);
  263.             line[len] = '\0';
  264. printf ("%s", line);            
  265.             for (p = line; p - line < len; p++)
  266.                 if (*p == '\032') {
  267.                     write (f, line, p-line);
  268.                     goto exit;
  269.                     }
  270.             write (f, line, len);
  271.             }
  272.         else
  273.             sleep (3);
  274.         if ((tick() - time) / sec > TIMEOUT) {
  275. printf ("TIMEOUT\n");
  276.             write_path (ctl_out, "D\n");
  277.             time = tick ();
  278.             }
  279.         }
  280. exit:
  281.     return (p-line);
  282.     }
  283. #endif /* REVERSE */
  284.  
  285. get_line (str)
  286. char *str;
  287. {
  288.     int len;
  289.     int time = 0;
  290.     int status_disp, data_disp, data_send, data_ack, tries, state;
  291.  
  292.     time = tick ();
  293.     data_send = data_ack = -1;
  294.     while (1) {
  295.         if (data_send || data_ack) {
  296.             write_path (ctl_out, "L\n");
  297.             do read_path (ctl_in, str, 80); while (str[0] == '(');
  298. printf ("status %s\n", str);
  299.             scan_status (str, &status_disp, &data_disp, &data_send, 
  300.                                     &data_ack, &tries, &state);
  301.             if (state == 0 || quit)
  302.                 longjmp (disconnected, 2);
  303.             if (data_send || data_ack)
  304.                 time = tick ();
  305.             }
  306.         else if (_gs_rdy (ctl_in) > 0)
  307.             check_status ();
  308.         if (_gs_rdy (tnc_in) > 0) {
  309.             read_path (tnc_in, str, 256);
  310. printf ("get_line: '%s'\n", str);
  311.             return;
  312.             }
  313.         sleep (3);
  314.         if ((tick() - time) / sec > TIMEOUT) {
  315. printf ("TIMEOUT\n");
  316.             write_path (ctl_out, "D\n");
  317.             time = tick ();
  318.             }
  319.         }
  320.     }
  321.  
  322. disconnect ()
  323. {
  324. printf ("disconnect\n");
  325.     write_path (ctl_out, "D\n");
  326.     while (!check_disconnect ())
  327.         ;
  328.     }
  329.  
  330. check_status ()
  331. {
  332.     if (check_disconnect ())
  333.         longjmp (disconnected, 1);
  334.     }
  335.  
  336. check_disconnect ()
  337. {
  338.     char str[80];
  339.     char *p, w[20];
  340.     int len;
  341.  
  342.     read_path (ctl_in, str, 80);
  343. printf ("%s\n", str);
  344.     p = str;
  345.     p += scanword (p, w, 20);
  346.     if (strcmp (w, "CHANNEL") == 0) {
  347.         p += scanword (p, w, 20);
  348.         if (strcmp (w, "NOT") == 0) {
  349.             p += scanword (p, w, 20);
  350.             return (strcmp (w, "CONNECTED") == 0);
  351.             }
  352.         else
  353.             return 0;
  354.         }
  355.     else {
  356.         p += scanword (p, w, 20);
  357.         if (strcmp (w, "LINK") == 0) {
  358.             p += scanword (p, w, 20);
  359.             if (strcmp (w, "FAILURE") != 0)
  360.                 return 0;
  361.             }
  362.         else if (strcmp (w, "DISCONNECTED") != 0)
  363.                 return 0;
  364.         }
  365.     return 1;
  366.     }
  367.  
  368. connect (mbox, path)
  369. char *mbox, *path;
  370. {
  371.     int i;
  372.     char str[90];
  373.  
  374.     if (path_count == 0) {
  375.         strcpy (path, mbox);
  376.         return (try_connect (mbox) == 1);
  377.         }
  378.     else
  379.         for (i = 0; i < path_count; i++) {
  380.             sprintf (str, "%s %s", mbox, paths[i]);
  381.             switch (try_connect (str)) {
  382.         case 0:    break;
  383.         case 1:    strcpy (path, str);
  384.                 return 1;
  385.         case -1:return 0;
  386.                 }
  387.             }
  388.     return 0;
  389.     }
  390.  
  391. try_connect (fpath)
  392. char *fpath;
  393. {
  394.     char str[95], w[20], *p;
  395.     int len;
  396.     int tries = 0;
  397.  
  398. printf ("try_connect %s\n", fpath);
  399.     for (p = fpath; *p; p++)
  400.         if (*p == '*') break;
  401.     if (*p)
  402.         return (netrom (fpath));
  403.     sprintf (str, "C %s\n", fpath);
  404.     write_path (ctl_out, str);
  405.     read_path (ctl_in, str, 95);
  406. printf ("%s\n", str);
  407.     p = str + scanword (str, w, 20);
  408.     p += scanword (p, w, 20);
  409.     if (strcmp (w, "CONNECTED") == 0)
  410.         return 1;
  411.     else if (strcmp (w, "BUSY") == 0 || strcmp (w, "STATION") == 0) {
  412.         return -1;
  413.         }
  414.     else
  415.         return 0;
  416.     }
  417.  
  418. netrom (fpath)
  419. char *fpath;
  420. {
  421.     char w[20], digis[10][12], str[95], str2[256], *p;
  422.     int i, j, k, dcount, tries;
  423.  
  424. printf ("netrom %s\n", fpath);
  425.     p = fpath;
  426.     p += scanword (p, w, 10);
  427.     dcount = 0;
  428.     do {
  429.         p += scanword (p, digis[dcount], 12);
  430.         } while (digis[dcount++][0]);
  431.     strcpy (digis[dcount-1], w);
  432.     for (i = 0; i < dcount-1; i++)
  433.         if (digis[i][0] == '*') break;
  434.     sprintf (str, "C %s", (digis[i][0] == '*') ? digis[i] + 1 : digis[i]);
  435.     for (j = 0; j < i; j++) {
  436.         strcat (str, " ");
  437.         if (digis[j][0] == '*')
  438.             strcat (str, digis[j] + 1);
  439.         else
  440.             strcat (str, digis[j]);
  441.         }
  442.     strcat (str, "\n");
  443.     write_path (ctl_out, str);
  444.     read_path (ctl_in, str, 95);
  445. printf ("  %s\n", str);
  446.     p = str + scanword (str, w, 20);
  447.     p += scanword (p, w, 20);
  448.     if (strcmp (w, "CONNECTED") != 0)
  449.         return 0;
  450.     i++;
  451.     while (i < dcount) {
  452.         for (j = i; j < dcount-1; j++)
  453.             if (digis[j][0] == '*') break;
  454.         sprintf (str, "C %s", (digis[j][0] == '*') ? digis[j] + 1 : digis[j]);
  455.         for (k = i; k < j; k++) {
  456.             strcat (str, " ");
  457.             if (digis[k][0] == '*')
  458.                 strcat (str, digis[k] + 1);
  459.             else
  460.                 strcat (str, digis[k]);
  461.             }
  462.         if (strcmp (str, "C ") == 0)
  463.             strcpy (str, "BBS");
  464.         strcat (str, "\n");
  465.         tries = 0;
  466. again:    write_path (tnc_out, str);
  467.         get_line (str2);
  468.         p = str2 + scanword (str2, w, 20);
  469.         p += scanword (p, w, 20);
  470.         if (strcmp (w, "Busy") == 0) {
  471. /*
  472.             if (strcmp (digis[dcount-1], "W0RLI") == 0) {disconnect(); return -1;}
  473.             if (++tries > 4) {
  474.                 disconnect ();
  475.                 return -1;
  476.                 }
  477.             sleep (60);
  478.             goto again;
  479. */
  480.             disconnect (); return -1;
  481.             }
  482.         else if (strcmp (w, "Connected") != 0) {
  483.             disconnect ();
  484.             return 0;
  485.             }
  486.         i = j + 1;
  487.         if (i == dcount - 1 && strcmp (digis[j], "*") == 0)
  488.             break;
  489.         }
  490.     return 1;
  491.     }
  492.  
  493. open_channel (port)
  494. char *port;
  495. {
  496.     int hostcmd;
  497.     int i, pid;
  498.     char str[40];
  499.  
  500.     strcpy (str, "/pipe/command.");
  501.     strcat (str, port);
  502.     if ((hostcmd = open (str, 2)) < 0)
  503.         return (0);
  504.     pid = getpid ();
  505.     sprintf (str, "o%d\n", pid);
  506.     write_path (hostcmd, str);
  507.     close (hostcmd);
  508.     sprintf (str, "/pipe/data_in.%d", pid);
  509.     for (i = 0; i < 10; i++) {
  510.         if ((tnc_in = open (str, 3)) != -1) break;
  511.         sleep (1);
  512.         }
  513.     if (tnc_in == -1)
  514.         return (0);
  515.     sprintf (str, "/pipe/data_out.%d", pid);
  516.     tnc_out = open (str, 3);
  517.     sprintf (str, "/pipe/ctl_in.%d", pid);
  518.     ctl_in = open (str, 3);
  519.     sprintf (str, "/pipe/ctl_out.%d", pid);
  520.     ctl_out = open (str, 3);
  521.     return (1);
  522.     }
  523.  
  524. close_channel (port)
  525. char *port;
  526. {
  527.     int hostcmd;
  528.     int i, j, pid;
  529.     char str[40];
  530.  
  531.     strcpy (str, "/pipe/command.");
  532.     strcat (str, port);
  533.     if ((hostcmd = open (str, 2)) < 0)
  534.         return (0);
  535.     pid = getpid ();
  536.     sprintf (str, "c%d\n", pid);
  537.     write_path (hostcmd, str);
  538.     close (hostcmd);
  539.     sleep (5);
  540.     drain (tnc_in);
  541.     drain (tnc_out);
  542.     drain (ctl_in);
  543.     drain (ctl_out);
  544.     close (tnc_in);
  545.     close (tnc_out);
  546.     close (ctl_in);
  547.     close (ctl_out);
  548.     sprintf (str, "/pipe/data_in.%d", pid);
  549.     for (i = 0; i < 10; i++) {
  550.         if (access (str, 0) == -1) break;
  551.         sleep (1);
  552.         }
  553.     if (i == 10) return 0;
  554.     return (1);
  555.     }
  556.  
  557. drain (path)
  558. {
  559.     int i, j;
  560.     char c;
  561.  
  562.     while ((i = _gs_rdy (path)) > 0) {
  563.         for (j = 0; j < i; j++)
  564.             read (path, &c, 1);
  565.         sleep (1);
  566.         }
  567.     }
  568.  
  569. write_path (path, str)
  570. char *str;
  571. {
  572.     write (path, str, strlen (str));
  573. if (path == tnc_out) writeln (1, str, strlen (str));
  574.     }
  575.  
  576. read_path (path, str, len)
  577. char *str;
  578. {
  579.     int i;
  580.     i = readln (path, str, len);
  581.     if (i)
  582.         str[i-1] = '\0';
  583.     return i;
  584.     }
  585.  
  586. read_fwd_file (mbox, file, size)
  587. char *mbox, *file;
  588. {
  589.     char str[80], w[7], *p, *p2;
  590.     int i, f, len;
  591.  
  592. printf ("read_fwd_file %s\n", mbox);
  593.     path_count = call_count = 0;
  594.     strcpy (str, mbox);
  595.     get_ssid (str);
  596.     strcpy (fwdcalls[call_count++], str);
  597.     for (p2 = file; p2 < file + size; p2 += strlen (p2) + 1) {
  598.         strcpy (str, p2);
  599.         p = str + scanword (str, w, 7);
  600.         if (strcmp (w, "VIA") == 0) {
  601.             while (isspace (*p))
  602.                 p++;
  603.             if (path_count < MAXPATHS)
  604.                 strcpy (paths[path_count++], p);
  605.             }
  606.         else if (*w && *w != '@' && *w != ';') {
  607.             get_ssid (w);
  608.             if (call_count < MAXCALLS)
  609.                 strcpy (fwdcalls[call_count++], w);
  610.             }
  611.         }
  612.     }
  613.  
  614. read_fwd_files (argc, argv)
  615. char *argv[];
  616. {
  617.     char str[80], w[7], *p;
  618.     int i, f, len;
  619.     char *mbox;
  620.  
  621.     for (i = 2; i < argc; i++) {
  622.         mbox = argv[i];
  623.         upper (mbox);
  624.         strcpy (str, mbox);
  625.         for (p = str; *p; p++)
  626.             if (*p == '-')
  627.                 *p = '_';
  628.         strcat (str, ".fwd");
  629.         fwdfile[i-2] = (char *)malloc (1);
  630.         fwdsize[i-2] = read_file (str, &fwdfile[i-2], 0);
  631.         }
  632.     return (1);
  633.     }
  634.  
  635. read_file (name, pptr, size)
  636. char *name, **pptr;
  637. {
  638.     int f, fsize, tsize;
  639.     char *fptr, *p, line[80];
  640.     
  641.     if (*name == '/')
  642.         strcpy (line, name);
  643.     else
  644.         sprintf (line, "%s/%s", FWDIR, name);
  645.     if ((f = open (line, 1)) < 0)
  646.         return (size);
  647.     fsize = _gs_size (f);
  648.     fptr = (char *)malloc (size + fsize);
  649.     if (size) movmem (*pptr, fptr, size);
  650.     read (f, fptr + size, fsize);
  651.     close (f);
  652.     for (p = fptr + size; p - fptr < size + fsize; p++) {
  653.         *p = toupper (*p);
  654.         if (*p == '\n')
  655.             *p = '\0';
  656.         }
  657.     free (*pptr);
  658.     *pptr = fptr;
  659.     tsize = size + fsize;
  660.     for (p = fptr + size; p - fptr < size + fsize; p += strlen (p) + 1) {
  661.         if (*p == '@') {
  662.             strcpy (line, p+1);
  663.             tsize = read_file (line, pptr, tsize);
  664.             p = *pptr + (p - fptr);
  665.             fptr = *pptr;
  666.             }
  667.         }
  668.     return (tsize);
  669.     }
  670.     
  671. signalman (signal)
  672. {
  673.     switch (signal) {
  674. case SIGQUIT:
  675.         quit = 1;
  676.         break;
  677. case SIGINT:
  678.         interrupt = 1;
  679.         break;
  680. default:
  681.         break;
  682.         
  683.         }
  684.     }
  685.  
  686. tick ()
  687. {
  688.     int time, date, i_tick;
  689.     short day;
  690.  
  691.     _sysdate (3, &time, &date, &day, &i_tick);
  692.     sec = i_tick >> 16;
  693.     return (time * sec + (i_tick & 0xFFFF));
  694.     }
  695.  
  696. scan_status (s, a, b, c, d, x, f)
  697. char *s;
  698. int *a, *b, *c, *d, *x, *f;
  699. {
  700.     char *p, w[20];
  701.  
  702.     p = s;
  703.     p += scanword (p, w, 20);
  704.     *a = atoi (w);
  705.     p += scanword (p, w, 20);
  706.     *b = atoi (w);
  707.     p += scanword (p, w, 20);
  708.     *c = atoi (w);
  709.     p += scanword (p, w, 20);
  710.     *d = atoi (w);
  711.     p += scanword (p, w, 20);
  712.     *x = atoi (w);
  713.     p += scanword (p, w, 20);
  714.     *f = atoi (w);
  715.     }
  716.