Annotation of coherent/g/usr/lib/uucp/tay104/cu.c, revision 1.1.1.1

1.1       root        1: /* cu.c
                      2:    Call up a remote system.
                      3: 
                      4:    Copyright (C) 1992 Ian Lance Taylor
                      5: 
                      6:    This file is part of the Taylor UUCP package.
                      7: 
                      8:    This program is free software; you can redistribute it and/or
                      9:    modify it under the terms of the GNU General Public License as
                     10:    published by the Free Software Foundation; either version 2 of the
                     11:    License, or (at your option) any later version.
                     12: 
                     13:    This program is distributed in the hope that it will be useful, but
                     14:    WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     16:    General Public License for more details.
                     17: 
                     18:    You should have received a copy of the GNU General Public License
                     19:    along with this program; if not, write to the Free Software
                     20:    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     21: 
                     22:    The author of the program may be contacted at [email protected] or
                     23:    c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
                     24:    */
                     25: 
                     26: #include "uucp.h"
                     27: 
                     28: #if USE_RCS_ID
                     29: const char cu_rcsid[] = "$Id: cu.c,v 1.1 93/07/30 07:53:00 bin Exp Locker: bin $";
                     30: #endif
                     31: 
                     32: #include "cu.h"
                     33: #include "uudefs.h"
                     34: #include "uuconf.h"
                     35: #include "conn.h"
                     36: #include "prot.h"
                     37: #include "system.h"
                     38: #include "sysdep.h"
                     39: #include "getopt.h"
                     40: 
                     41: #include <stdio.h>
                     42: #include <ctype.h>
                     43: #include <errno.h>
                     44: 
                     45: /* Here are the user settable variables.  The user is permitted to
                     46:    change these while running the program, using ~s.  */
                     47: 
                     48: /* The escape character used to introduce a special command.  The
                     49:    escape character is the first character of this string.  */
                     50: const char *zCuvar_escape = "~";
                     51: 
                     52: /* Whether to delay for a second before printing the host name after
                     53:    seeing an escape character.  */
                     54: boolean fCuvar_delay = TRUE;
                     55: 
                     56: /* The input characters which finish a line.  The escape character is
                     57:    only recognized following one of these characters.  The default is
                     58:    carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the
                     59:    Ultrix /etc/remote file.  */
                     60: const char *zCuvar_eol = "\r\025\003\017\004\023\021\022";
                     61: 
                     62: /* Whether to transfer binary data (nonprintable characters other than
                     63:    newline and tab) when sending a file.  If this is FALSE, then
                     64:    newline is changed to carriage return.  */
                     65: boolean fCuvar_binary = FALSE;
                     66: 
                     67: /* A prefix string to use before sending a binary character from a
                     68:    file; this is only used if fCuvar_binary is TRUE.  The default is
                     69:    ^Z. */
                     70: const char *zCuvar_binary_prefix = "\026";
                     71: 
                     72: /* Whether to check for echoes of characters sent when sending a file.
                     73:    This is ignored if fCuvar_binary is TRUE.  */
                     74: boolean fCuvar_echocheck = FALSE;
                     75: 
                     76: /* A character to look for after each newline is sent when sending a
                     77:    file.  The character is the first character in this string, except
                     78:    that a '\0' means that no echo check is done.  */
                     79: const char *zCuvar_echonl = "\r";
                     80: 
                     81: /* The timeout to use when looking for an character.  */
                     82: int cCuvar_timeout = 30;
                     83: 
                     84: /* The character to use to kill a line if an echo check fails.  The
                     85:    first character in this string is sent.  The default is ^U.  */
                     86: const char *zCuvar_kill = "\025";
                     87: 
                     88: /* The number of times to try resending a line if the echo check keeps
                     89:    failing.  */
                     90: int cCuvar_resend = 10;
                     91: 
                     92: /* The string to send at the end of a file sent with ~>.  The default
                     93:    is ^D.  */
                     94: const char *zCuvar_eofwrite = "\004";
                     95: 
                     96: /* The string to look for to finish a file received with ~<.  For tip
                     97:    this is a collection of single characters, but I don't want to do
                     98:    that because it means that there are characters which cannot be
                     99:    received.  The default is a guess at a typical shell prompt.  */
                    100: const char *zCuvar_eofread = "$";
                    101: 
                    102: /* Whether to provide verbose information when sending or receiving a
                    103:    file.  */
                    104: boolean fCuvar_verbose = TRUE;
                    105: 
                    106: /* The table used to give a value to a variable, and to print all the
                    107:    variable values.  */
                    108: 
                    109: static const struct uuconf_cmdtab asCuvars[] =
                    110: {
                    111:   { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL },
                    112:   { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL },
                    113:   { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL },
                    114:   { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL },
                    115:   { "binary-prefix", UUCONF_CMDTABTYPE_STRING,
                    116:       (pointer) &zCuvar_binary_prefix, NULL },
                    117:   { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN,
                    118:       (pointer) &fCuvar_echocheck, NULL },
                    119:   { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL },
                    120:   { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL },
                    121:   { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL },
                    122:   { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL },
                    123:   { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL },
                    124:   { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL },
                    125:   { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL },
                    126:   { NULL, 0, NULL, NULL}
                    127: };
                    128: 
                    129: /* The program name.  */
                    130: char abProgram[] = "cu";
                    131: 
                    132: /* The string printed at the initial connect.  */
                    133: #if ANSI_C
                    134: #define ZCONNMSG "\aConnected."
                    135: #else
                    136: #define ZCONNMSG "Connected."
                    137: #endif
                    138: 
                    139: /* The string printed when disconnecting.  */
                    140: #if ANSI_C
                    141: #define ZDISMSG "\aDisconnected."
                    142: #else
                    143: #define ZDISMSG "Disconnected."
                    144: #endif
                    145: 
                    146: /* Local variables.  */
                    147: 
                    148: /* The string we print when the user is once again connected to the
                    149:    port after transferring a file or taking some other action.  */
                    150: static const char abCuconnected[]
                    151: #if ANSI_C
                    152:   = "\a[connected]";
                    153: #else
                    154:   = "[connected]";
                    155: #endif
                    156: 
                    157: /* Global uuconf pointer.  */
                    158: static pointer pCuuuconf;
                    159: 
                    160: /* Connection.  */
                    161: static struct sconnection *qCuconn;
                    162: 
                    163: /* Whether to close the connection.  */
                    164: static boolean fCuclose_conn;
                    165: 
                    166: /* Dialer used to dial out.  */
                    167: static struct uuconf_dialer *qCudialer;
                    168: 
                    169: /* Whether we need to restore the terminal.  */
                    170: static boolean fCurestore_terminal;
                    171: 
                    172: /* Whether we are doing local echoing.  */
                    173: static boolean fCulocalecho;
                    174: 
                    175: /* Whether we need to call fsysdep_cu_finish.  */
                    176: static boolean fCustarted;
                    177: 
                    178: /* A structure used to pass information to icuport_lock.  */
                    179: struct sconninfo
                    180: {
                    181:   boolean fmatched;
                    182:   boolean flocked;
                    183:   struct sconnection *qconn;
                    184:   const char *zline;
                    185: };
                    186: 
                    187: /* Local functions.  */
                    188: 
                    189: static void ucuusage P((void));
                    190: static void ucuabort P((void));
                    191: static void uculog_start P((void));
                    192: static void uculog_end P((void));
                    193: static int icuport_lock P((struct uuconf_port *qport, pointer pinfo));
                    194: static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn,
                    195:                            int bcmd));
                    196: static boolean fcuset_var P((pointer puuconf, char *zline));
                    197: static int icuunrecogvar P((pointer puuconf, int argc, char **argv,
                    198:                            pointer pvar, pointer pinfo));
                    199: static int icuunrecogfn P((pointer puuconf, int argc, char **argv,
                    200:                           pointer pvar, pointer pinfo));
                    201: static void uculist_vars P((void));
                    202: static void uculist_fns P((const char *zescape));
                    203: static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn,
                    204:                               char *zline));
                    205: static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
                    206:                              size_t cbuf));
                    207: 
                    208: #define ucuputs(zline) \
                    209:        do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
                    210: 
                    211: /* Long getopt options.  */
                    212: static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } };
                    213: 
                    214: int
                    215: main (argc, argv)
                    216:      int argc;
                    217:      char **argv;
                    218: {
                    219:   /* -c: phone number.  */
                    220:   char *zphone = NULL;
                    221:   /* -e: even parity.  */
                    222:   boolean feven = FALSE;
                    223:   /* -l: line.  */
                    224:   char *zline = NULL;
                    225:   /* -n: prompt for phone number.  */
                    226:   boolean fprompt = FALSE;
                    227:   /* -o: odd parity.  */
                    228:   boolean fodd = FALSE;
                    229:   /* -p: port name.  */
                    230:   const char *zport = NULL;
                    231:   /* -s: speed.  */
                    232:   long ibaud = 0L;
                    233:   /* -t: map cr to crlf.  */
                    234:   boolean fmapcr = FALSE;
                    235:   /* -z: system.  */
                    236:   const char *zsystem = NULL;
                    237:   /* -I: configuration file name.  */
                    238:   const char *zconfig = NULL;
                    239:   int iopt;
                    240:   pointer puuconf;
                    241:   int iuuconf;
                    242:   const char *zlocalname;
                    243:   int i;
                    244:   struct uuconf_system ssys;
                    245:   const struct uuconf_system *qsys = NULL;
                    246:   boolean flooped;
                    247:   struct uuconf_port sport;
                    248:   struct sconnection sconn;
                    249:   struct sconninfo sinfo;
                    250:   long ihighbaud;
                    251:   struct uuconf_dialer sdialer;
                    252:   struct uuconf_dialer *qdialer;
                    253:   char bcmd;
                    254: 
                    255:   /* We want to accept -# as a speed.  It's easiest to look through
                    256:      the arguments, replace -# with -s#, and let getopt handle it.  */
                    257:   for (i = 1; i < argc; i++)
                    258:     {
                    259:       if (argv[i][0] == '-'
                    260:          && isdigit (BUCHAR (argv[i][1])))
                    261:        {
                    262:          size_t clen;
                    263:          char *z;
                    264: 
                    265:          clen = strlen (argv[i]);
                    266:          z = zbufalc (clen + 2);
                    267:          z[0] = '-';
                    268:          z[1] = 's';
                    269:          memcpy (z + 2, argv[i] + 1, clen);
                    270:          argv[i] = z;
                    271:        }
                    272:     }
                    273: 
                    274:   while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:",
                    275:                              asCulongopts, (int *) NULL)) != EOF)
                    276:     {
                    277:       switch (iopt)
                    278:        {
                    279:        case 'c':
                    280:          /* Phone number.  */
                    281:          zphone = optarg;
                    282:          break;
                    283: 
                    284:        case 'd':
                    285:          /* Set debugging level to maximum.  */
                    286: #if DEBUG > 1
                    287:          iDebug = DEBUG_MAX;
                    288: #endif
                    289:          break;
                    290: 
                    291:        case 'e':
                    292:          /* Even parity.  */
                    293:          feven = TRUE;
                    294:          break;
                    295: 
                    296:        case 'h':
                    297:          /* Local echo.  */
                    298:          fCulocalecho = TRUE;
                    299:          break;
                    300: 
                    301:        case 'n':
                    302:          /* Prompt for phone number.  */
                    303:          fprompt = TRUE;
                    304:          break;
                    305: 
                    306:        case 'l':
                    307:          /* Line name.  */
                    308:          zline = optarg;
                    309:          break;
                    310: 
                    311:        case 'o':
                    312:          /* Odd parity.  */
                    313:          fodd = TRUE;
                    314:          break;
                    315: 
                    316:        case 'p':
                    317:        case 'a':
                    318:          /* Port name (-a is for compatibility).  */
                    319:          zport = optarg;
                    320:          break;
                    321: 
                    322:        case 's':
                    323:          /* Speed.  */
                    324:          ibaud = strtol (optarg, (char **) NULL, 10);
                    325:          break;
                    326: 
                    327:        case 't':
                    328:          /* Map cr to crlf.  */
                    329:          fmapcr = TRUE;
                    330:          break;
                    331: 
                    332:        case 'z':
                    333:          /* System name.  */
                    334:          zsystem = optarg;
                    335:          break;
                    336: 
                    337:        case 'I':
                    338:          /* Configuration file name.  */
                    339:          if (fsysdep_other_config (optarg))
                    340:            zconfig = optarg;
                    341:          break;
                    342: 
                    343:        case 'x':
                    344: #if DEBUG > 1
                    345:          /* Set debugging level.  */
                    346:          iDebug |= idebug_parse (optarg);
                    347: #endif
                    348:          break;
                    349: 
                    350:        case 0:
                    351:          /* Long option found and flag set.  */
                    352:          break;
                    353: 
                    354:        default:
                    355:          ucuusage ();
                    356:          break;
                    357:        }
                    358:     }
                    359: 
                    360:   /* There can be one more argument, which is either a system name, a
                    361:      phone number, or "dir".  We decide which it is based on the first
                    362:      character.  To call a UUCP system whose name begins with a digit,
                    363:      or one which is named "dir", you must use -z.  */
                    364:   if (optind != argc)
                    365:     {
                    366:       if (optind != argc - 1
                    367:          || zsystem != NULL
                    368:          || zphone != NULL)
                    369:        ucuusage ();
                    370:       if (strcmp (argv[optind], "dir") != 0)
                    371:        {
                    372:          if (isdigit (BUCHAR (argv[optind][0])))
                    373:            zphone = argv[optind];
                    374:          else
                    375:            zsystem = argv[optind];
                    376:        }
                    377:     }
                    378: 
                    379:   /* If the user doesn't give a system, port, line or speed, then
                    380:      there's no basis on which to select a port.  */
                    381:   if (zsystem == NULL
                    382:       && zport == NULL
                    383:       && zline == NULL
                    384:       && ibaud == 0L)
                    385:     ucuusage ();
                    386: 
                    387:   if (fprompt)
                    388:     {
                    389:       size_t cphone;
                    390: 
                    391:       printf ("Phone number: ");
                    392:       (void) fflush (stdout);
                    393:       zphone = NULL;
                    394:       cphone = 0;
                    395:       if (getline (&zphone, &cphone, stdin) <= 0
                    396:          || *zphone == '\0')
                    397:        {
                    398:          fprintf (stderr, "%s: No phone number entered\n", abProgram);
                    399:          exit (EXIT_FAILURE);
                    400:        }
                    401:     }
                    402: 
                    403:   iuuconf = uuconf_init (&puuconf, "cu", zconfig);
                    404:   if (iuuconf != UUCONF_SUCCESS)
                    405:     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    406:   pCuuuconf = puuconf;
                    407: 
                    408: #if DEBUG > 1
                    409:   {
                    410:     const char *zdebug;
                    411: 
                    412:     iuuconf = uuconf_debuglevel (puuconf, &zdebug);
                    413:     if (iuuconf != UUCONF_SUCCESS)
                    414:       ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    415:     if (zdebug != NULL)
                    416:       iDebug |= idebug_parse (zdebug);
                    417:   }
                    418: #endif
                    419: 
                    420:   usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID);
                    421: 
                    422:   iuuconf = uuconf_localname (puuconf, &zlocalname);
                    423:   if (iuuconf == UUCONF_NOT_FOUND)
                    424:     {
                    425:       zlocalname = zsysdep_localname ();
                    426:       if (zlocalname == NULL)
                    427:        exit (EXIT_FAILURE);
                    428:     }
                    429:   else if (iuuconf != UUCONF_SUCCESS)
                    430:     ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    431: 
                    432:   ulog_fatal_fn (ucuabort);
                    433:   pfLstart = uculog_start;
                    434:   pfLend = uculog_end;
                    435: 
                    436: #ifdef SIGINT
                    437:   usysdep_signal (SIGINT);
                    438: #endif
                    439: #ifdef SIGHUP
                    440:   usysdep_signal (SIGHUP);
                    441: #endif
                    442: #ifdef SIGQUIT
                    443:   usysdep_signal (SIGQUIT);
                    444: #endif
                    445: #ifdef SIGTERM
                    446:   usysdep_signal (SIGTERM);
                    447: #endif
                    448: #ifdef SIGPIPE
                    449:   usysdep_signal (SIGPIPE);
                    450: #endif
                    451: 
                    452:   if (zsystem != NULL)
                    453:     {
                    454:       iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
                    455:       if (iuuconf != UUCONF_SUCCESS)
                    456:        {
                    457:          if (iuuconf != UUCONF_NOT_FOUND)
                    458:            ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    459:          ulog (LOG_FATAL, "%s: System not found", zsystem);
                    460:        }
                    461:       qsys = &ssys;
                    462:     }
                    463: 
                    464:   /* This loop is used if a system is specified.  It loops over the
                    465:      various alternates until it finds one for which the dial
                    466:      succeeds.  This is an ugly spaghetti construction, and it should
                    467:      be broken up into different functions someday.  */
                    468:   flooped = FALSE;
                    469:   while (TRUE)
                    470:     {
                    471:       enum tparitysetting tparity;
                    472:       enum tstripsetting tstrip;
                    473: 
                    474:       /* The uuconf_find_port function only selects directly on a port
                    475:         name and a speed.  To select based on the line name, we use a
                    476:         function.  If we can't find any defined port, and the user
                    477:         specified a line name but did not specify a port name or a
                    478:         system or a phone number, then we fake a direct port with
                    479:         that line name (we don't fake a port if a system or phone
                    480:         number were given because if we fake a port we have no way to
                    481:         place a call; perhaps we should automatically look up a
                    482:         particular dialer).  This permits users to say cu -lttyd0
                    483:         without having to put ttyd0 in the ports file, provided they
                    484:         have read and write access to the port.  */
                    485:       sinfo.fmatched = FALSE;
                    486:       sinfo.flocked = FALSE;
                    487:       sinfo.qconn = &sconn;
                    488:       sinfo.zline = zline;
                    489:       if (zport != NULL || zline != NULL || ibaud != 0L)
                    490:        {
                    491:          iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L,
                    492:                                      icuport_lock, (pointer) &sinfo,
                    493:                                      &sport);
                    494:          if (iuuconf != UUCONF_SUCCESS)
                    495:            {
                    496:              if (iuuconf != UUCONF_NOT_FOUND)
                    497:                {
                    498:                  if (sinfo.flocked)
                    499:                    {
                    500:                      (void) fconn_unlock (&sconn);
                    501:                      uconn_free (&sconn);
                    502:                    }
                    503:                  ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    504:                }
                    505:              if (zline == NULL
                    506:                  || zport != NULL
                    507:                  || zphone != NULL
                    508:                  || qsys != NULL)
                    509:                {
                    510:                  if (sinfo.fmatched)
                    511:                    ulog (LOG_FATAL, "All matching ports in use");
                    512:                  else
                    513:                    ulog (LOG_FATAL, "No matching ports");
                    514:                }
                    515: 
                    516:              sport.uuconf_zname = zline;
                    517:              sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
                    518:              sport.uuconf_zprotocols = NULL;
                    519:              sport.uuconf_qproto_params = NULL;
                    520:              sport.uuconf_ireliable = 0;
                    521:              sport.uuconf_zlockname = NULL;
                    522:              sport.uuconf_palloc = NULL;
                    523:              sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
                    524:              sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
                    525: 
                    526:              if (! fsysdep_port_access (&sport))
                    527:                ulog (LOG_FATAL, "%s: Permission denied", zline);
                    528: 
                    529:              if (! fconn_init (&sport, &sconn))
                    530:                ucuabort ();
                    531: 
                    532:              if (! fconn_lock (&sconn, FALSE))
                    533:                ulog (LOG_FATAL, "%s: Line in use", zline);
                    534: 
                    535:              qCuconn = &sconn;
                    536:            }
                    537:          ihighbaud = 0L;
                    538:        }
                    539:       else
                    540:        {
                    541:          for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
                    542:            {
                    543:              if (! qsys->uuconf_fcall)
                    544:                continue;
                    545:              if (qsys->uuconf_qport != NULL)
                    546:                {
                    547:                  if (fconn_init (qsys->uuconf_qport, &sconn))
                    548:                    {
                    549:                      if (fconn_lock (&sconn, FALSE))
                    550:                        {
                    551:                          qCuconn = &sconn;
                    552:                          break;
                    553:                        }
                    554:                      uconn_free (&sconn);
                    555:                    }
                    556:                }
                    557:              else
                    558:                {
                    559:                  sinfo.fmatched = FALSE;
                    560:                  sinfo.flocked = FALSE;
                    561:                  sinfo.qconn = &sconn;
                    562:                  iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
                    563:                                              qsys->uuconf_ibaud,
                    564:                                              qsys->uuconf_ihighbaud,
                    565:                                              icuport_lock,
                    566:                                              (pointer) &sinfo,
                    567:                                              &sport);
                    568:                  if (iuuconf == UUCONF_SUCCESS)
                    569:                    break;
                    570:                  if (iuuconf != UUCONF_NOT_FOUND)
                    571:                    {
                    572:                      if (sinfo.flocked)
                    573:                        {
                    574:                          (void) fconn_unlock (&sconn);
                    575:                          uconn_free (&sconn);
                    576:                        }
                    577:                      ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
                    578:                    }
                    579:                }
                    580:            }
                    581: 
                    582:          if (qsys == NULL)
                    583:            {
                    584:              const char *zrem;
                    585: 
                    586:              if (flooped)
                    587:                zrem = "remaining ";
                    588:              else
                    589:                zrem = "";
                    590:              if (sinfo.fmatched)
                    591:                ulog (LOG_FATAL, "%s: All %smatching ports in use",
                    592:                      zsystem, zrem);
                    593:              else
                    594:                ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem);
                    595:            }
                    596: 
                    597:          ibaud = qsys->uuconf_ibaud;
                    598:          ihighbaud = qsys->uuconf_ihighbaud;
                    599:        }
                    600: 
                    601:       /* Here we have locked a connection to use.  */
                    602:       if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE))
                    603:        ucuabort ();
                    604: 
                    605:       fCuclose_conn = TRUE;
                    606: 
                    607:       if (FGOT_SIGNAL ())
                    608:        ucuabort ();
                    609: 
                    610:       /* Set up the connection.  */
                    611:       if (fodd && feven)
                    612:        {
                    613:          tparity = PARITYSETTING_NONE;
                    614:          tstrip = STRIPSETTING_SEVENBITS;
                    615:        }
                    616:       else if (fodd)
                    617:        {
                    618:          tparity = PARITYSETTING_ODD;
                    619:          tstrip = STRIPSETTING_SEVENBITS;
                    620:        }
                    621:       else if (feven)
                    622:        {
                    623:          tparity = PARITYSETTING_EVEN;
                    624:          tstrip = STRIPSETTING_SEVENBITS;
                    625:        }
                    626:       else
                    627:        {
                    628:          tparity = PARITYSETTING_DEFAULT;
                    629:          tstrip = STRIPSETTING_DEFAULT;
                    630:        }
                    631: 
                    632:       if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON))
                    633:        ucuabort ();
                    634: 
                    635:       if (qsys != NULL)
                    636:        zphone = qsys->uuconf_zphone;
                    637: 
                    638:       if (qsys != NULL || zphone != NULL)
                    639:        {
                    640:          enum tdialerfound tdialer;
                    641: 
                    642:          if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer,
                    643:                            &tdialer))
                    644:            {
                    645:              if (zport != NULL
                    646:                  || zline != NULL
                    647:                  || ibaud != 0L
                    648:                  || qsys == NULL)
                    649:                ucuabort ();
                    650: 
                    651:              if (qsys->uuconf_qalternate == NULL)
                    652:                ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
                    653: 
                    654:              fCuclose_conn = FALSE;
                    655:              (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE);
                    656:              qCuconn = NULL;
                    657:              (void) fconn_unlock (&sconn);
                    658:              uconn_free (&sconn);
                    659: 
                    660:              /* Loop around and try another alternate.  */
                    661:              flooped = TRUE;
                    662:              continue;
                    663:            }
                    664:          if (tdialer == DIALERFOUND_FALSE)
                    665:            qdialer = NULL;
                    666:          else
                    667:            qdialer = &sdialer;
                    668:        }
                    669:       else
                    670:        {
                    671:          /* If no system or phone number was specified, we connect
                    672:             directly to the modem.  We only permit this if the user
                    673:             has access to the port, since it permits various
                    674:             shenanigans such as reprogramming the automatic
                    675:             callbacks.  */
                    676:          if (! fsysdep_port_access (sconn.qport))
                    677:            ulog (LOG_FATAL, "Access to port denied");
                    678:          qdialer = NULL;
                    679:          if (! fconn_carrier (&sconn, FALSE))
                    680:            ulog (LOG_FATAL, "Can't turn off carrier");
                    681:        }
                    682: 
                    683:       break;
                    684:     }
                    685: 
                    686:   qCudialer = qdialer;
                    687: 
                    688:   if (FGOT_SIGNAL ())
                    689:     ucuabort ();
                    690: 
                    691:   /* Here we have connected, and can start the main cu protocol.  The
                    692:      program spends most of its time in system dependent code, and
                    693:      only comes out when a special command is received from the
                    694:      terminal.  */
                    695:   printf ("%s\n", ZCONNMSG);
                    696: 
                    697:   if (! fsysdep_terminal_raw (fCulocalecho))
                    698:     ucuabort ();
                    699: 
                    700:   fCurestore_terminal = TRUE;
                    701: 
                    702:   if (! fsysdep_cu_init (&sconn))
                    703:     ucuabort ();
                    704: 
                    705:   fCustarted = TRUE;
                    706: 
                    707:   while (fsysdep_cu (&sconn, &bcmd, zlocalname))
                    708:     if (! fcudo_cmd (puuconf, &sconn, bcmd))
                    709:       break;
                    710: 
                    711:   fCustarted = FALSE;
                    712:   if (! fsysdep_cu_finish ())
                    713:     ucuabort ();
                    714: 
                    715:   fCurestore_terminal = FALSE;
                    716:   (void) fsysdep_terminal_restore ();
                    717: 
                    718:   (void) fconn_close (&sconn, puuconf, qdialer, TRUE);
                    719:   (void) fconn_unlock (&sconn);
                    720:   uconn_free (&sconn);
                    721: 
                    722:   printf ("\n%s\n", ZDISMSG);
                    723: 
                    724:   ulog_close ();
                    725: 
                    726:   usysdep_exit (TRUE);
                    727: 
                    728:   /* Avoid errors about not returning a value.  */
                    729:   return 0;
                    730: }
                    731: 
                    732: /* Print a usage message and die.  */
                    733: 
                    734: static void
                    735: ucuusage ()
                    736: {
                    737:   fprintf (stderr,
                    738:           "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
                    739:           VERSION);
                    740:   fprintf (stderr,
                    741:           "Usage: cu [options] [system or phone-number]\n");
                    742:   fprintf (stderr,
                    743:           " -a port, -p port: Use named port\n");
                    744:   fprintf (stderr,
                    745:           " -l line: Use named device (e.g. tty0)\n");
                    746:   fprintf (stderr,
                    747:           " -s speed, -#: Use given speed\n");
                    748:   fprintf (stderr,
                    749:           " -c phone: Phone number to call\n");
                    750:   fprintf (stderr,
                    751:           " -z system: System to call\n");
                    752:   fprintf (stderr,
                    753:           " -e: Set even parity\n");
                    754:   fprintf (stderr,
                    755:           " -o: Set odd parity\n");
                    756:   fprintf (stderr,
                    757:           " -h: Echo locally\n");
                    758:   fprintf (stderr,
                    759:           " -t: Map carriage return to carriage return/linefeed\n");
                    760:   fprintf (stderr,
                    761:           " -n: Prompt for phone number\n");
                    762:   fprintf (stderr,
                    763:           " -d: Set maximum debugging level\n");
                    764:   fprintf (stderr,
                    765:           " -x debug: Set debugging type\n");
                    766: #if HAVE_TAYLOR_CONFIG
                    767:   fprintf (stderr,
                    768:           " -I file: Set configuration file to use\n");
                    769: #endif /* HAVE_TAYLOR_CONFIG */
                    770: 
                    771:   exit (EXIT_FAILURE);
                    772: }
                    773: 
                    774: /* This function is called when a fatal error occurs.  */
                    775: 
                    776: static void
                    777: ucuabort ()
                    778: {
                    779:   if (fCustarted)
                    780:     {
                    781:       fCustarted = FALSE;
                    782:       (void) fsysdep_cu_finish ();
                    783:     }
                    784: 
                    785:   if (fCurestore_terminal)
                    786:     {
                    787:       fCurestore_terminal = FALSE;
                    788:       (void) fsysdep_terminal_restore ();
                    789:     }
                    790: 
                    791:   if (qCuconn != NULL)
                    792:     {
                    793:       struct sconnection *qconn;
                    794: 
                    795:       if (fCuclose_conn)
                    796:        {
                    797:          fCuclose_conn = FALSE;
                    798:          (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE);
                    799:        }
                    800:       qconn = qCuconn;
                    801:       qCuconn = NULL;
                    802:       (void) fconn_unlock (qconn);
                    803:       uconn_free (qconn);
                    804:     }
                    805: 
                    806:   ulog_close ();
                    807: 
                    808:   printf ("\n%s\n", ZDISMSG);
                    809: 
                    810:   usysdep_exit (FALSE);
                    811: }
                    812: 
                    813: /* This variable is just used to communicate between uculog_start and
                    814:    uculog_end.  */
                    815: static boolean fCulog_restore;
                    816: 
                    817: /* This function is called by ulog before it output anything.  We use
                    818:    it to restore the terminal, if necessary.  ulog is only called for
                    819:    errors or debugging in cu, so it's not too costly to do this.  If
                    820:    we didn't do it, then at least on Unix each line would leave the
                    821:    cursor in the same column rather than wrapping back to the start,
                    822:    since CRMOD will not be on.  */
                    823: 
                    824: static void
                    825: uculog_start ()
                    826: {
                    827:   if (! fCurestore_terminal)
                    828:     fCulog_restore = FALSE;
                    829:   else
                    830:     {
                    831:       fCulog_restore = TRUE;
                    832:       fCurestore_terminal = FALSE;
                    833:       if (! fsysdep_terminal_restore ())
                    834:        ucuabort ();
                    835:     }
                    836: }
                    837: 
                    838: /* This function is called by ulog after everything is output.  It
                    839:    sets the terminal back, if necessary.  */
                    840: 
                    841: static void
                    842: uculog_end ()
                    843: {
                    844:   if (fCulog_restore)
                    845:     {
                    846:       if (! fsysdep_terminal_raw (fCulocalecho))
                    847:        ucuabort ();
                    848:       fCurestore_terminal = TRUE;
                    849:     }
                    850: }
                    851: 
                    852: /* Check to see if this port has the desired line, to handle the -l
                    853:    option.  If it does, or if no line was specified, set up a
                    854:    connection and lock it.  */
                    855: 
                    856: static int
                    857: icuport_lock (qport, pinfo)
                    858:      struct uuconf_port *qport;
                    859:      pointer pinfo;
                    860: {
                    861:   struct sconninfo *q = (struct sconninfo *) pinfo;
                    862: 
                    863:   if (q->zline != NULL
                    864:       && ! fsysdep_port_is_line (qport, q->zline))
                    865:     return UUCONF_NOT_FOUND;
                    866: 
                    867:   q->fmatched = TRUE;
                    868: 
                    869:   if (! fconn_init (qport, q->qconn))
                    870:     return UUCONF_NOT_FOUND;
                    871:   else if (! fconn_lock (q->qconn, FALSE))
                    872:     {
                    873:       uconn_free (q->qconn);
                    874:       return UUCONF_NOT_FOUND;
                    875:     }
                    876:   else
                    877:     {
                    878:       qCuconn = q->qconn;
                    879:       q->flocked = TRUE;
                    880:       return UUCONF_SUCCESS;
                    881:     }
                    882: }
                    883: 
                    884: /* Execute a cu escape command.  Return TRUE if the connection should
                    885:    continue, or FALSE if the connection should be terminated.  */
                    886: 
                    887: static boolean
                    888: fcudo_cmd (puuconf, qconn, bcmd)
                    889:      pointer puuconf;
                    890:      struct sconnection *qconn;
                    891:      int bcmd;
                    892: {
                    893:   char *zline;
                    894:   char *z;
                    895:   char abescape[5];
                    896:   boolean fret;
                    897:   size_t clen;
                    898:   char abbuf[100];
                    899: 
                    900:   /* Some commands take a string up to the next newline character.  */
                    901:   switch (bcmd)
                    902:     {
                    903:     default:
                    904:       zline = NULL;
                    905:       break;
                    906:     case '!':
                    907:     case '$':
                    908:     case '|':
                    909:     case '+':
                    910:     case '%':
                    911:     case 'c':
                    912:     case '>':
                    913:     case '<':
                    914:     case 'p':
                    915:     case 't':
                    916:     case 's':
                    917:       {
                    918:        zline = zsysdep_terminal_line ((const char *) NULL);
                    919:        if (zline == NULL)
                    920:          ucuabort ();
                    921:        zline[strcspn (zline, "\n")] = '\0';
                    922:       }
                    923:       break;
                    924:     }
                    925: 
                    926:   switch (bcmd)
                    927:     {
                    928:     default:
                    929:       if (! isprint (*zCuvar_escape))
                    930:        sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
                    931:       else
                    932:        {
                    933:          abescape[0] = *zCuvar_escape;
                    934:          abescape[1] = '\0';
                    935:        }
                    936:       sprintf (abbuf, "[Unrecognized.  Use %s%s to send %s]",
                    937:               abescape, abescape, abescape);
                    938:       ucuputs (abbuf);
                    939:       return TRUE;
                    940: 
                    941:     case '.':
                    942:       /* Hangup.  */
                    943:       return FALSE;
                    944: 
                    945:     case '!':
                    946:     case '$':
                    947:     case '|':
                    948:     case '+':
                    949:       /* Shell out.  */
                    950:       if (! fsysdep_cu_copy (FALSE)
                    951:          || ! fsysdep_terminal_restore ())
                    952:        ucuabort ();
                    953:       fCurestore_terminal = FALSE;
                    954:       {
                    955:        enum tshell_cmd t;
                    956: 
                    957:        switch (bcmd)
                    958:          {
                    959:          default:
                    960:          case '!': t = SHELL_NORMAL; break;
                    961:          case '$': t = SHELL_STDOUT_TO_PORT; break;
                    962:          case '|': t = SHELL_STDIN_FROM_PORT; break;
                    963:          case '+': t = SHELL_STDIO_ON_PORT; break;
                    964:          }
                    965:          
                    966:        (void) fsysdep_shell (qconn, zline, t);
                    967:       }
                    968:       if (! fsysdep_cu_copy (TRUE)
                    969:          || ! fsysdep_terminal_raw (fCulocalecho))
                    970:        ucuabort ();
                    971:       fCurestore_terminal = TRUE;
                    972:       ubuffree (zline);
                    973:       return TRUE;
                    974: 
                    975:     case '%':
                    976:       fret = fcudo_subcmd (puuconf, qconn, zline);
                    977:       ubuffree (zline);
                    978:       return fret;
                    979: 
                    980:     case '#':
                    981:       if (! fconn_break (qconn))
                    982:        ucuabort ();
                    983:       return TRUE;
                    984: 
                    985:     case 'c':
                    986:       (void) fsysdep_chdir (zline);
                    987:       ubuffree (zline);
                    988:       return TRUE;
                    989: 
                    990:     case '>':
                    991:     case '<':
                    992:     case 'p':
                    993:     case 't':
                    994:       clen = strlen (zline);
                    995:       z = zbufalc (clen + 3);
                    996:       z[0] = bcmd;
                    997:       z[1] = ' ';
                    998:       memcpy (z + 2, zline, clen + 1);
                    999:       ubuffree (zline);
                   1000:       fret = fcudo_subcmd (puuconf, qconn, z);
                   1001:       ubuffree (z);
                   1002:       return fret;
                   1003: 
                   1004:     case 'z':
                   1005:       if (! fsysdep_cu_copy (FALSE)
                   1006:          || ! fsysdep_terminal_restore ())
                   1007:        ucuabort ();
                   1008:       fCurestore_terminal = FALSE;
                   1009:       if (! fsysdep_suspend ())
                   1010:        ucuabort ();
                   1011:       if (! fsysdep_cu_copy (TRUE)
                   1012:          || ! fsysdep_terminal_raw (fCulocalecho))
                   1013:        ucuabort ();
                   1014:       fCurestore_terminal = TRUE;
                   1015:       return TRUE;
                   1016:       
                   1017:     case 's':
                   1018:       fret = fcuset_var (puuconf, zline);
                   1019:       ubuffree (zline);
                   1020:       return fret;
                   1021: 
                   1022:     case 'v':
                   1023:       uculist_vars ();
                   1024:       return TRUE;
                   1025: 
                   1026:     case '?':
                   1027:       if (! isprint (*zCuvar_escape))
                   1028:        sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
                   1029:       else
                   1030:        {
                   1031:          abescape[0] = *zCuvar_escape;
                   1032:          abescape[1] = '\0';
                   1033:        }
                   1034:       ucuputs ("");
                   1035:       ucuputs ("[Escape sequences]");
                   1036:       sprintf (abbuf,
                   1037:               "[%s. hangup]                   [%s!CMD run shell]",
                   1038:               abescape, abescape);
                   1039:       ucuputs (abbuf);
                   1040:       sprintf (abbuf,
                   1041:               "[%s$CMD stdout to remote]      [%s|CMD stdin from remote]",
                   1042:               abescape, abescape);
                   1043:       ucuputs (abbuf);
                   1044:       sprintf (abbuf,
                   1045:               "[%s+CMD stdin and stdout to remote]",
                   1046:               abescape);
                   1047:       ucuputs (abbuf);
                   1048:       sprintf (abbuf,
                   1049:               "[%s# send break]               [%scDIR change directory]",
                   1050:               abescape, abescape);
                   1051:       ucuputs (abbuf);
                   1052:       sprintf (abbuf,
                   1053:               "[%s> send file]                [%s< receive file]",
                   1054:               abescape, abescape);
                   1055:       ucuputs (abbuf);
                   1056:       sprintf (abbuf,
                   1057:               "[%spFROM TO send to Unix]      [%stFROM TO receive from Unix]",
                   1058:               abescape, abescape);
                   1059:       ucuputs (abbuf);
                   1060:       sprintf (abbuf,
                   1061:               "[%ssVAR VAL set variable]      [%ssVAR set boolean]",
                   1062:               abescape, abescape);
                   1063:       ucuputs (abbuf);
                   1064:       sprintf (abbuf,
                   1065:               "[%ss!VAR unset boolean]        [%sv list variables]",
                   1066:               abescape, abescape);
                   1067:       ucuputs (abbuf);
                   1068: #ifdef SIGTSTP
                   1069:       sprintf (abbuf,
                   1070:               "[%sz suspend]",
                   1071:               abescape);
                   1072:       ucuputs (abbuf);
                   1073: #endif
                   1074:       uculist_fns (abescape);
                   1075:       return TRUE;
                   1076:     }
                   1077: }
                   1078: 
                   1079: /* List ~% functions.  */
                   1080: 
                   1081: static void
                   1082: uculist_fns (zescape)
                   1083:      const char *zescape;
                   1084: {
                   1085:   char abbuf[100];
                   1086: 
                   1087:   sprintf (abbuf,
                   1088:           "[%s%%break send break]         [%s%%cd DIR change directory]",
                   1089:           zescape, zescape);
                   1090:   ucuputs (abbuf);
                   1091:   sprintf (abbuf,
                   1092:           "[%s%%put FROM TO send file]    [%s%%take FROM TO receive file]",
                   1093:           zescape, zescape);
                   1094:   ucuputs (abbuf);
                   1095:   sprintf (abbuf,
                   1096:           "[%s%%nostop no XON/XOFF]       [%s%%stop use XON/XOFF]",
                   1097:           zescape, zescape);
                   1098:   ucuputs (abbuf);
                   1099: }
                   1100: 
                   1101: /* Set a variable.  */
                   1102: 
                   1103: static boolean
                   1104: fcuset_var (puuconf, zline)
                   1105:      pointer puuconf;
                   1106:      char *zline;
                   1107: {
                   1108:   char *zvar, *zval;
                   1109:   char *azargs[2];
                   1110:   char azbool[2];
                   1111:   int iuuconf;
                   1112: 
                   1113:   zvar = strtok (zline, "= \t");
                   1114:   if (zvar == NULL)
                   1115:     {
                   1116:       ucuputs (abCuconnected);
                   1117:       return TRUE;
                   1118:     }
                   1119: 
                   1120:   zval = strtok ((char *) NULL, " \t");
                   1121: 
                   1122:   if (zval == NULL)
                   1123:     {
                   1124:       azargs[0] = zvar;
                   1125:       if (azargs[0][0] != '!')
                   1126:        azbool[0] = 't';
                   1127:       else
                   1128:        {
                   1129:          ++azargs[0];
                   1130:          azbool[0] = 'f';
                   1131:        }
                   1132:       azbool[1] = '\0';
                   1133:       azargs[1] = azbool;
                   1134:     }
                   1135:   else
                   1136:     {
                   1137:       azargs[0] = zvar;
                   1138:       azargs[1] = zval;
                   1139:     }
                   1140: 
                   1141:   iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars,
                   1142:                             (pointer) NULL, icuunrecogvar, 0,
                   1143:                             (pointer) NULL);
                   1144:   if (iuuconf != UUCONF_SUCCESS)
                   1145:     ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
                   1146: 
                   1147:   return TRUE;
                   1148: }
                   1149: 
                   1150: /* Warn about an unknown variable.  */
                   1151: 
                   1152: /*ARGSUSED*/
                   1153: static int
                   1154: icuunrecogvar (puuconf, argc, argv, pvar, pinfo)
                   1155:      pointer puuconf;
                   1156:      int argc;
                   1157:      char **argv;
                   1158:      pointer pvar;
                   1159:      pointer pinfo;
                   1160: {
                   1161:   char abescape[5];
                   1162: 
                   1163:   if (! isprint (*zCuvar_escape))
                   1164:     sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
                   1165:   else
                   1166:     {
                   1167:       abescape[0] = *zCuvar_escape;
                   1168:       abescape[1] = '\0';
                   1169:     }
                   1170:   ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)",
                   1171:        argv[0], abescape);
                   1172:   return UUCONF_CMDTABRET_CONTINUE;
                   1173: }
                   1174: 
                   1175: /* List all the variables with their values.  */
                   1176: 
                   1177: static void
                   1178: uculist_vars ()
                   1179: {
                   1180:   const struct uuconf_cmdtab *q;
                   1181:   char abbuf[100];
                   1182: 
                   1183:   ucuputs ("");
                   1184:   for (q = asCuvars; q->uuconf_zcmd != NULL; q++)
                   1185:     {
                   1186:       switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype))
                   1187:        {
                   1188:        case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN):
                   1189:          if (*(boolean *) q->uuconf_pvar)
                   1190:            sprintf (abbuf, "%s true", q->uuconf_zcmd);
                   1191:          else
                   1192:            sprintf (abbuf, "%s false", q->uuconf_zcmd);
                   1193:          break;
                   1194: 
                   1195:        case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT):
                   1196:          sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar);
                   1197:          break;
                   1198: 
                   1199:        case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG):
                   1200:          sprintf (abbuf, "%s %ld", q->uuconf_zcmd,
                   1201:                   *(long *) q->uuconf_pvar);
                   1202:          break;
                   1203: 
                   1204:        case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING):
                   1205:        case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING):
                   1206:          {
                   1207:            const char *z;
                   1208:            char abchar[5];
                   1209:            size_t clen;
                   1210: 
                   1211:            sprintf (abbuf, "%s ", q->uuconf_zcmd);
                   1212:            clen = strlen (abbuf);
                   1213:            for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++)
                   1214:              {
                   1215:                int cchar;
                   1216: 
                   1217:                if (! isprint (*z))
                   1218:                  {
                   1219:                    sprintf (abchar, "\\%03o", (unsigned int) *z);
                   1220:                    cchar = 4;
                   1221:                  }
                   1222:                else
                   1223:                  {
                   1224:                    abchar[0] = *z;
                   1225:                    abchar[1] = '\0';
                   1226:                    cchar = 1;
                   1227:                  }
                   1228:                if (clen + cchar < sizeof (abbuf))
                   1229:                  strcat (abbuf, abchar);
                   1230:                clen += cchar;
                   1231:              }
                   1232:          }
                   1233:          break;
                   1234: 
                   1235:        default:
                   1236:          sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd);
                   1237:          break;
                   1238:        }
                   1239: 
                   1240:       ucuputs (abbuf);
                   1241:     }
                   1242: }
                   1243: 
                   1244: /* Subcommands.  These are commands that begin with ~%.  */
                   1245: 
                   1246: /* This variable is only used so that we can pass a non-NULL address
                   1247:    in pvar.  It is never assigned to or examined.  */
                   1248: 
                   1249: static char bCutype;
                   1250: 
                   1251: /* The command table for the subcommands.  */
                   1252: 
                   1253: static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1254:                       pointer pinfo));
                   1255: static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1256:                       pointer pinfo));
                   1257: static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1258:                       pointer pinfo));
                   1259: static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1260:                     pointer pinfo));
                   1261: static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1262:                      pointer pinfo));
                   1263: static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar,
                   1264:                        pointer pinfo));
                   1265: 
                   1266: static const struct uuconf_cmdtab asCucmds[] =
                   1267: {
                   1268:   { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
                   1269:   { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
                   1270:   { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir },
                   1271:   { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug },
                   1272:   { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
                   1273:   { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
                   1274:   { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop },
                   1275:   { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop },
                   1276:   { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput },
                   1277:   { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake },
                   1278:   { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
                   1279:   { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
                   1280:   { NULL, 0, NULL, NULL }
                   1281: };
                   1282: 
                   1283: /* Do a subcommand.  This is called by commands beginning with ~%.  */
                   1284: 
                   1285: static boolean
                   1286: fcudo_subcmd (puuconf, qconn, zline)
                   1287:      pointer puuconf;
                   1288:      struct sconnection *qconn;
                   1289:      char *zline;
                   1290: {
                   1291:   char *azargs[3];
                   1292:   int iarg;
                   1293:   int iuuconf;
                   1294: 
                   1295:   for (iarg = 0; iarg < 3; iarg++)
                   1296:     {
                   1297:       azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n");
                   1298:       if (azargs[iarg] == NULL)
                   1299:        break;
                   1300:     }
                   1301: 
                   1302:   if (iarg == 0)
                   1303:     {
                   1304:       ucuputs (abCuconnected);
                   1305:       return TRUE;
                   1306:     }
                   1307: 
                   1308:   iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds,
                   1309:                             (pointer) qconn, icuunrecogfn,
                   1310:                             0, (pointer) NULL);
                   1311:   if (iuuconf != UUCONF_SUCCESS)
                   1312:     ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
                   1313: 
                   1314:   return TRUE;
                   1315: }
                   1316: 
                   1317: /* Warn about an unknown function.  */
                   1318: 
                   1319: /*ARGSUSED*/
                   1320: static int
                   1321: icuunrecogfn (puuconf, argc, argv, pvar, pinfo)
                   1322:      pointer puuconf;
                   1323:      int argc;
                   1324:      char **argv;
                   1325:      pointer pvar;
                   1326:      pointer pinfo;
                   1327: {
                   1328:   char abescape[5];
                   1329: 
                   1330:   if (! isprint (*zCuvar_escape))
                   1331:     sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
                   1332:   else
                   1333:     {
                   1334:       abescape[0] = *zCuvar_escape;
                   1335:       abescape[1] = '\0';
                   1336:     }
                   1337:   if (argv[0][0] == '?')
                   1338:     uculist_fns (abescape);
                   1339:   else
                   1340:     ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)",
                   1341:          argv[0], abescape);
                   1342:   return UUCONF_CMDTABRET_CONTINUE;
                   1343: }
                   1344: 
                   1345: /* Send a break.  */
                   1346: 
                   1347: /*ARGSUSED*/
                   1348: static int
                   1349: icubreak (puuconf, argc, argv, pvar, pinfo)
                   1350:      pointer puuconf;
                   1351:      int argc;
                   1352:      char **argv;
                   1353:      pointer pvar;
                   1354:      pointer pinfo;
                   1355: {
                   1356:   struct sconnection *qconn = (struct sconnection *) pinfo;
                   1357: 
                   1358:   if (! fconn_break (qconn))
                   1359:     ucuabort ();
                   1360:   return UUCONF_CMDTABRET_CONTINUE;
                   1361: }
                   1362: 
                   1363: /* Change directories.  */
                   1364: 
                   1365: /*ARGSUSED*/
                   1366: static int
                   1367: icuchdir (puuconf, argc, argv, pvar, pinfo)
                   1368:      pointer puuconf;
                   1369:      int argc;
                   1370:      char **argv;
                   1371:      pointer pvar;
                   1372:      pointer pinfo;
                   1373: {
                   1374:   const char *zarg;
                   1375: 
                   1376:   if (argc <= 1)
                   1377:     zarg = NULL;
                   1378:   else
                   1379:     zarg = argv[1];
                   1380:   (void) fsysdep_chdir (zarg);
                   1381:   return UUCONF_CMDTABRET_CONTINUE;
                   1382: }
                   1383: 
                   1384: /* Toggle debugging.  */
                   1385: 
                   1386: /*ARGSUSED*/
                   1387: static int
                   1388: icudebug (puuconf, argc, argv, pvar, pinfo)
                   1389:      pointer puuconf;
                   1390:      int argc;
                   1391:      char **argv;
                   1392:      pointer pvar;
                   1393:      pointer pinfo;
                   1394: {
                   1395: #if DEBUG > 1
                   1396:   if (iDebug != 0)
                   1397:     iDebug = 0;
                   1398:   else
                   1399:     iDebug = DEBUG_MAX;
                   1400: #else
                   1401:   ucuputs ("[compiled without debugging]");
                   1402: #endif
                   1403:   return UUCONF_CMDTABRET_CONTINUE;
                   1404: }
                   1405: 
                   1406: /* Control whether the port does xon/xoff handshaking.  If pvar is not
                   1407:    NULL, this is "stop"; otherwise it is "nostop".  */
                   1408: 
                   1409: /*ARGSUSED*/
                   1410: static int
                   1411: icunostop (puuconf, argc, argv, pvar, pinfo)
                   1412:      pointer puuconf;
                   1413:      int argc;
                   1414:      char **argv;
                   1415:      pointer pvar;
                   1416:      pointer pinfo;
                   1417: {
                   1418:   struct sconnection *qconn = (struct sconnection *) pinfo;
                   1419: 
                   1420:   if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT,
                   1421:                   pvar == NULL ? XONXOFF_OFF : XONXOFF_ON))
                   1422:     ucuabort ();
                   1423:   return UUCONF_CMDTABRET_CONTINUE;
                   1424: }
                   1425: 
                   1426: /* Send a file to the remote system.  The first argument is the file
                   1427:    to send.  If that argument is not present, it is prompted for.  The
                   1428:    second argument is to file name to use on the remote system.  If
                   1429:    that argument is not present, the basename of the local filename is
                   1430:    used.  If pvar is not NULL, then this is ~>, which is used to send
                   1431:    a command to a non-Unix system.  We treat is the same as ~%put,
                   1432:    except that we assume the user has already entered the appropriate
                   1433:    command (for ~%put, we force ``cat >to'' to the other side).  */
                   1434: 
                   1435: /*ARGSUSED*/
                   1436: static int
                   1437: icuput (puuconf, argc, argv, pvar, pinfo)
                   1438:      pointer puuconf;
                   1439:      int argc;
                   1440:      char **argv;
                   1441:      pointer pvar;
                   1442:      pointer pinfo;
                   1443: {
                   1444:   struct sconnection *qconn = (struct sconnection *) pinfo;
                   1445:   char *zfrom;
                   1446:   char *zto = NULL;
                   1447:   char *zalc;
                   1448:   openfile_t e;
                   1449:   int cline;
                   1450:   char *zbuf;
                   1451:   size_t cbuf;
                   1452: 
                   1453:   if (argc > 1)
                   1454:     zfrom = zbufcpy (argv[1]);
                   1455:   else
                   1456:     {
                   1457:       zfrom = zsysdep_terminal_line ("File to send: ");
                   1458:       if (zfrom == NULL)
                   1459:        ucuabort ();
                   1460:       zfrom[strcspn (zfrom, " \t\n")] = '\0';
                   1461: 
                   1462:       if (*zfrom == '\0')
                   1463:        {
                   1464:          ubuffree (zfrom);
                   1465:          ucuputs (abCuconnected);
                   1466:          return UUCONF_CMDTABRET_CONTINUE;
                   1467:        }
                   1468:     }
                   1469: 
                   1470:   if (pvar == NULL)
                   1471:     {
                   1472:       if (argc > 2)
                   1473:        zto = zbufcpy (argv[2]);
                   1474:       else
                   1475:        {
                   1476:          char *zbase;
                   1477:          char *zprompt;
                   1478: 
                   1479:          zbase = zsysdep_base_name (zfrom);
                   1480:          if (zbase == NULL)
                   1481:            ucuabort ();
                   1482: 
                   1483:          zprompt = zbufalc (sizeof "Remote file name []: " +
                   1484:                             strlen (zbase));
                   1485:          sprintf (zprompt, "Remote file name [%s]: ", zbase);
                   1486:          zto = zsysdep_terminal_line (zprompt);
                   1487:          ubuffree (zprompt);
                   1488:          if (zto == NULL)
                   1489:            ucuabort ();
                   1490: 
                   1491:          zto[strcspn (zto, " \t\n")] = '\0';
                   1492:          if (*zto != '\0')
                   1493:            ubuffree (zbase);
                   1494:          else
                   1495:            {
                   1496:              ubuffree (zto);
                   1497:              zto = zbase;
                   1498:            }
                   1499:        }
                   1500:     }
                   1501: 
                   1502:   e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary);
                   1503:   if (! ffileisopen (e))
                   1504:     {
                   1505:       const char *zerrstr;
                   1506: 
                   1507:       if (pvar == NULL)
                   1508:        ubuffree (zto);
                   1509:       zerrstr = strerror (errno);
                   1510:       zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr));
                   1511:       sprintf (zalc, "%s: %s", zfrom, zerrstr);
                   1512:       ubuffree (zfrom);
                   1513:       ucuputs (zalc);
                   1514:       ubuffree (zalc);
                   1515:       ucuputs (abCuconnected);
                   1516:       return UUCONF_CMDTABRET_CONTINUE;
                   1517:     }
                   1518: 
                   1519:   ubuffree (zfrom);
                   1520: 
                   1521:   /* Tell the system dependent layer to stop copying data from the
                   1522:      port to the terminal.  We want to read the echoes ourself.  Also
                   1523:      permit the local user to generate signals.  */
                   1524:   if (! fsysdep_cu_copy (FALSE)
                   1525:       || ! fsysdep_terminal_signals (TRUE))
                   1526:     ucuabort ();
                   1527: 
                   1528:   /* If pvar is NULL, then we are sending a file to a Unix system.  We
                   1529:      send over the command "cat > TO" to prepare it to receive.  If
                   1530:      pvar is not NULL, the user is assumed to have set up whatever
                   1531:      action was needed to receive the file.  */
                   1532:   if (pvar == NULL)
                   1533:     {
                   1534:       boolean fret;
                   1535: 
                   1536:       zalc = zbufalc (sizeof "cat > \n" + strlen (zto));
                   1537:       sprintf (zalc, "cat > %s\n", zto);
                   1538:       ubuffree (zto);
                   1539:       fret = fcusend_buf (qconn, zalc, strlen (zalc));
                   1540:       ubuffree (zalc);
                   1541:       if (! fret)
                   1542:        {
                   1543:          (void) ffileclose (e);
                   1544:          if (! fsysdep_cu_copy (TRUE)
                   1545:              || ! fsysdep_terminal_signals (FALSE))
                   1546:            ucuabort ();
                   1547:          ucuputs (abCuconnected);
                   1548:          return UUCONF_CMDTABRET_CONTINUE;
                   1549:        }
                   1550:     }
                   1551: 
                   1552:   cline = 0;
                   1553: 
                   1554:   zbuf = NULL;
                   1555:   cbuf = 0;
                   1556: 
                   1557:   while (TRUE)
                   1558:     {
                   1559:       char abbuf[512];
                   1560:       size_t c;
                   1561: 
                   1562: #if USE_STDIO
                   1563:       if (fCuvar_binary)
                   1564: #endif
                   1565:        {
                   1566:          if (ffileeof (e))
                   1567:            break;
                   1568:          c = cfileread (e, abbuf, sizeof abbuf);
                   1569:          if (ffilereaderror (e, c))
                   1570:            {
                   1571:              ucuputs ("[file read error]");
                   1572:              break;
                   1573:            }
                   1574:          if (c == 0)
                   1575:            break;
                   1576:          zbuf = abbuf;
                   1577:        }
                   1578: #if USE_STDIO
                   1579:       else
                   1580:        {
                   1581:          if (getline (&zbuf, &cbuf, e) <= 0)
                   1582:            {
                   1583:              xfree ((pointer) zbuf);
                   1584:              break;
                   1585:            }
                   1586:          c = strlen (zbuf);
                   1587:        }
                   1588: #endif
                   1589: 
                   1590:       if (fCuvar_verbose)
                   1591:        {
                   1592:          ++cline;
                   1593:          printf ("%d ", cline);
                   1594:          (void) fflush (stdout);
                   1595:        }
                   1596: 
                   1597:       if (! fcusend_buf (qconn, zbuf, c))
                   1598:        {
                   1599:          if (! fCuvar_binary)
                   1600:            xfree ((pointer) zbuf);
                   1601:          (void) fclose (e);
                   1602:          if (! fsysdep_cu_copy (TRUE)
                   1603:              || ! fsysdep_terminal_signals (FALSE))
                   1604:            ucuabort ();
                   1605:          ucuputs (abCuconnected);
                   1606:          return UUCONF_CMDTABRET_CONTINUE;
                   1607:        }
                   1608:     }
                   1609: 
                   1610:   (void) ffileclose (e);
                   1611: 
                   1612:   if (pvar == NULL)
                   1613:     {
                   1614:       char beof;
                   1615: 
                   1616:       beof = '\004';
                   1617:       if (! fconn_write (qconn, &beof, 1))
                   1618:        ucuabort ();
                   1619:     }
                   1620:   else
                   1621:     {
                   1622:       if (*zCuvar_eofwrite != '\0')
                   1623:        {
                   1624:          if (! fconn_write (qconn, zCuvar_eofwrite,
                   1625:                             strlen (zCuvar_eofwrite)))
                   1626:            ucuabort ();
                   1627:        }
                   1628:     }
                   1629: 
                   1630:   if (fCuvar_verbose)
                   1631:     ucuputs ("");
                   1632: 
                   1633:   ucuputs ("[file transfer complete]");
                   1634: 
                   1635:   if (! fsysdep_cu_copy (TRUE)
                   1636:       || ! fsysdep_terminal_signals (FALSE))
                   1637:     ucuabort ();
                   1638: 
                   1639:   ucuputs (abCuconnected);
                   1640:   return UUCONF_CMDTABRET_CONTINUE;
                   1641: }
                   1642: 
                   1643: /* Get a file from the remote side.  This is ~%take, or ~t, or ~<.
                   1644:    The first two are assumed to be taking the file from a Unix system,
                   1645:    so we force the command "cat FROM; echo  */
                   1646: 
                   1647: /*ARGSUSED*/
                   1648: static int
                   1649: icutake (puuconf, argc, argv, pvar, pinfo)
                   1650:      pointer puuconf;
                   1651:      int argc;
                   1652:      char **argv;
                   1653:      pointer pvar;
                   1654:      pointer pinfo;
                   1655: {
                   1656:   struct sconnection *qconn = (struct sconnection *) pinfo;
                   1657:   const char *zeof;
                   1658:   char *zfrom, *zto, *zcmd;
                   1659:   char *zalc;
                   1660:   openfile_t e;
                   1661:   char bcr;
                   1662:   size_t ceoflen;
                   1663:   char *zlook = NULL;
                   1664:   size_t ceofhave;
                   1665:   boolean ferr;
                   1666: 
                   1667:   if (argc > 1)
                   1668:     zfrom = zbufcpy (argv[1]);
                   1669:   else
                   1670:     {
                   1671:       zfrom = zsysdep_terminal_line ("Remote file to retreive: ");
                   1672:       if (zfrom == NULL)
                   1673:        ucuabort ();
                   1674:       zfrom[strcspn (zfrom, " \t\n")] = '\0';
                   1675:       if (*zfrom == '\0')
                   1676:        {
                   1677:          ubuffree (zfrom);
                   1678:          ucuputs (abCuconnected);
                   1679:          return UUCONF_CMDTABRET_CONTINUE;
                   1680:        }
                   1681:     }
                   1682: 
                   1683:   if (argc > 2)
                   1684:     zto = zbufcpy (argv[2]);
                   1685:   else
                   1686:     {
                   1687:       char *zbase;
                   1688:       char *zprompt;
                   1689: 
                   1690:       zbase = zsysdep_base_name (zfrom);
                   1691:       if (zbase == NULL)
                   1692:        ucuabort ();
                   1693: 
                   1694:       zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase));
                   1695:       sprintf (zprompt, "Local file name [%s]: ", zbase);
                   1696:       zto = zsysdep_terminal_line (zprompt);
                   1697:       ubuffree (zprompt);
                   1698:       if (zto == NULL)
                   1699:        ucuabort ();
                   1700: 
                   1701:       zto[strcspn (zto, " \t\n")] = '\0';
                   1702:       if (*zto != '\0')
                   1703:        ubuffree (zbase);
                   1704:       else
                   1705:        {
                   1706:          ubuffree (zto);
                   1707:          zto = zbase;
                   1708:        }
                   1709:     }
                   1710: 
                   1711:   if (pvar != NULL)
                   1712:     {
                   1713:       zcmd = zsysdep_terminal_line ("Remote command to execute: ");
                   1714:       if (zcmd == NULL)
                   1715:        ucuabort ();
                   1716:       zcmd[strcspn (zcmd, "\n")] = '\0';
                   1717:       zeof = zCuvar_eofread;
                   1718:     }
                   1719:   else
                   1720:     {
                   1721:       zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////"
                   1722:                      + strlen (zfrom));
                   1723:       sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom);
                   1724:       zeof = "\n////cuend////\n";
                   1725:     }
                   1726: 
                   1727:   ubuffree (zfrom);
                   1728: 
                   1729:   e = esysdep_user_fopen (zto, FALSE, fCuvar_binary);
                   1730:   if (! ffileisopen (e))
                   1731:     {
                   1732:       const char *zerrstr;
                   1733: 
                   1734:       ubuffree (zcmd);
                   1735:       zerrstr = strerror (errno);
                   1736:       zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr));
                   1737:       sprintf (zalc, "%s: %s\n", zto, zerrstr);
                   1738:       ucuputs (zalc);
                   1739:       ubuffree (zalc);
                   1740:       ucuputs (abCuconnected);
                   1741:       ubuffree (zto);
                   1742:       return UUCONF_CMDTABRET_CONTINUE;
                   1743:     }
                   1744: 
                   1745:   ubuffree (zto);
                   1746: 
                   1747:   if (! fsysdep_cu_copy (FALSE)
                   1748:       || ! fsysdep_terminal_signals (TRUE))
                   1749:     ucuabort ();
                   1750: 
                   1751:   if (! fconn_write (qconn, zcmd, strlen (zcmd)))
                   1752:     ucuabort ();
                   1753:   bcr = '\r';
                   1754:   if (! fconn_write (qconn, &bcr, 1))
                   1755:     ucuabort ();
                   1756: 
                   1757:   ubuffree (zcmd);
                   1758: 
                   1759:   /* Eliminated any previously echoed data to avoid confusion.  */
                   1760:   iPrecstart = 0;
                   1761:   iPrecend = 0;
                   1762: 
                   1763:   /* If we're dealing with a Unix system, we can reliably discard the
                   1764:      command.  Otherwise, the command will probably wind up in the
                   1765:      file; too bad.  */
                   1766:   if (pvar == NULL)
                   1767:     {
                   1768:       int b;
                   1769: 
                   1770:       while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n')
                   1771:        {
                   1772:          if (b == -2)
                   1773:            ucuabort ();
                   1774:          if (b < 0)
                   1775:            {
                   1776:              ucuputs ("[timed out waiting for newline]");
                   1777:              ucuputs (abCuconnected);
                   1778:              return UUCONF_CMDTABRET_CONTINUE;
                   1779:            }
                   1780:        }
                   1781:     }
                   1782: 
                   1783:   ceoflen = strlen (zeof);
                   1784:   zlook = zbufalc (ceoflen);
                   1785:   ceofhave = 0;
                   1786:   ferr = FALSE;
                   1787: 
                   1788:   while (TRUE)
                   1789:     {
                   1790:       int b;
                   1791: 
                   1792:       if (FGOT_SIGNAL ())
                   1793:        {
                   1794:          /* Make sure the signal is logged.  */
                   1795:          ulog (LOG_ERROR, (const char *) NULL);
                   1796:          ucuputs ("[file receive aborted]");
                   1797:          /* Reset the SIGINT flag so that it does not confuse us in
                   1798:             the future.  */
                   1799:          afSignal[INDEXSIG_SIGINT] = FALSE;
                   1800:          break;
                   1801:        }       
                   1802: 
                   1803:       b = breceive_char (qconn, cCuvar_timeout, TRUE);
                   1804:       if (b == -2)
                   1805:        ucuabort ();
                   1806:       if (b < 0)
                   1807:        {
                   1808:          if (ceofhave > 0)
                   1809:            (void) fwrite (zlook, sizeof (char), ceofhave, e);
                   1810:          ucuputs ("[timed out]");
                   1811:          break;
                   1812:        }
                   1813: 
                   1814:       if (ceoflen == 0)
                   1815:        {
                   1816:          if (cfilewrite (e, &b, 1) != 1)
                   1817:            {
                   1818:              ferr = TRUE;
                   1819:              break;
                   1820:            }
                   1821:        }
                   1822:       else
                   1823:        {
                   1824:          zlook[ceofhave] = b;
                   1825:          ++ceofhave;
                   1826:          if (ceofhave == ceoflen)
                   1827:            {
                   1828:              size_t cmove;
                   1829:              char *zmove;
                   1830: 
                   1831:              if (memcmp (zeof, zlook, ceoflen) == 0)
                   1832:                {
                   1833:                  ucuputs ("[file transfer complete]");
                   1834:                  break;
                   1835:                }
                   1836: 
                   1837:              if (cfilewrite (e, zlook, 1) != 1)
                   1838:                {
                   1839:                  ferr = TRUE;
                   1840:                  break;
                   1841:                }
                   1842: 
                   1843:              zmove = zlook;
                   1844:              for (cmove = ceoflen - 1, zmove = zlook;
                   1845:                   cmove > 0;
                   1846:                   cmove--, zmove++)
                   1847:                zmove[0] = zmove[1];
                   1848: 
                   1849:              --ceofhave;
                   1850:            }
                   1851:        }
                   1852:     }
                   1853: 
                   1854:   ubuffree (zlook);
                   1855: 
                   1856:   if (! ffileclose (e))
                   1857:     ferr = TRUE;
                   1858:   if (ferr)
                   1859:     ucuputs ("[file write error]");
                   1860: 
                   1861:   if (! fsysdep_cu_copy (TRUE)
                   1862:       || ! fsysdep_terminal_signals (FALSE))
                   1863:     ucuabort ();
                   1864: 
                   1865:   ucuputs (abCuconnected);
                   1866: 
                   1867:   return UUCONF_CMDTABRET_CONTINUE;
                   1868: }
                   1869: 
                   1870: /* Send a buffer to the remote system.  If fCuvar_binary is FALSE,
                   1871:    each buffer passed in will be a single line; in this case we can
                   1872:    check the echoed characters and kill the line if they do not match.
                   1873:    This returns FALSE if an echo check fails.  If a port error
                   1874:    occurrs, it calls ucuabort.  */
                   1875: 
                   1876: static boolean
                   1877: fcusend_buf (qconn, zbufarg, cbufarg)
                   1878:      struct sconnection *qconn;
                   1879:      const char *zbufarg;
                   1880:      size_t cbufarg;
                   1881: {
                   1882:   const char *zbuf;
                   1883:   size_t cbuf;
                   1884:   int ctries;
                   1885:   size_t cbplen;
                   1886:   char *zsendbuf;
                   1887: 
                   1888:   zbuf = zbufarg;
                   1889:   cbuf = cbufarg;
                   1890:   ctries = 0;
                   1891: 
                   1892:   if (fCuvar_binary)
                   1893:     cbplen = strlen (zCuvar_binary_prefix);
                   1894:   else
                   1895:     cbplen = 1;
                   1896:   zsendbuf = zbufalc (64 * (cbplen + 1));
                   1897: 
                   1898:   /* Loop while we still have characters to send.  The value of cbuf
                   1899:      will be reset to cbufarg if an echo failure occurs while sending
                   1900:      a line in non-binary mode.  */
                   1901:   while (cbuf > 0)
                   1902:     {
                   1903:       int csend;
                   1904:       char *zput;
                   1905:       const char *zget;
                   1906:       boolean fnl;
                   1907:       int i;
                   1908: 
                   1909:       if (FGOT_SIGNAL ())
                   1910:        {
                   1911:          /* Make sure the signal is logged.  */
                   1912:          ubuffree (zsendbuf);
                   1913:          ulog (LOG_ERROR, (const char *) NULL);
                   1914:          ucuputs ("[file send aborted]");
                   1915:          /* Reset the SIGINT flag so that it does not confuse us in
                   1916:             the future.  */
                   1917:          afSignal[INDEXSIG_SIGINT] = FALSE;
                   1918:          return FALSE;
                   1919:        }
                   1920: 
                   1921:       /* Discard anything we've read from the port up to now, to avoid
                   1922:         confusing the echo checking.  */
                   1923:       iPrecstart = 0;
                   1924:       iPrecend = 0;
                   1925: 
                   1926:       /* Send all characters up to a newline before actually sending
                   1927:         the newline.  This makes it easier to handle the special
                   1928:         newline echo checking.  Send up to 64 characters at a time
                   1929:         before doing echo checking.  */
                   1930:       if (*zbuf == '\n')
                   1931:        csend = 1;
                   1932:       else
                   1933:        {
                   1934:          const char *znl;
                   1935: 
                   1936:          znl = memchr (zbuf, '\n', cbuf);
                   1937:          if (znl == NULL)
                   1938:            csend = cbuf;
                   1939:          else
                   1940:            csend = znl - zbuf;
                   1941:          if (csend > 64)
                   1942:            csend = 64;
                   1943:        }
                   1944: 
                   1945:       /* Translate this part of the buffer.  If we are not in binary
                   1946:         mode, we translate \n to \r, and ignore any nonprintable
                   1947:         characters.  */
                   1948:       zput = zsendbuf;
                   1949:       fnl = FALSE;
                   1950:       for (i = 0, zget = zbuf; i < csend; i++, zget++)
                   1951:        {
                   1952:          if (isprint (*zget)
                   1953:              || *zget == '\t')
                   1954:            *zput++ = *zget;
                   1955:          else if (*zget == '\n')
                   1956:            {
                   1957:              if (fCuvar_binary)
                   1958:                *zput++ = '\n';
                   1959:              else
                   1960:                *zput++ = '\r';
                   1961:              fnl = TRUE;
                   1962:            }
                   1963:          else if (fCuvar_binary)
                   1964:            {
                   1965:              strcpy (zput, zCuvar_binary_prefix);
                   1966:              zput += cbplen;
                   1967:              *zput++ = *zget;
                   1968:            }
                   1969:        }
                   1970:                
                   1971:       zbuf += csend;
                   1972:       cbuf -= csend;
                   1973: 
                   1974:       if (zput == zsendbuf)
                   1975:        continue;
                   1976: 
                   1977:       /* Send the data over the port.  */
                   1978:       if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE))
                   1979:        ucuabort ();
                   1980: 
                   1981:       /* We do echo checking if requested, unless we are in binary
                   1982:         mode.  Echo checking of a newline is different from checking
                   1983:         of normal characters; when we send a newline we look for
                   1984:         *zCuvar_echonl.  */
                   1985:       if ((fCuvar_echocheck && ! fCuvar_binary)
                   1986:          || (fnl && *zCuvar_echonl != '\0'))
                   1987:        {
                   1988:          long iend;
                   1989: 
                   1990:          iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout;
                   1991:          for (zget = zsendbuf; zget < zput; zget++)
                   1992:            {
                   1993:              int bread;
                   1994:              int bwant;
                   1995: 
                   1996:              if (fCuvar_binary ? *zget == '\n' : *zget == '\r')
                   1997:                {
                   1998:                  bwant = *zCuvar_echonl;
                   1999:                  if (bwant == '\0')
                   2000:                    continue;
                   2001:                }
                   2002:              else
                   2003:                {
                   2004:                  if (! fCuvar_echocheck || ! isprint (*zget))
                   2005:                    continue;
                   2006:                  bwant = *zget;
                   2007:                }
                   2008: 
                   2009:              do
                   2010:                {
                   2011:                  if (FGOT_SIGNAL ())
                   2012:                    {
                   2013:                      /* Make sure the signal is logged.  */
                   2014:                      ubuffree (zsendbuf);
                   2015:                      ulog (LOG_ERROR, (const char *) NULL);
                   2016:                      ucuputs ("[file send aborted]");
                   2017:                      /* Reset the SIGINT flag so that it does not
                   2018:                         confuse us in the future.  */
                   2019:                      afSignal[INDEXSIG_SIGINT] = FALSE;
                   2020:                      return FALSE;
                   2021:                    }
                   2022: 
                   2023:                  bread = breceive_char (qconn,
                   2024:                                         iend - ixsysdep_time ((long *) NULL),
                   2025:                                         TRUE);
                   2026:                  if (bread < 0)
                   2027:                    {
                   2028:                      if (bread == -2)
                   2029:                        ucuabort ();
                   2030: 
                   2031:                      /* If we timed out, and we're not in binary
                   2032:                         mode, we kill the line and try sending it
                   2033:                         again from the beginning.  */
                   2034:                      if (! fCuvar_binary && *zCuvar_kill != '\0')
                   2035:                        {
                   2036:                          ++ctries;
                   2037:                          if (ctries < cCuvar_resend)
                   2038:                            {
                   2039:                              if (fCuvar_verbose)
                   2040:                                {
                   2041:                                  printf ("R ");
                   2042:                                  (void) fflush (stdout);
                   2043:                                }
                   2044:                              if (! fsend_data (qconn, zCuvar_kill, 1,
                   2045:                                                TRUE))
                   2046:                                ucuabort ();
                   2047:                              zbuf = zbufarg;
                   2048:                              cbuf = cbufarg;
                   2049:                              break;
                   2050:                            }
                   2051:                        }
                   2052:                      ubuffree (zsendbuf);
                   2053:                      ucuputs ("[timed out looking for echo]");
                   2054:                      return FALSE;
                   2055:                    }
                   2056:                }
                   2057:              while (bread != *zget);
                   2058: 
                   2059:              if (bread < 0)
                   2060:                break;
                   2061:            }
                   2062:        }
                   2063:     }
                   2064: 
                   2065:   ubuffree (zsendbuf);
                   2066: 
                   2067:   return TRUE;
                   2068: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.