1: #ifndef NOCMDL 2: /* C K U U S Y -- "User Interface" for Unix Kermit, part Y */ 3: 4: /* Command-Line Argument Parser */ 5: 6: /* 7: Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), 8: Columbia University Center for Computing Activities. 9: First released January 1985. 10: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New 11: York. Permission is granted to any individual or institution to use this 12: software as long as it is not sold for profit. This copyright notice must be 13: retained. This software may not be included in commercial products without 14: written permission of Columbia University. 15: */ 16: 17: #include "ckcdeb.h" 18: #include "ckcasc.h" 19: #include "ckcker.h" 20: #include "ckucmd.h" 21: #include "ckcnet.h" 22: 23: #ifdef NETCONN 24: #ifdef SUNX25 25: #include "ckcnet.h" 26: extern int revcall, closgr, cudata; 27: extern char udata[MAXCUDATA]; 28: extern int x25fd; 29: #endif /* SUNX25 */ 30: extern int telnetfd; 31: #endif /* NETCONN */ 32: 33: extern char *ckxsys, *ckzsys, *cmarg, *cmarg2, **xargv, **cmlist, *clcmds; 34: extern int action, cflg, xargc, stdouf, stdinf, displa, cnflg, nfils, 35: local, quiet, escape, network, mdmtyp, maxrps, rpsiz, bgset, xargs, 36: urpsiz, wslotr, swcapr, binary, warn, parity, turn, turnch, duplex, flow, 37: fncact, clfils, noinit, stayflg, nettype; 38: extern long speed, ttgspd(), zchki(); 39: extern char ttname[]; 40: 41: #ifndef NODIAL 42: extern int nmdm; 43: extern struct keytab mdmtab[]; 44: #endif /* NODIAL */ 45: 46: /* C M D L I N -- Get arguments from command line */ 47: /* 48: Simple Unix-style command line parser, conforming with 'A Proposed Command 49: Syntax Standard for Unix Systems', Hemenway & Armitage, Unix/World, Vol.1, 50: No.3, 1984. 51: */ 52: int 53: cmdlin() { 54: char x; /* Local general-purpose int */ 55: cmarg = ""; /* Initialize globals */ 56: cmarg2 = ""; 57: action = cflg = 0; 58: 59: /* If we were started directly from a Kermit application file, its name is */ 60: /* in argv[1], so skip past it. */ 61: 62: if (xargc > 1) { 63: if (*xargv[0] != '-' && *xargv[1] != '-') { 64: if ( 65: /* some shells don't put full pathname... */ 66: /* zchki(xargv[0]) > 0 && */ /* ...so skip this test */ 67: zchki(xargv[1]) > 0) { /* if it's an existing file */ 68: xargc -= 1; /* skip past it */ 69: xargv += 1; /* ... */ 70: } 71: } 72: } 73: 74: while (--xargc > 0) { /* Go through command line words */ 75: xargv++; 76: debug(F111,"xargv",*xargv,xargc); 77: if (**xargv == '=') return(0); 78: #ifdef VMS 79: else if (**xargv == '/') continue; 80: #endif /* VMS */ 81: else if (**xargv == '-') { /* Got an option (begins with dash) */ 82: x = *(*xargv+1); /* Get the option letter */ 83: if (doarg(x) < 0) doexit(BAD_EXIT,1); /* Go handle option */ 84: } else { /* No dash where expected */ 85: usage(); 86: doexit(BAD_EXIT,1); 87: } 88: } 89: debug(F101,"action","",action); 90: if (!local) { 91: if ((action == 'c') || (cflg != 0)) 92: fatal("-l and -b required"); 93: } 94: if (*cmarg2 != 0) { 95: if ((action != 's') && (action != 'r') && 96: (action != 'v')) 97: fatal("-a without -s, -r, or -g"); 98: } 99: if ((action == 'v') && (stdouf) && (!local)) { 100: if (isatty(1)) 101: fatal("unredirected -k can only be used in local mode"); 102: } 103: if ((action == 's') || (action == 'v') || 104: (action == 'r') || (action == 'x')) { 105: if (local) displa = 1; 106: if (stdouf) { displa = 0; quiet = 1; } 107: } 108: 109: if (quiet) displa = 0; /* No display if quiet requested */ 110: return(action); /* Then do any requested protocol */ 111: } 112: 113: /* D O A R G -- Do a command-line argument. */ 114: 115: int 116: #ifdef CK_ANSIC 117: doarg(char x) 118: #else 119: doarg(x) char x; 120: #endif /* CK_ANSIC */ 121: /* doarg */ { 122: int i, y, z; long zz; char *xp; 123: 124: xp = *xargv+1; /* Pointer for bundled args */ 125: while (x) { 126: switch (x) { 127: 128: #ifndef NOSPL 129: case 'C': /* Commands for parser */ 130: xargv++, xargc--; 131: if ((xargc < 1) || (**xargv == '-')) 132: fatal("No commands given for -C"); 133: clcmds = *xargv; /* Get the argument (must be quoted) */ 134: break; 135: #endif /* NOSPL */ 136: 137: #ifndef NOICP 138: case 'S': /* "Stay" - enter interactive */ 139: stayflg = 1; /* command parser after executing */ 140: break; /* command-line actions. */ 141: #endif /* NOICP */ 142: 143: #ifndef NOSERVER 144: case 'x': /* server */ 145: if (action) fatal("conflicting actions"); 146: action = 'x'; 147: break; 148: #endif /* NOSERVER */ 149: 150: case 'f': /* finish */ 151: if (action) fatal("conflicting actions"); 152: action = setgen('F',"","",""); 153: break; 154: 155: case 'r': /* receive */ 156: if (action) fatal("conflicting actions"); 157: action = 'v'; 158: break; 159: 160: case 'k': /* receive to stdout */ 161: if (action) fatal("conflicting actions"); 162: stdouf = 1; 163: action = 'v'; 164: break; 165: 166: case 's': /* send */ 167: if (action) fatal("conflicting actions"); 168: if (*(xp+1)) fatal("invalid argument bundling after -s"); 169: nfils = z = 0; /* Initialize file counter, flag */ 170: cmlist = xargv+1; /* Remember this pointer */ 171: while (--xargc > 0) { /* Traverse the list */ 172: xargv++; 173: if (**xargv == '-') { /* Check for sending stdin */ 174: if (strcmp(*xargv,"-") != 0) /* Watch out for next option. */ 175: break; 176: z++; /* "-" alone means send from stdin. */ 177: } else if (zchki(*xargv) > -1 /* Check if file exists */ 178: #ifndef UNIX 179: /* or contains wildcard characters matching real files */ 180: || (iswild(*xargv) && zxpand(*xargv) > 0) 181: #endif /* UNIX */ 182: ) { 183: nfils++; /* Bump file counter */ 184: } 185: } 186: xargc++, xargv--; /* Adjust argv/argc */ 187: if (nfils < 1 && z == 0) 188: #ifdef VMS 189: fatal("%CKERMIT-E-SEARCHFAIL, no files for -s"); 190: #else 191: fatal("No files for -s"); 192: #endif /* VMS */ 193: if (z > 1) fatal("-s: too many -'s"); 194: if (z == 1 && nfils > 0) 195: fatal("invalid mixture of filenames and '-' in -s"); 196: if (nfils == 0) { 197: if (isatty(0)) fatal("sending from terminal not allowed"); 198: else stdinf = 1; 199: } 200: 201: #ifdef COMMENT 202: /* If only one filespec was given, indicate "internal list" rather than */ 203: /* "expanded list", so in case it includes wildcards, C-Kermit can */ 204: /* expand them itself. */ 205: if (nfils == 1) { 206: cmarg = *cmlist; 207: nfils = -1; 208: } 209: #endif /* COMMENT */ 210: 211: debug(F101,*xargv,"",nfils); 212: action = 's'; 213: #ifdef UNIX 214: /* When set, this flag tells Kermit not to expand wildcard characters. */ 215: /* In UNIX, the shell has already expanded them. In VMS, OS/2, etc, */ 216: /* Kermit must expand them. Kermit must not expand them in UNIX because */ 217: /* a filename might itself contain metacharacters. Imagine, for example, */ 218: /* what would happen if a directory contained a file named "*". */ 219: clfils = 1; /* Flag for command-line files */ 220: #endif /* UNIX */ 221: break; 222: 223: case 'g': /* get */ 224: if (action) fatal("conflicting actions"); 225: if (*(xp+1)) fatal("invalid argument bundling after -g"); 226: xargv++, xargc--; 227: if ((xargc == 0) || (**xargv == '-')) 228: fatal("missing filename for -g"); 229: cmarg = *xargv; 230: action = 'r'; 231: break; 232: 233: case 'c': /* connect before */ 234: cflg = 1; 235: break; 236: 237: case 'n': /* connect after */ 238: cnflg = 1; 239: break; 240: 241: case 'h': /* help */ 242: usage(); 243: #ifndef NOICP 244: if (stayflg) 245: break; 246: else 247: #endif /* NOICP */ 248: doexit(GOOD_EXIT,-1); 249: 250: case 'a': /* "as" */ 251: if (*(xp+1)) fatal("invalid argument bundling after -a"); 252: xargv++, xargc--; 253: if ((xargc < 1) || (**xargv == '-')) 254: fatal("missing name in -a"); 255: cmarg2 = *xargv; 256: break; 257: 258: #ifndef NOICP 259: case 'Y': /* No initialization file */ 260: noinit = 1; 261: break; 262: 263: case 'y': /* Alternate init-file name */ 264: if (*(xp+1)) fatal("invalid argument bundling after -y"); 265: xargv++, xargc--; 266: if (xargc < 1) fatal("missing name in -y"); 267: /* strcpy(kermrc,*xargv); ...this was already done in prescan()... */ 268: break; 269: #endif /* NOICP */ 270: 271: case 'l': /* set line */ 272: #ifdef NETCONN 273: case 'X': /* set host to X.25 address */ 274: case 'Z': /* set host to X.25 file descriptor */ 275: case 'j': /* set host (TCP/IP socket) */ 276: #endif /* NETCONN */ 277: network = 0; 278: if (*(xp+1)) fatal("invalid argument bundling after -l or -j"); 279: xargv++, xargc--; 280: if ((xargc < 1) || (**xargv == '-')) 281: fatal("communication line device name missing"); 282: strcpy(ttname,*xargv); 283: local = (strcmp(ttname,CTTNAM) != 0); 284: if (x == 'l') { 285: if (ttopen(ttname,&local,mdmtyp,0) < 0) 286: fatal("can't open device"); 287: debug(F101,"cmdlin speed","",speed); 288: #ifdef COMMENT 289: /* What can it hurt? */ 290: if (speed < 0L) /* If speed hasn't been set yet, */ 291: #endif /* COMMENT */ 292: speed = ttgspd(); /* get it. */ 293: #ifdef NETCONN 294: } else { 295: if (x == 'j') { /* IP network host name */ 296: mdmtyp = -nettype; /* perhaps alread set in init file */ 297: telnetfd = 1; /* Or maybe an open file descriptor */ 298: #ifdef SUNX25 299: } else if (x == 'X') { /* X.25 address */ 300: mdmtyp = 0 - NET_SX25; 301: } else if (x == 'Z') { /* Open X.25 file descriptor */ 302: mdmtyp = 0 - NET_SX25; 303: x25fd = 1; 304: #endif /* SUNX25 */ 305: } 306: if (ttopen(ttname,&local,mdmtyp,0) < 0) 307: fatal("can't open host connection"); 308: network = 1; 309: #endif /* NETCONN */ 310: } 311: /* add more here later - decnet, etc... */ 312: break; 313: 314: #ifdef SUNX25 315: case 'U': /* X.25 call user data */ 316: if (*(xp+1)) fatal("invalid argument bundling"); 317: xargv++, xargc--; 318: if ((xargc < 1) || (**xargv == '-')) 319: fatal("missing call user data string"); 320: strcpy(udata,*xargv); 321: if ((int)strlen(udata) <= MAXCUDATA) cudata = 1; 322: else fatal("Invalid call user data"); 323: break; 324: 325: case 'o': /* X.25 closed user group */ 326: if (*(xp+1)) fatal("invalid argument bundling"); 327: xargv++, xargc--; 328: if ((xargc < 1) || (**xargv == '-')) 329: fatal("missing closed user group index"); 330: z = atoi(*xargv); /* Convert to number */ 331: if (z >= 0 && z <= 99) closgr = z; 332: else fatal("Invalid closed user group index"); 333: break; 334: 335: case 'u': /* X.25 reverse charge call */ 336: revcall = 1; 337: break; 338: #endif /* SUNX25 */ 339: 340: case 'b': /* set bits-per-second for serial */ 341: if (*(xp+1)) fatal("invalid argument bundling"); /* communication device */ 342: xargv++, xargc--; 343: if ((xargc < 1) || (**xargv == '-')) 344: fatal("missing baud"); 345: zz = atol(*xargv); /* Convert to long int */ 346: i = zz / 10L; 347: if (ttsspd(i) > -1) /* Check and set it */ 348: speed = zz; 349: else 350: fatal("unsupported transmission rate"); 351: break; 352: 353: #ifndef NODIAL 354: case 'm': /* Modem type */ 355: if (*(xp+1)) fatal("invalid argument bundling after -m"); 356: xargv++, xargc--; 357: if ((xargc < 1) || (**xargv == '-')) 358: fatal("modem type missing"); 359: y = lookup(mdmtab,*xargv,nmdm,&z); 360: if (y < 0) 361: fatal("unknown modem type"); 362: mdmtyp = y; 363: break; 364: #endif 365: 366: case 'e': /* Extended packet length */ 367: if (*(xp+1)) fatal("invalid argument bundling after -e"); 368: xargv++, xargc--; 369: if ((xargc < 1) || (**xargv == '-')) 370: fatal("missing length"); 371: z = atoi(*xargv); /* Convert to number */ 372: if (z > 10 && z <= maxrps) { 373: rpsiz = urpsiz = z; 374: if (z > 94) rpsiz = 94; /* Fallback if other Kermit can't */ 375: } else fatal("Unsupported packet length"); 376: break; 377: 378: case 'v': /* Vindow size */ 379: if (*(xp+1)) fatal("invalid argument bundling"); 380: xargv++, xargc--; 381: if ((xargc < 1) || (**xargv == '-')) 382: fatal("missing or bad window size"); 383: z = atoi(*xargv); /* Convert to number */ 384: if (z < 32) { /* If in range */ 385: wslotr = z; /* set it */ 386: if (z > 1) swcapr = 1; /* Set capas bit if windowing */ 387: } else fatal("Unsupported packet length"); 388: break; 389: 390: case 'i': /* Treat files as binary */ 391: binary = 1; 392: break; 393: 394: case 'w': /* Writeover */ 395: warn = 0; 396: fncact = XYFX_X; 397: break; 398: 399: case 'q': /* Quiet */ 400: quiet = 1; 401: break; 402: 403: #ifdef DEBUG 404: case 'd': /* debug */ 405: /** debopn("debug.log"); *** already did this in prescan() **/ 406: break; 407: #endif /* DEBUG */ 408: 409: case 'p': /* set parity */ 410: if (*(xp+1)) fatal("invalid argument bundling"); 411: xargv++, xargc--; 412: if ((xargc < 1) || (**xargv == '-')) 413: fatal("missing parity"); 414: switch(x = **xargv) { 415: case 'e': 416: case 'o': 417: case 'm': 418: case 's': parity = x; break; 419: case 'n': parity = 0; break; 420: default: fatal("invalid parity"); 421: } 422: break; 423: 424: case 't': 425: turn = 1; /* Line turnaround handshake */ 426: turnch = XON; /* XON is turnaround character */ 427: duplex = 1; /* Half duplex */ 428: flow = 0; /* No flow control */ 429: break; 430: 431: case 'z': /* Not background */ 432: bgset = 0; 433: break; 434: 435: default: 436: fatal("invalid argument, type 'kermit -h' for help"); 437: } 438: 439: x = *++xp; /* See if options are bundled */ 440: } 441: return(0); 442: } 443: #else /* No command-line interface... */ 444: 445: extern int xargc; 446: int 447: cmdlin() { 448: if (xargc > 1) printf("Sorry, command-line options disabled.\n"); 449: return(0); 450: } 451: #endif /* NOCMDL */