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