home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume35 / ncftp / part01 next >
Text File  |  1993-01-25  |  56KB  |  2,497 lines

  1. Newsgroups: comp.sources.misc
  2. From: mgleason@cse.unl.edu (Michael Gleason)
  3. Subject: v35i004:  ncftp - Alternative User Interface for FTP, Part01/04
  4. Message-ID: <csm-v35i004=ncftp.095334@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: e3a2b18b99720bdd10123e1feb0d6783
  6. Date: Mon, 25 Jan 1993 15:54:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mgleason@cse.unl.edu (Michael Gleason)
  10. Posting-number: Volume 35, Issue 4
  11. Archive-name: ncftp/part01
  12. Environment: UNIX, ANSI-C, getopt
  13. Supersedes: ncftp: Volume 34, Issue 14-16
  14.  
  15. ncftp - Alternative user interface for FTP
  16. version 1.0 PL 2 by Mike Gleason, NCEMRSoft.
  17.  
  18. Changes from 1.0 PL 1:
  19.  
  20.   * ls is more flexible, so now you can do things like "ls -flags directory."
  21.     Previous versions of ncftp (and ftp) only allowed "ls -flags" or
  22.     "ls directory."
  23.  
  24.   * Some new progress meters, a fancy bargraph and another similar to the
  25.     original % meter that shows how many kilobytes have been transferred.
  26.     This meter is also used when the remote site doesn't support the SIZE
  27.     command, so you can always have a progress meter.
  28.  
  29.   * If you don't want ftp and ncftp to share an rc, you can use a '.ncftprc'
  30.     for ncftp and a '.netrc' for ftp.
  31.  
  32.   * Better portability; in addition to support for DG/UX, NeXT, and DYNIX,
  33.     the getpass2() function which was causing problems has been replaced
  34.     by a more portable version.  Also using a private getopt which can be
  35.     called more than once.
  36.  
  37.   * Syslog'ging capability added for system administrators.
  38.  
  39.   * So many small enhancements and bug fixes that the patch is almost as
  40.     large as the shar-chive.  See patchlevel.h for the gory details.
  41.  
  42.  
  43. ncftp was created out of disgust with using the regular 'ftp'
  44. command found on many brands of Unix.  People who spend a lot
  45. of time in ftp will want to install ncftp.
  46.  
  47. Features:
  48.  
  49.  * No more typing 'anonymous' and your email address every time
  50.    you want to ftp anonymously.  You don't need to have the
  51.    site in your .netrc.
  52.    
  53.  * No more typing complete site names.  Sites in your .netrc
  54.    can be abbreviated.  Type 'o wuar' to call wuarchive.wustl.edu.
  55.  
  56.  * Use your pager (like 'more') to read remote files (and also
  57.    compressed files).
  58.  
  59.  * Use your pager to view remote directory listings.
  60.  
  61.  * Transfers feature a progress meter.
  62.  
  63.  * Implicit cd.
  64.  
  65.  * Fancy prompts.
  66.  
  67.  * You can keep a log of your actions.  See what the path was of
  68.    that file you downloaded yesterday so you don't have to
  69.    look for it today.
  70.  
  71.  * Built-in mini-nslookup.
  72.  
  73.  * The 'ls' command is ls -CF.  Some ftp's ls was identical to 'dir.'
  74.  
  75.  * You can 'redial' a remote host until you connect.
  76.  
  77.  * Don't need to 'close' a site, just open a new one.
  78.  
  79.  * Don't feel like typing a long filename?  Use a wildcard in single
  80.    file commands like get and page.
  81.  
  82.  * You can create empty remote files.
  83.  
  84.  * Supports 'colon mode', so you can type 'ncftp cse.unl.edu:/pub/foo',
  85.    to copy foo into your current directory.
  86.  
  87.  * You can re-display the last directory listing without getting it
  88.    across the network.
  89.  
  90.  * Detects when new mail arrives.
  91.  
  92.  * ncftp is quieter by default -- who cares if the PORT command was
  93.    successful (if you do, turn verbose on :-).
  94.  
  95.  * It can be compiled to log transfers, etc., to the system log.
  96. -------------
  97. #! /bin/sh
  98. # This is a shell archive.  Remove anything before this line, then feed it
  99. # into a shell via "sh file" or similar.  To overwrite existing files,
  100. # type "sh file -c".
  101. # Contents:  cmds.c ftp.h
  102. # Wrapped by kent@sparky on Mon Jan 25 09:48:02 1993
  103. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  104. echo If this archive is complete, you will see the following message:
  105. echo '          "shar: End of archive 1 (of 4)."'
  106. if test -f 'cmds.c' -a "${1}" != "-c" ; then 
  107.   echo shar: Will not clobber existing file \"'cmds.c'\"
  108. else
  109.   echo shar: Extracting \"'cmds.c'\" \(48279 characters\)
  110.   sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
  111. X/* cmds.c */
  112. X
  113. X#include "sys.h"
  114. X#include <sys/types.h>
  115. X#include <sys/param.h>
  116. X
  117. X#include <sys/wait.h>
  118. X
  119. X#include <sys/stat.h>
  120. X#include <sys/socket.h>
  121. X#include <arpa/ftp.h>
  122. X#include <setjmp.h>
  123. X#include <signal.h>
  124. X#include <string.h>
  125. X#include <errno.h>
  126. X#include <netdb.h>
  127. X#include <netinet/in.h>
  128. X#include <arpa/inet.h>
  129. X#include <ctype.h>
  130. X#include <sys/time.h>
  131. X#include <time.h>
  132. X
  133. X#ifdef SYSLOG
  134. X#    include <syslog.h>
  135. X#endif
  136. X
  137. X#ifndef NO_UNISTDH
  138. X#    include <unistd.h>
  139. X#endif
  140. X
  141. X#include "ftpdefs.h"
  142. X#include "defaults.h"
  143. X#include "cmds.h"
  144. X#include "main.h"
  145. X#include "ftp.h"
  146. X#include "ftprc.h"
  147. X#include "getpass.h"
  148. X#include "glob.h"
  149. X#include "copyright.h"
  150. X
  151. X/* cmds.c globals */
  152. Xint                    curtype;            /* file transfer type */
  153. Xstr32                curtypename;        /* name of file transfer type */
  154. Xint                    verbose;            /* print messages coming back from server */
  155. Xint                    mprompt;            /* interactively prompt on m* cmds */
  156. Xint                    debug;                /* debugging level */
  157. Xint                    options;            /* used during socket creation */
  158. Xint                    macnum;                /* number of defined macros */
  159. Xint                    paging = 0;
  160. Xint                    creating = 0;
  161. Xstruct macel        macros[16];
  162. Xchar                *macbuf;            /* holds ALL macros */
  163. Xjmp_buf                jabort;
  164. Xchar                *mname;                /* name of current m* command */
  165. Xint                    activemcmd;            /* flag: if != 0, then active multi command */
  166. Xstring                cwd;                /* current remote directory */
  167. Xstring                lcwd;                /* current local directory */
  168. Xchar                lasthostname[64];    /* name of last host w/ lookup(). */
  169. Xint                    remote_is_unix;        /* TRUE if remote host is unix. */
  170. Xint                    auto_binary = dAUTOBINARY;    /* If TRUE, set binary each connection. */
  171. Xint                    Opterr = 1;            /* if error message should be printed */
  172. Xint                    Optind = 1;            /* index into parent argv vector */
  173. Xint                    Optopt;                /* character checked for validity */
  174. Xchar                *Optarg;            /* argument associated with option */
  175. Xchar                *Optplace = EMSG;    /* saved position in an arg */
  176. X
  177. X#ifdef REDIR
  178. Xint                            is_ls = 0;        /* are we doing an ls?  if so, then buffer */
  179. Xstruct lslist               *lshead = NULL;    /* hold last output from host */
  180. Xstruct lslist               *lstail = NULL;
  181. X#endif
  182. X
  183. X/* cmds.c externs */
  184. Xextern char                    *globerr, *home, *reply_string;
  185. Xextern int                    code, margc, connected, ansi_escapes;
  186. Xextern int                    connected, fromatty, data, progress_meter;
  187. Xextern int                    parsing_rc;
  188. Xextern char                    *altarg, *line, *margv[];
  189. Xextern char                    *globchars;
  190. Xextern string                hostname, progname, pager, anon_password;
  191. Xextern string                prompt, logfname, version;
  192. Xextern long                    logsize, eventnumber;
  193. Xextern size_t                xferbufsize;
  194. Xextern struct servent        *sp;
  195. Xextern struct cmd            cmdtab[];
  196. Xextern struct userinfo        uinfo;
  197. Xextern FILE                    *cin, *cout, *logf;
  198. Xextern int                    Optind;
  199. Xextern char                    *Optarg;
  200. Xextern int gethostname (char *, int);
  201. Xextern int ioctl (int, int, ...);
  202. X
  203. Xstruct var vars[] = {
  204. X    { "anon-password",        STR,    0,    anon_password,    (setvarproc) 0    },
  205. X    { "ansi-escapes",        INT,    0,    &ansi_escapes,    (setvarproc) 0    },
  206. X    { "auto-binary",        INT,    0,    &auto_binary,    (setvarproc) 0    },
  207. X    { "debug",                INT,    0,    &debug,            (setvarproc) 0    },
  208. X    { "local-dir",            STR,    0,    lcwd,            set_ldir         },
  209. X    { "logfile",            STR,    0,    logfname,        set_log            },
  210. X    { "logsize",            LONG,    0,    &logsize,        (setvarproc) 0    },
  211. X    { "mprompt",            INT,    0,    &mprompt,        (setvarproc) 0    },
  212. X    { "pager",                STR,    0,    pager + 1,        set_pager        },
  213. X    { "prompt",                STR,    0,    prompt,            set_prompt        },
  214. X    { "progress-reports",    INT,    0,    &progress_meter,(setvarproc) 0    },
  215. X    { "remote-is-unix",        INT,    1,    &remote_is_unix,(setvarproc) 0    },
  216. X    { "type",                STR,    1,    curtypename,    set_type        },
  217. X    { "verbose",            INT,    0,    &verbose,        set_verbose        }
  218. X};
  219. X
  220. Xstruct types types[] = {
  221. X    { "ascii",  "A",    TYPE_A, 0 },
  222. X    { "binary", "I",    TYPE_I, 0 },
  223. X    { "image",  "I",    TYPE_I, 0 },
  224. X    { "ebcdic", "E",    TYPE_E, 0 },
  225. X    { "tenex",  "L",    TYPE_L, "8" },
  226. X    0
  227. X};
  228. X
  229. X
  230. X
  231. Xvoid Getopt_Reset(void)
  232. X{
  233. X    Optind = 1;
  234. X    Optplace = "";
  235. X}    /* Getopt_Reset */
  236. X
  237. X
  238. X
  239. Xint Getopt(int nargc, char **nargv, char *ostr)
  240. X{
  241. X    register char *oli;                   /* Option letter list index */
  242. X
  243. X    if (!*Optplace) {                       /* update scanning pointer */
  244. X        if (Optind >= nargc || *(Optplace = nargv[Optind]) != '-')
  245. X            return (EOF);
  246. X        if (Optplace[1] && *++Optplace == '-') {    /* found "--" */
  247. X            ++Optind;
  248. X            return (EOF);
  249. X        }
  250. X    }                                   /* Option letter okay? */
  251. X    if ((Optopt = (int) *Optplace++) == (int) ':' ||
  252. X        !(oli = index(ostr, Optopt))) {
  253. X        if (!*Optplace)
  254. X            ++Optind;
  255. X        if (Opterr) {
  256. X            fprintf(stderr, "%s%s%c\n", *nargv, ": illegal option -- ", Optopt);
  257. X            return(BADCH);
  258. X        }
  259. X    }
  260. X    if (*++oli != ':') {               /* don't need argument */
  261. X        Optarg = NULL;
  262. X        if (!*Optplace)
  263. X            ++Optind;
  264. X    } else {                           /* need an argument */
  265. X        if (*Optplace)                       /* no white space */
  266. X            Optarg = Optplace;
  267. X        else if (nargc <= ++Optind) {  /* no arg */
  268. X            Optplace = EMSG;
  269. X            if (Opterr) {
  270. X                fprintf(stderr, "%s%s%c\n", *nargv, ": option requires an argument -- ", Optopt);
  271. X                return(BADCH);
  272. X            }
  273. X        } else                           /* white space */
  274. X            Optarg = nargv[Optind];
  275. X        Optplace = EMSG;
  276. X        ++Optind;
  277. X    }
  278. X    return (Optopt);                   /* dump back Option letter */
  279. X}                                       /* Getopt */
  280. X
  281. X
  282. X
  283. X
  284. Xchar *Gets(char *sline, size_t size)
  285. X{
  286. X    char *cp = fgets(sline, (int) (size - 1), stdin);
  287. X    if (cp != NULL) {
  288. X        cp += strlen(cp) - 1;
  289. X        if (*cp == '\n')
  290. X            *cp = 0;    /* get rid of the newline. */
  291. X    }
  292. X    return cp;
  293. X}    /* Gets */
  294. X
  295. X
  296. X
  297. X
  298. Xchar **re_makeargv(char *promptstr, int *argc)
  299. X{
  300. X    size_t sz;
  301. X
  302. X    (void) strcat(line, " ");
  303. X    (void) printf(promptstr);
  304. X    sz = strlen(line);
  305. X    (void) Gets(&line[sz], (size_t) (CMDLINELEN - sz)) ;
  306. X    (void) makeargv();
  307. X    *argc = margc;
  308. X    return (margv);
  309. X}    /* re_makeargv */
  310. X
  311. X
  312. X
  313. X
  314. Xchar *get_cwd(char *buf, int size)
  315. X{
  316. X#ifdef SYSV
  317. X#    ifdef NO_UNISTDH
  318. X#        ifdef GETCWDSIZET
  319. X    extern char *getcwd(char *, size_t);
  320. X#        else
  321. X    extern char *getcwd(char *, int);
  322. X#        endif
  323. X#    endif
  324. X    return (getcwd(buf, size - 1));
  325. X#else
  326. X    extern char *getwd(char *);
  327. X    return (getwd(buf));
  328. X#endif
  329. X}   /* get_cwd */
  330. X
  331. X/*
  332. X * Connect to peer server and
  333. X * auto-login, if possible.
  334. X */
  335. X
  336. Xint setpeer(int argc, char **argv)
  337. X{
  338. X    char                *path;
  339. X    unsigned int        port;
  340. X    time_t                now;
  341. X    int                    openmode = 1, tmpverbose, opt, hErr;
  342. X    int                    redial_delay = dREDIALDELAY;
  343. X    int                    ignore_rc = 0, dials, max_dials = 1;
  344. X    string                pathname, newhost;
  345. X    char                *cmdname = argv[0];
  346. X
  347. X    port = sp->s_port;
  348. X    Getopt_Reset();
  349. X    while ((opt = Getopt(argc, argv, "aiup:rd:g:")) >= 0) {
  350. X        switch (opt) {
  351. X            case 'a': openmode = OPEN_A; break;
  352. X            case 'u': openmode = OPEN_U; break;
  353. X            case 'i': ignore_rc = 1; break;
  354. X            case 'p':
  355. X                port = atoi(Optarg);
  356. X                if (port <= 0) {
  357. X                    (void) printf("%s: bad port number (%s).\n", cmdname, Optarg);
  358. X                    goto usage;
  359. X                }
  360. X                port = htons(port);
  361. X                break;
  362. X            case 'd': redial_delay = atoi(Optarg); break;
  363. X            case 'g': max_dials = atoi(Optarg);  break;
  364. X            case 'r': max_dials = -1; break;
  365. X            default:
  366. X            usage:
  367. X                (void) printf("usage: %s [-a | -u] [-i] [-p N] [-r [-d N] [-g N]] hostname[:pathname]\n\
  368. X    -a     : Open anonymously (this is the default).\n\
  369. X    -u     : Open, specify user/password.\n\
  370. X    -i     : Ignore machine entry in your .netrc.\n\
  371. X    -p N   : Use port #N for connection.\n\
  372. X    -r     : \"Redial\" until connected.\n\
  373. X    -d N   : Redial, pausing N seconds between tries.\n\
  374. X    -g N   : Redial, giving up after N tries.\n\
  375. X    :path  : Open site, then retrieve file \"path.\"\n", cmdname);
  376. X                code = -1;
  377. X                return;
  378. X        }
  379. X    }
  380. X
  381. X    if (argv[Optind] == NULL)
  382. X        goto usage;
  383. X    (void) Strncpy(newhost, argv[Optind]);
  384. X    if (connected) {
  385. X        if (NOT_VQUIET && hostname != NULL)
  386. X            (void) printf("Closing %s...\n", hostname);
  387. X        (void) disconnect(0, NULL);
  388. X    }
  389. X
  390. X    /*
  391. X     *    If we are given something like wuarchive.wustl.edu:/pub/foo,
  392. X     *    try to connect to the site then first try to cd to /pub/foo,
  393. X     *    or if that fails, assume it is a file then try to fetch
  394. X     *    /pub/foo and write foo in the current local directory.
  395. X     */
  396. X    if ((path = index(newhost, ':')) != NULL) {
  397. X        *path++ = 0;
  398. X        (void) Strncpy(pathname, path);
  399. X    }
  400. X
  401. X    GetFullSiteName(newhost);
  402. X    for (dials = 0; max_dials < 0 || dials < max_dials; dials++) {
  403. X        if (dials > 0) {
  404. X            (void) sleep(redial_delay);
  405. X            (void) fprintf(stderr, "Retry Number: %d\n", dials + 1);
  406. X        }
  407. X        hErr = hookup(newhost, port);
  408. X        if (hErr == -2)        /* Recoverable, so we can try again. */
  409. X            continue;
  410. X        else if (hErr == 0) {
  411. X            connected = 1;
  412. X            tmpverbose = verbose;
  413. X            if (debug == 0)
  414. X                verbose = V_QUIET;
  415. X            remote_is_unix = 1;
  416. X            if (command("SYST") == COMPLETE) {
  417. X                if (tmpverbose == V_VERBOSE) {
  418. X                    register char *cp, c;
  419. X                    cp = index(reply_string+4, ' ');
  420. X                    if (cp == NULL)
  421. X                        cp = index(reply_string+4, '\r');
  422. X                    if (cp) {
  423. X                        if (cp[-1] == '.')
  424. X                            cp--;
  425. X                        c = *cp;
  426. X                        *cp = '\0';
  427. X                    }
  428. X    
  429. X                    (void) printf("Remote system type is %s.\n",
  430. X                        reply_string+4);
  431. X                    if (cp)
  432. X                        *cp = c;
  433. X                }
  434. X                remote_is_unix = !strncmp(reply_string + 4, "UNIX", (size_t) 4);
  435. X            }
  436. X    
  437. X            if (auto_binary || path || !strncmp(reply_string, "215 UNIX Type: L8", (size_t) 17)) {
  438. X                _settype("binary");
  439. X                if (tmpverbose > V_TERSE)
  440. X                    (void) printf("Using %s mode to transfer files.\n", curtypename);
  441. X            }
  442. X            if (tmpverbose >= V_ERRS && 
  443. X                !strncmp(reply_string, "215 TOPS20", (size_t) 10)) {
  444. X                (void) printf(
  445. X    "Remember to set tenex mode when transfering _binary_ files from this machine.\n");
  446. X            }
  447. X            verbose = tmpverbose;
  448. X
  449. X            if (!login(newhost, openmode, ignore_rc) || cout == NULL)
  450. X                goto nextdial;        /* error! */
  451. X            if (logf != NULL) {
  452. X                (void) time(&now);
  453. X                (void) fprintf(logf, "%s opened at %s",
  454. X                    hostname,
  455. X                    ctime(&now));
  456. X            }
  457. X
  458. X            /* Freshen 'cwd' variable for the prompt. */
  459. X            (void) _cd(NULL);
  460. X            if (path != NULL) {
  461. X                if (! _cd(pathname)) {
  462. X                    /* Couldn't cd to this path, must be a file then. */
  463. X                    (void) sprintf(line, "get %s", pathname);
  464. X                    makeargv();
  465. X                    (void) get(margc, margv);
  466. X                    /* If we were invoked from the command line, quit
  467. X                     * after we got this file.
  468. X                     */
  469. X                    if (eventnumber == 0L) {
  470. X                        (void) quit(0, NULL);
  471. X                    }
  472. X                }
  473. X            }
  474. X            break;
  475. X            /* end if we are connected */
  476. X        } else {
  477. X            /* Irrecoverable error, so don't bother redialing. */
  478. X            break;
  479. X        }
  480. Xnextdial: continue;
  481. X    }
  482. X}    /* setpeer */
  483. X
  484. X
  485. X/*
  486. X * Set transfer type.
  487. X */
  488. Xint settype(int argc, char **argv)
  489. X{
  490. X    if (argc > 2) {
  491. X        (void) printf("usage: %s [ ascii | binary | ebcdic | image | tenex ]\n", argv[0]);
  492. X        code = -1;
  493. X        return;
  494. X    }
  495. X    code = 0;
  496. X    if (argc < 2) {
  497. Xxx:        (void) printf("Using %s mode to transfer files.\n", curtypename);
  498. X        return;
  499. X    }
  500. X    _settype(argv[1]);
  501. X    if (IS_VVERBOSE)
  502. X        goto xx;
  503. X}    /* settype */
  504. X
  505. X
  506. X
  507. X
  508. Xvoid _settype(char *typename)
  509. X{
  510. X    register struct types    *p;
  511. X    int                        comret, i;
  512. X    string                    cmd;
  513. X    *cmd = 0;
  514. X    switch (isupper(*typename) ? tolower(*typename) : (*typename)) {
  515. X        case 'a': i = 0; break;
  516. X        case 'b': i = 1; break;
  517. X        case 'i': i = 2; break;
  518. X        case 'e': i = 3; break;
  519. X        case 't': i = 4;
  520. X            (void) strcpy(cmd, "TYPE L 8");
  521. X            break;
  522. X        default:
  523. X            (void) printf("%s: unknown type\n", typename);
  524. X            code = -1;
  525. X            return;
  526. X    }
  527. X    p = &types[i];
  528. X    if (*cmd == 0)
  529. X        (void) sprintf(cmd, "TYPE %s", p->t_mode);
  530. X    comret = command(cmd);
  531. X    if (comret == COMPLETE) {
  532. X        (void) Strncpy(curtypename, p->t_name);
  533. X        curtype = p->t_type;
  534. X    }
  535. X}    /* _settype */
  536. X
  537. X
  538. X
  539. X
  540. X/*ARGSUSED*/
  541. Xint setbinary(int argc, char **argv) {    _settype("binary");    }
  542. X/*ARGSUSED*/
  543. Xint setascii(int argc, char **argv) {    _settype("ascii");    }
  544. X
  545. X
  546. X
  547. Xchar *verbose_msgs[] = {
  548. X    "Only printing necessary error messages.\n",
  549. X    "Printing error messages and announcements from the remote host.\n",
  550. X    "Printing all messages, errors, acknowledgments, and announcements.\n"
  551. X};
  552. X
  553. Xvoid set_verbose(char *new, int unset)
  554. X{
  555. X    int i;
  556. X
  557. X    if (unset == -1) verbose = !verbose;
  558. X    else if (unset || !new || !*new) verbose = V_ERRS;
  559. X    else {
  560. X        i = StrToBool(new);
  561. X        if (i < V_QUIET) i = V_QUIET;
  562. X        else if (i > V_VERBOSE) i = V_VERBOSE;
  563. X        verbose = i;
  564. X    }
  565. X    if (!parsing_rc && NOT_VQUIET) 
  566. X        fputs(verbose_msgs[verbose], stdout);
  567. X}    /* set_verbose */
  568. X
  569. X
  570. X
  571. X
  572. Xvoid set_prompt(char *new, int unset)
  573. X{
  574. X    (void) Strncpy(prompt, (unset || !new || !*new) ? dPROMPT : new);
  575. X    init_prompt();
  576. X}    /* set_prompt */
  577. X
  578. X
  579. X
  580. X
  581. Xvoid set_log(char *fname, int unset)
  582. X{
  583. X    if (logf) {
  584. X        (void) fclose(logf);
  585. X        logf = NULL;
  586. X    }
  587. X    if (!unset && fname && *fname) {
  588. X        (void) Strncpy(logfname, fname);
  589. X        logf = fopen (logfname, "a");
  590. X    }
  591. X}    /* set_log */
  592. X
  593. X
  594. X
  595. X
  596. Xvoid set_pager(char *new, int unset)
  597. X{
  598. X    if (unset)
  599. X        (void) strcpy(pager, "-");
  600. X    else {
  601. X        if (!new)
  602. X            new = dPAGER;
  603. X        if (!*new)
  604. X            (void) strcpy(pager, "-");
  605. X        else if (*new != '-')
  606. X            (void) sprintf(pager, "|%s", (*new == '|' ? new + 1 : new));
  607. X    }
  608. X}    /* set_pager */
  609. X
  610. X
  611. X
  612. X
  613. Xvoid set_type(char *newtype, int unset)
  614. X{
  615. X    int t = verbose;
  616. X    verbose = V_QUIET;
  617. X    if (!connected && t > V_QUIET)
  618. X        (void) printf("Not connected.\n");
  619. X    else
  620. X        _settype(newtype && !unset ? newtype : "image");
  621. X    verbose = t;
  622. X}    /* set_type */
  623. X
  624. X
  625. X
  626. X
  627. Xvoid set_ldir(char *ldir, int unset)
  628. X{
  629. X    int t = verbose;
  630. X    char *argv[2];
  631. X
  632. X    if (ldir && !unset) {
  633. X        verbose = V_QUIET;
  634. X        argv[1] = ldir;
  635. X        lcd(2, argv);
  636. X        verbose = t;
  637. X    }
  638. X}    /* set_ldir */
  639. X
  640. X
  641. X
  642. X
  643. Xint set(int argc, char **argv)
  644. X{
  645. X    int unset, i, c;
  646. X    struct var *v;
  647. X    char *var, *val = NULL;
  648. X
  649. X    if (argc < 2 || strncmp(argv[1], "all", (size_t)3) == 0) {
  650. X        /* Show all variables. */
  651. X        for (i=0; i<sizeof(vars)/sizeof(struct var); i++) {
  652. X            (void) printf("%-20s= ", vars[i].name);
  653. X            c = vars[i].type;
  654. X            if (c < 0) c = -c;
  655. X            if (vars[i].conn_required && !connected)
  656. X                (void) printf("(not connected)\n");
  657. X            else switch (c) {
  658. X                case INT:
  659. X                    (void) printf("%d\n", *(int *)vars[i].var); break;
  660. X                case LONG:
  661. X                    (void) printf("%ld\n", *(long *)vars[i].var); break;
  662. X                case STR:
  663. X                    (void) printf("\"%s\"\n", (char *) vars[i].var); break;
  664. X            }
  665. X        }
  666. X    } else {
  667. X        unset = argv[0][0] == 'u';
  668. X        var = argv[1];
  669. X        if (argc == 2)
  670. X            val = NULL;
  671. X        else if (argc > 2) {
  672. X            /* could be =, value or just value. */
  673. X            if (*argv[2] == '=') {
  674. X                if (argc > 3)
  675. X                    val = argv[3];
  676. X                else return;    /* can't do 'set var =' */
  677. X            } else
  678. X                val = argv[2];
  679. X        }
  680. X        for (i=0, v=NULL; i<sizeof(vars)/sizeof(struct var); i++) {
  681. X            if (strncmp(vars[i].name, var, sizeof(vars[i].name)) == 0) {
  682. X                v = &vars[i];
  683. X                break;
  684. X            }
  685. X        }
  686. X        if (v == NULL) 
  687. X            (void) fprintf(stderr, "%s: unknown variable.\n", var);
  688. X        else {
  689. X            if (v->conn_required && !connected)
  690. X                (void) fprintf(stderr, "%s: must be connected.\n", var);
  691. X            else if (v->type < 0)    
  692. X                (void) fprintf(stderr, "%s: read-only variable.\n", var);
  693. X            else if (v->proc != (setvarproc) 0)
  694. X                (*v->proc)(val, unset);        /* a custom set proc. */
  695. X            else if (unset) switch(v->type) {
  696. X                case INT:
  697. X                    *(int *) v->var = 0; break;
  698. X                case LONG:
  699. X                    *(long *) v->var = 0; break;
  700. X                case STR:
  701. X                    *(char *) v->var = 0; break;
  702. X            } else {
  703. X                if (val == NULL) switch(v->type) {
  704. X                    /* User just said "set varname" */
  705. X                    case INT:
  706. X                        *(int *) v->var = 1; break;
  707. X                    case LONG:
  708. X                        *(long *) v->var = 1; break;
  709. X                    case STR:
  710. X                        *(char *) v->var = 0; break;
  711. X                } else {
  712. X                    /* User said "set varname = value" */
  713. X                    switch (v->type) {
  714. X                        case INT:
  715. X                            (void) sscanf(val, "%d", (int *) v->var); break;
  716. X                        case LONG:
  717. X                            (void) sscanf(val, "%ld", (long *) v->var); break;
  718. X                        case STR:
  719. X                            (void) strcpy(v->var, val); break;
  720. X                    }
  721. X                }
  722. X            }
  723. X        }
  724. X    }
  725. X}    /* set */
  726. X
  727. X
  728. X
  729. X
  730. X/*
  731. X * Send a single file.
  732. X */
  733. Xint put(int argc, char **argv)
  734. X{
  735. X    char *cmd;
  736. X    char *oldargv1;
  737. X
  738. X    if (argc == 2) {
  739. X        argc++;
  740. X        argv[2] = argv[1];
  741. X    }
  742. X    if (argc < 2)
  743. X        argv = re_makeargv("(local-file) ", &argc);
  744. X    if (argc < 2) {
  745. Xusage:
  746. X        (void) printf("usage:%s local-file remote-file\n", argv[0]);
  747. X        code = -1;
  748. X        return;
  749. X    }
  750. X    if (argc < 3)
  751. X        argv = re_makeargv("(remote-file) ", &argc);
  752. X    if (argc < 3) 
  753. X        goto usage;
  754. X    oldargv1 = argv[1];
  755. X    if (!globulize(&argv[1])) {
  756. X        code = -1;
  757. X        return;
  758. X    }
  759. X    /*
  760. X     * If "globulize" modifies argv[1], and argv[2] is a copy of
  761. X     * the old argv[1], make it a copy of the new argv[1].
  762. X     */
  763. X    if (argv[1] != oldargv1 && argv[2] == oldargv1) {
  764. X        argv[2] = argv[1];
  765. X    }
  766. X    cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
  767. X    sendrequest(cmd, argv[1], argv[2]);
  768. X}    /* put */
  769. X
  770. X
  771. X
  772. X
  773. X/*
  774. X * Send multiple files.
  775. X */
  776. Xint mput(int argc, char **argv)
  777. X{
  778. X    register int i;
  779. X    void (*oldintr)(int);
  780. X    char *tp;
  781. X
  782. X    if (argc < 2)
  783. X        argv = re_makeargv("(local-files) ", &argc);
  784. X    if (argc < 2) {
  785. X        (void) printf("usage:%s local-files\n", argv[0]);
  786. X        code = -1;
  787. X        return;
  788. X    }
  789. X    mname = argv[0];
  790. X    activemcmd = 1;
  791. X    oldintr = signal(SIGINT, (void (*)(int)) mabort);
  792. X    (void) setjmp(jabort);
  793. X    for (i = 1; i < argc; i++) {
  794. X        register char **cpp, **gargs;
  795. X
  796. X        gargs = glob(argv[i]);
  797. X        if (globerr != NULL) {
  798. X            (void) printf("%s\n", globerr);
  799. X            if (gargs) {
  800. X                blkfree(gargs);
  801. X                free(gargs);
  802. X            }
  803. X            continue;
  804. X        }
  805. X        for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  806. X            if (activemcmd && confirm(argv[0], *cpp)) {
  807. X                tp = *cpp;
  808. X                sendrequest("STOR", *cpp, tp);
  809. X                if (!activemcmd && fromatty) {
  810. X                    if (confirm("Continue with","mput")) {
  811. X                        activemcmd++;
  812. X                    }
  813. X                }
  814. X            }
  815. X        }
  816. X        if (gargs != NULL) {
  817. X            blkfree(gargs);
  818. X            free(gargs);
  819. X        }
  820. X    }
  821. X    (void) signal(SIGINT, oldintr);
  822. X    activemcmd = 0;
  823. X}    /* mput */
  824. X
  825. X
  826. X
  827. Xint tmp_name(char *str)
  828. X{
  829. X    (void) strcpy(str, "/tmp/ncftpXXXXXX");
  830. X    return (mktemp(str) == NULL);
  831. X}    /* tmp_name */
  832. X
  833. X
  834. X
  835. X
  836. Xint rem_glob_one(char *pattern)
  837. X{
  838. X    int            oldverbose, result = 0;
  839. X    char        *cp;
  840. X    string        str, tname;
  841. X    FILE        *ftemp;
  842. X
  843. X    /* Check for wildcard characters. */
  844. X    if (*pattern == '|' || strpbrk(pattern, globchars) == NULL)
  845. X        return 0;
  846. X
  847. X    (void) tmp_name(tname);
  848. X    oldverbose = verbose;
  849. X    verbose = V_QUIET;
  850. X    recvrequest ("NLST", tname, pattern, "w");
  851. X    verbose = oldverbose;
  852. X    ftemp = fopen(tname, "r");
  853. X    if (ftemp == NULL || FGets(str, ftemp) == NULL) {
  854. X        if (NOT_VQUIET)
  855. X            (void) printf("%s: no match.\n", pattern);
  856. X        result = -1;
  857. X        goto done;
  858. X    }
  859. X    if ((cp = index(str, '\n')) != NULL)
  860. X        *cp = '\0';
  861. X    (void) strcpy(pattern, str);
  862. X    cp = FGets(str, ftemp);
  863. X    /* It is an error if the pattern matched more than one file. */
  864. X    if (cp != NULL) {
  865. X        if (NOT_VQUIET)
  866. X            (void) printf("?Ambiguous remote file name.\n");
  867. X        result = -2;
  868. X    }
  869. Xdone:
  870. X    if (ftemp != NULL)
  871. X        (void) fclose(ftemp);
  872. X    (void) unlink(tname);
  873. X    return (result);
  874. X}    /* rem_glob_one */
  875. X
  876. X
  877. X
  878. X
  879. X/*
  880. X * Receive (and maybe page) one file.
  881. X */
  882. Xint get(int argc, char **argv)
  883. X{
  884. X    string local_file;
  885. X    string remote_file;
  886. X
  887. X    /* paging mode is set if the command name is 'page' or 'more.' */
  888. X    paging = (**argv != 'g');
  889. X
  890. X    if (argc < 2)
  891. X        argv = re_makeargv("(remote-file) ", &argc);
  892. X
  893. X    if (argc < 2) {
  894. X        if (paging)
  895. X            (void) printf("usage: %s remote-file\n", argv[0]);
  896. X        else {
  897. Xgetusage:
  898. X                (void) printf("usage: %s remote-file [local-file]\n", argv[0]);
  899. X        }
  900. X        return;
  901. X    }
  902. X    argv[1] = Strncpy(remote_file, argv[1]);
  903. X    if (rem_glob_one(argv[1]) < 0)
  904. X        return;
  905. X
  906. X    if (paging) {
  907. X        size_t len = strlen(remote_file);
  908. X
  909. X        /* Run compressed remote files through zcat, then the pager. */
  910. X        if (strlen(remote_file) > 2 && remote_file[len - 1] == 'Z' && remote_file[len - 2] == '.') {
  911. X            _settype("b");
  912. X            (void) sprintf(local_file, "|%s", ZCAT);
  913. X            argv[2] = Strncat(local_file, pager);
  914. X        } else
  915. X            argv[2] = pager;
  916. X    } else {
  917. X        /* normal get */
  918. X        if (argc == 2) {
  919. X            (void) Strncpy(local_file, argv[1]);
  920. X            argv[2] = local_file;
  921. X        } else {
  922. X            if (argc < 3)
  923. X                argv = re_makeargv("(local-file) ", &argc);
  924. X            if (argc < 3) 
  925. X                goto getusage;
  926. X            if (!globulize(&argv[2])) {
  927. X                code = -1;
  928. X                return;
  929. X            }
  930. X        }
  931. X    }
  932. X    recvrequest("RETR", argv[2], argv[1], "w");
  933. X    paging = 0;
  934. X}    /* get */
  935. X
  936. X
  937. X
  938. X/*ARGSUSED*/
  939. Xvoid mabort(int unused)
  940. X{
  941. X    (void) printf("\n");
  942. X    (void) fflush(stdout);
  943. X    if (activemcmd && fromatty) {
  944. X        if (confirm("Continue with", mname)) {
  945. X            longjmp(jabort,0);
  946. X        }
  947. X    }
  948. X    activemcmd = 0;
  949. X    longjmp(jabort,0);
  950. X}    /* mabort */
  951. X
  952. X
  953. X
  954. X
  955. X/*
  956. X * Get multiple files.
  957. X */
  958. Xint mget(int argc, char **argv)
  959. X{
  960. X    char *cp, *tp;
  961. X    void (*oldintr)(int);
  962. X
  963. X    if (argc < 2)
  964. X        argv = re_makeargv("(remote-files) ", &argc);
  965. X    if (argc < 2) {
  966. X        (void) printf("usage:%s remote-files\n", argv[0]);
  967. X        code = -1;
  968. X        return;
  969. X    }
  970. X    mname = argv[0];
  971. X    activemcmd = 1;
  972. X    oldintr = signal(SIGINT,mabort);
  973. X    (void) setjmp(jabort);
  974. X    while ((cp = remglob(argv)) != NULL) {
  975. X        if (*cp == '\0') {
  976. X            activemcmd = 0;
  977. X            continue;
  978. X        }
  979. X        if (activemcmd && confirm(argv[0], cp)) {
  980. X            tp = cp;
  981. X            recvrequest("RETR", tp, cp, "w");
  982. X            if (!activemcmd && fromatty) {
  983. X                if (confirm("Continue with","mget")) {
  984. X                    activemcmd++;
  985. X                }
  986. X            }
  987. X        }
  988. X    }
  989. X    (void) signal(SIGINT,oldintr);
  990. X    activemcmd = 0;
  991. X}    /* mget */
  992. X
  993. X
  994. X
  995. X
  996. Xchar *remglob(char *argv[])
  997. X{
  998. X    static FILE            *ftemp = NULL;
  999. X    int                    oldverbose;
  1000. X    char                *cp, *mode;
  1001. X    static string        tmpname, str;
  1002. X
  1003. X    if (!activemcmd) {
  1004. Xxx:
  1005. X        if (ftemp) {
  1006. X            (void) fclose(ftemp);
  1007. X            ftemp = NULL;
  1008. X            (void) unlink(tmpname);
  1009. X        }
  1010. X        return(NULL);
  1011. X    }
  1012. X    if (ftemp == NULL) {
  1013. X        (void) tmp_name(tmpname);
  1014. X        oldverbose = verbose, verbose = V_QUIET;
  1015. X        for (mode = "w"; *++argv != NULL; mode = "a")
  1016. X            recvrequest ("NLST", tmpname, *argv, mode);
  1017. X        verbose = oldverbose;
  1018. X        ftemp = fopen(tmpname, "r");
  1019. X        if (ftemp == NULL) {
  1020. X            (void) printf("Can't find list of remote files (%s), oops.\n", tmpname);
  1021. X            return (NULL);
  1022. X        }
  1023. X    }
  1024. X    if (FGets(str, ftemp) == NULL) 
  1025. X        goto xx;
  1026. X    if ((cp = index(str, '\n')) != NULL)
  1027. X        *cp = '\0';
  1028. X    return (str);
  1029. X}    /* remglob */
  1030. X
  1031. X
  1032. X
  1033. X
  1034. Xchar *
  1035. Xonoff(int boolf)
  1036. X{
  1037. X    return (boolf ? "on" : "off");
  1038. X}   /* onoff */
  1039. X
  1040. X
  1041. X
  1042. X
  1043. Xint
  1044. XStrToBool(char *s)
  1045. X{
  1046. X    register char c;
  1047. X
  1048. X    c = *s | 32;            /* lcase(*value) */
  1049. X    switch (c) {
  1050. X        case 'f':           /* false */
  1051. X            return (0);
  1052. X        case 'o':           /* test for "off" and "on" */
  1053. X            c = s[1] | 32;
  1054. X            return(c == 'f' ? 0 : 1);
  1055. X        case 't':           /* true */
  1056. X            return (1);
  1057. X        default:            /* 1, 0, -1, other number? */
  1058. X            return (atoi(s));
  1059. X    }
  1060. X}   /* StrToBool */
  1061. X
  1062. X
  1063. X/*
  1064. X * Turn on/off printing of server echo's, messages, and statistics.
  1065. X */
  1066. Xint setverbose(int argc, char **argv)
  1067. X{
  1068. X    if (argc > 1)
  1069. X        set_verbose(argv[1], 0);
  1070. X    else set_verbose(argv[1], -1);
  1071. X    code = verbose;
  1072. X}    /* setverbose */
  1073. X
  1074. X
  1075. X
  1076. X/*
  1077. X * Toggle interactive prompting
  1078. X * during mget, mput, and mdelete.
  1079. X */
  1080. Xint setprompt(int argc, char **argv)
  1081. X{
  1082. X    if (argc > 1)
  1083. X        mprompt = StrToBool(argv[1]);
  1084. X    else mprompt = !mprompt;
  1085. X    if (IS_VVERBOSE)
  1086. X        (void) printf("Interactive prompting for m* commmands %s.\n", onoff(mprompt));
  1087. X    code = mprompt;
  1088. X}    /* setprompt */
  1089. X
  1090. X
  1091. X/*
  1092. X * Set debugging mode on/off and/or
  1093. X * set level of debugging.
  1094. X */
  1095. Xint setdebug(int argc, char **argv)
  1096. X{
  1097. X    int val;
  1098. X
  1099. X    if (argc > 1) {
  1100. X        val = StrToBool(argv[1]);
  1101. X        if (val < 0) {
  1102. X            (void) printf("%s: bad debugging value.\n", argv[1]);
  1103. X            code = -1;
  1104. X            return;
  1105. X        }
  1106. X    } else
  1107. X        val = !debug;
  1108. X    debug = val;
  1109. X    fix_options();
  1110. X    if (IS_VVERBOSE)
  1111. X        (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  1112. X    code = debug > 0;
  1113. X}    /* debug */
  1114. X
  1115. X
  1116. X
  1117. Xvoid fix_options(void)
  1118. X{
  1119. X    if (debug)
  1120. X        options |= SO_DEBUG;
  1121. X    else
  1122. X        options &= ~SO_DEBUG;
  1123. X}    /* fix_options */
  1124. X
  1125. X
  1126. X
  1127. X/*
  1128. X * Set current working directory
  1129. X * on remote machine.
  1130. X */
  1131. Xint cd(int argc, char **argv)
  1132. X{
  1133. X    if (argc < 2)
  1134. X        argv = re_makeargv("(remote-directory) ", &argc);
  1135. X    if (argc < 2) {
  1136. X        (void) printf("usage:%s remote-directory\n", argv[0]);
  1137. X        code = -1;
  1138. X        return;
  1139. X    }
  1140. X    (void) _cd(argv[1]);
  1141. X}    /* cd */
  1142. X
  1143. X
  1144. X
  1145. X
  1146. Xint implicit_cd(char *dir)
  1147. X{
  1148. X    int i, j = 0;
  1149. X    
  1150. X    if (connected) {
  1151. X        i = verbose;
  1152. X        /* Special verbosity level that ignores errors and prints other stuff,
  1153. X         * so you will get just the unknown command message and not an error
  1154. X         * message from cd.
  1155. X         */
  1156. X        verbose = V_IMPLICITCD;
  1157. X        j = _cd(dir);
  1158. X        verbose = i;
  1159. X    }
  1160. X    return j;
  1161. X}    /* implicit_cd */
  1162. X
  1163. X
  1164. X
  1165. X
  1166. Xint _cd(char *dir)
  1167. X{
  1168. X    register char *cp;
  1169. X    int result = 0, tmpverbose;
  1170. X    string str;
  1171. X
  1172. X    if (dir == NULL)
  1173. X        goto getrwd;
  1174. X    /* Won't work because glob really is a ls, so 'cd pu*' will match
  1175. X     * pub/README, pub/file2, etc.
  1176. X     *    if (result = rem_glob_one(dir) < 0)
  1177. X     *    return result;
  1178. X     */
  1179. X    if (strncmp(dir, "CDUP", (size_t) 4) == 0)
  1180. X        (void) Strncpy(str, dir);
  1181. X    else
  1182. X        (void) sprintf(str, "CWD %s", dir);
  1183. X    if (command(str) != 5) {
  1184. Xgetrwd:
  1185. X        /* (void) Strncpy(cwd, dir); */
  1186. X        tmpverbose = verbose; verbose = V_QUIET;
  1187. X        (void) command("PWD");
  1188. X        verbose = tmpverbose;
  1189. X        cp = rindex(reply_string, '\"');
  1190. X        if (cp != NULL) {
  1191. X            result = 1;
  1192. X            *cp = '\0';
  1193. X            cp = index(reply_string, '\"');
  1194. X            if (cp != NULL)
  1195. X                (void) Strncpy(cwd, ++cp);
  1196. X        }
  1197. X    }
  1198. X    if (debug > 0)
  1199. X        (void) printf("---> Current remote directory is \"%s\"\n", cwd);
  1200. X    return (result);
  1201. X}    /* _cd */
  1202. X
  1203. X
  1204. X
  1205. X
  1206. X/*
  1207. X * Set current working directory
  1208. X * on local machine.
  1209. X */
  1210. Xint lcd(int argc, char **argv)
  1211. X{
  1212. X    if (argc < 2)
  1213. X        argc++, argv[1] = home;
  1214. X    if (argc != 2) {
  1215. X        (void) printf("usage:%s local-directory\n", argv[0]);
  1216. X        code = -1;
  1217. X        return;
  1218. X    }
  1219. X    if (!globulize(&argv[1])) {
  1220. X        code = -1;
  1221. X        return;
  1222. X    }
  1223. X    if (chdir(argv[1]) < 0) {
  1224. X        Perror(argv[1]);
  1225. X        code = -1;
  1226. X        return;
  1227. X    }
  1228. X    (void) get_cwd(lcwd, (int) sizeof(lcwd));
  1229. X    if (IS_VVERBOSE) 
  1230. X        (void) printf("Local directory now %s\n", lcwd);
  1231. X    code = 0;
  1232. X}    /* lcd */
  1233. X
  1234. X
  1235. X
  1236. X
  1237. X/*
  1238. X * Delete a single file.
  1239. X */
  1240. Xint do_delete(int argc, char **argv)
  1241. X{
  1242. X    string str;
  1243. X
  1244. X    if (argc < 2)
  1245. X        argv = re_makeargv("(remote file to delete) ", &argc);
  1246. X    if (argc < 2) {
  1247. X        (void) printf("usage:%s remote-file\n", argv[0]);
  1248. X        code = -1;
  1249. X        return;
  1250. X    }
  1251. X    if (rem_glob_one(argv[1]) == 0) {
  1252. X        (void) sprintf(str, "DELE %s", argv[1]);
  1253. X        (void) command(str);
  1254. X    }
  1255. X}    /* do_delete */
  1256. X
  1257. X
  1258. X
  1259. X
  1260. X/*
  1261. X * Delete multiple files.
  1262. X */
  1263. Xint mdelete(int argc, char **argv)
  1264. X{
  1265. X    char *cp;
  1266. X    void (*oldintr)(int);
  1267. X    string str;
  1268. X
  1269. X    if (argc < 2)
  1270. X        argv = re_makeargv("(remote-files) ", &argc);
  1271. X    if (argc < 2) {
  1272. X        (void) printf("usage:%s remote-files\n", argv[0]);
  1273. X        code = -1;
  1274. X        return;
  1275. X    }
  1276. X    mname = argv[0];
  1277. X    activemcmd = 1;
  1278. X    oldintr = signal(SIGINT, mabort);
  1279. X    (void) setjmp(jabort);
  1280. X    while ((cp = remglob(argv)) != NULL) {
  1281. X        if (*cp == '\0') {
  1282. X            activemcmd = 0;
  1283. X            continue;
  1284. X        }
  1285. X        if (activemcmd && confirm(argv[0], cp)) {
  1286. X            (void) sprintf(str, "DELE %s", cp);
  1287. X            (void) command(str);
  1288. X            if (!activemcmd && fromatty) {
  1289. X                if (confirm("Continue with", "mdelete")) {
  1290. X                    activemcmd++;
  1291. X                }
  1292. X            }
  1293. X        }
  1294. X    }
  1295. X    (void) signal(SIGINT, oldintr);
  1296. X    activemcmd = 0;
  1297. X}    /* mdelete */
  1298. X
  1299. X
  1300. X
  1301. X
  1302. X/*
  1303. X * Rename a remote file.
  1304. X */
  1305. Xint renamefile(int argc, char **argv)
  1306. X{
  1307. X    string str;
  1308. X
  1309. X    if (argc < 2)
  1310. X        argv = re_makeargv("(from-name) ", &argc);
  1311. X    if (argc < 2) {
  1312. Xusage:
  1313. X        (void) printf("%s from-name to-name\n", argv[0]);
  1314. X        code = -1;
  1315. X        return;
  1316. X    }
  1317. X    if (argc < 3)
  1318. X        argv = re_makeargv("(to-name) ", &argc);
  1319. X    if (argc < 3)
  1320. X        goto usage;
  1321. X    if (rem_glob_one(argv[1]) < 0)
  1322. X        return;
  1323. X    (void) sprintf(str, "RNFR %s", argv[1]);
  1324. X    if (command(str) == CONTINUE) {
  1325. X        (void) sprintf(str, "RNTO %s", argv[1]);
  1326. X        (void) command(str);
  1327. X    }
  1328. X}    /* renamefile */
  1329. X
  1330. X
  1331. X
  1332. X/*
  1333. X * Get a directory listing
  1334. X * of remote files.
  1335. X */
  1336. Xint ls(int argc, char **argv)
  1337. X{
  1338. X    char        *whichcmd, *cp;
  1339. X    str32        lsflags;
  1340. X    string        remote, local, str;
  1341. X    int            listmode, pagemode, i;
  1342. X
  1343. X#ifdef REDIR
  1344. X    register struct lslist *a, *b;
  1345. X    for (a = lshead; a != NULL; ) {
  1346. X        b = a->next;
  1347. X        if (a->string)
  1348. X            free(a->string);    /* free string */
  1349. X        free(a);                  /* free node */
  1350. X        a = b;
  1351. X    }
  1352. X    lshead = lstail = NULL;
  1353. X#endif
  1354. X
  1355. X    pagemode = 0;
  1356. X    switch (**argv) {
  1357. X        case 'p':                            /* pls, pdir, pnlist */
  1358. X            pagemode = 1;
  1359. X            listmode = argv[0][1] == 'd';
  1360. X            break;
  1361. X        case 'd':                            /* dir */
  1362. X            listmode = 1;
  1363. X            break;
  1364. X        default:                            /* ls, nlist */
  1365. X            listmode = 0;
  1366. X    }
  1367. X    whichcmd = listmode ? "LIST" : "NLST";
  1368. X
  1369. X    (void) strncpy(local, (pagemode ? pager : "-"), sizeof(local));
  1370. X    remote[0] = lsflags[0] = 0;
  1371. X    
  1372. X    /* Possible scenarios:
  1373. X     *  1.    ls
  1374. X     *  2.    ls -flags
  1375. X     *  3.    ls directory
  1376. X     *  4.  ls -flags >outfile
  1377. X     *  5.  ls directory >outfile
  1378. X     *  6.  ls -flags directory
  1379. X     *  7.  ls -flags directory >outfile
  1380. X     */
  1381. X
  1382. X    for (i=1; i<argc; i++) {
  1383. X        switch (argv[i][0]) {
  1384. X            case '-': 
  1385. X                /*
  1386. X                 * If you give more than one set of flags, concat the each
  1387. X                 * additional set to the first one (without the dash).
  1388. X                 */
  1389. X                (void) strncat(lsflags, (argv[i] + (lsflags[0] == '-')), sizeof(lsflags));
  1390. X                break;
  1391. X            case '|':
  1392. X            case '>': (void) Strncpy(local, argv[i] + (argv[i][0] == '>')); break;
  1393. X            default:  
  1394. X                if (remote[0] != 0) {
  1395. X                    printf("ls: only one directory at a time please (or don't forget the '>' in >outfile).\n");
  1396. Xlsusage:
  1397. X                    (void) printf("usage: %s [-flags] [remote-directory] [>local-file]\n", argv[0]);
  1398. X                    code = -1;
  1399. X                    return;
  1400. X                }
  1401. X                /*
  1402. X                 * In case you want to get a remote file called '--README--'
  1403. X                 * or '>README,' you can use '\--README--' and '\>README.'
  1404. X                 */
  1405. X                (void) strncpy(remote, ((argv[i][0] == '\\') && (argv[i][1] != 0)) ? argv[i] + 1 : argv[i], sizeof(remote));
  1406. X        }    /* end switch */    
  1407. X    }        /* end loop */
  1408. X
  1409. X    /*
  1410. X     *    If we are given an ls with some flags, make sure we use 
  1411. X     *    columnized output (-C) unless one column output (-1) is
  1412. X     *    specified.
  1413. X     */
  1414. X    if (!listmode) {
  1415. X        if (lsflags[0] != 0) {
  1416. X            (void) Strncpy(str, lsflags);
  1417. X            for (cp = str + 1; *cp; cp++)
  1418. X                if (*cp == '1')
  1419. X                    goto aa;
  1420. X            (void) sprintf(lsflags, "-FC%s", str + 1);
  1421. X        } else {
  1422. X            if (remote_is_unix)
  1423. X                (void) strcpy(lsflags, "-FC");
  1424. X        }
  1425. X    }
  1426. Xaa:    if (strcmp(local, "-") != 0) {
  1427. X        char *lp = local;
  1428. X
  1429. X        if ((!globulize(&lp)) || ((local[0] != '|') && (!confirm("Output to local-file: ", local)))) {
  1430. X            code = -1;
  1431. X            return;
  1432. X        } 
  1433. X        if (lp != local) {
  1434. X            (void) Strncpy(str, lp);
  1435. X            (void) Strncpy(local, str);
  1436. X        }
  1437. X    }
  1438. X#ifdef REDIR
  1439. X    is_ls=1; /* tells getreply() to buffer output on a lshead list */
  1440. X#endif
  1441. X    (void) Strncpy(str, remote);
  1442. X    if (lsflags[0] && remote[0])
  1443. X        (void) sprintf(remote, "%s%c%s", lsflags, LS_FLAGS_AND_FILE, str);
  1444. X    else
  1445. X        (void) strncpy(remote, lsflags[0] ? lsflags : str, sizeof(remote));
  1446. X    recvrequest(whichcmd, local, (remote[0] == 0 ? NULL : remote), "w");
  1447. X#ifdef REDIR
  1448. X    is_ls=0;
  1449. X#endif
  1450. X}    /* ls */
  1451. X
  1452. X
  1453. X
  1454. X
  1455. X/*
  1456. X * Get a directory listing
  1457. X * of multiple remote files.
  1458. X */
  1459. Xint mls(int argc, char **argv)
  1460. X{
  1461. X    char *cmd, mode[1], *dest;
  1462. X    int i;
  1463. X    void (*oldintr)(int);
  1464. X
  1465. X    if (argc < 2)
  1466. X        argv = re_makeargv("(remote-files) ", &argc);
  1467. X    if (argc < 3)
  1468. X        argv = re_makeargv("(local-file) ", &argc);
  1469. X    if (argc < 3) {
  1470. X        (void) printf("usage:%s remote-files local-file\n", argv[0]);
  1471. X        code = -1;
  1472. X        return;
  1473. X    }
  1474. X    dest = argv[argc - 1];
  1475. X    argv[argc - 1] = NULL;
  1476. X    if (strcmp(dest, "-") && *dest != '|')
  1477. X        if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
  1478. X            code = -1;
  1479. X            return;
  1480. X    }
  1481. X    cmd = argv[0][1] != 'd' ? "NLST" : "LIST";
  1482. X    mname = argv[0];
  1483. X    activemcmd = 1;
  1484. X    oldintr = signal(SIGINT, mabort);
  1485. X    (void) setjmp(jabort);
  1486. X    for (i = 1; activemcmd && i < argc-1; ++i) {
  1487. X        *mode = (i == 1) ? 'w' : 'a';
  1488. X        recvrequest(cmd, dest, argv[i], mode);
  1489. X        if (!activemcmd && fromatty) {
  1490. X            if (confirm("Continue with", argv[0])) {
  1491. X                activemcmd++;
  1492. X            }
  1493. X        }
  1494. X    }
  1495. X    (void) signal(SIGINT, oldintr);
  1496. X    activemcmd = 0;
  1497. X}    /* mls */
  1498. X
  1499. X
  1500. X
  1501. X
  1502. X/*
  1503. X * Do a shell escape
  1504. X */
  1505. X/*ARGSUSED*/
  1506. Xint shell(int argc, char **argv)
  1507. X{
  1508. X    int                pid;
  1509. X    void            (*old1)(int), (*old2)(int);
  1510. X    char            *theShell, *namep;
  1511. X#ifndef U_WAIT
  1512. X    int                Status;
  1513. X#else
  1514. X    union wait        Status;
  1515. X#endif
  1516. X    string            str;
  1517. X
  1518. X    old1 = signal (SIGINT, SIG_IGN);
  1519. X    old2 = signal (SIGQUIT, SIG_IGN);
  1520. X    if ((pid = fork()) == 0) {
  1521. X        for (pid = 3; pid < 20; pid++)
  1522. X            (void) close(pid);
  1523. X        (void) signal(SIGINT, SIG_DFL);
  1524. X        (void) signal(SIGQUIT, SIG_DFL);
  1525. X        if ((theShell = getenv("SHELL")) == NULL)
  1526. X            theShell = uinfo.shell;
  1527. X        if (theShell == NULL)
  1528. X            theShell = "/bin/sh";
  1529. X        namep = rindex(theShell, '/');
  1530. X        if (namep == NULL)
  1531. X            namep = theShell;
  1532. X        (void) strcpy(str, "-");
  1533. X        (void) strcat(str, ++namep);
  1534. X        if (strcmp(namep, "sh") != 0)
  1535. X            str[0] = '+';
  1536. X        if (debug) {
  1537. X            (void) printf ("%s\n", theShell);
  1538. X            (void) fflush (stdout);
  1539. X        }
  1540. X        if (argc > 1)
  1541. X            (void) execl(theShell, str, "-c", altarg, (char *)0);
  1542. X        else
  1543. X            (void) execl(theShell, str, (char *)0);
  1544. X        Perror(theShell);
  1545. X        code = -1;
  1546. X        exit(1);
  1547. X        }
  1548. X    if (pid > 0)
  1549. X        while (wait((void *) &Status) != pid)
  1550. X            ;
  1551. X    (void) signal(SIGINT, old1);
  1552. X    (void) signal(SIGQUIT, old2);
  1553. X    if (pid == -1) {
  1554. X        Perror("Try again later");
  1555. X        code = -1;
  1556. X    } else code = 0;
  1557. X    return (0);
  1558. X}    /* shell */
  1559. X
  1560. X
  1561. X
  1562. X
  1563. X/*
  1564. X * Send new user information (re-login)
  1565. X */
  1566. Xint do_user(int argc, char **argv)
  1567. X{
  1568. X    char            acct[80];
  1569. X    int                n, aflag = 0;
  1570. X    string            str;
  1571. X
  1572. X    if (argc < 2)
  1573. X        argv = re_makeargv("(username) ", &argc);
  1574. X    if (argc > 4) {
  1575. X        (void) printf("usage: %s username [password] [account]\n", argv[0]);
  1576. X        code = -1;
  1577. X        return (0);
  1578. X    }
  1579. X    (void) sprintf(str, "USER %s", argv[1]);
  1580. X    n = command(str);
  1581. X    if (n == CONTINUE) {
  1582. X        if (argc < 3 )
  1583. X            argv[2] = Getpass("Password: "), argc++;
  1584. X        (void) sprintf(str, "PASS %s", argv[2]);
  1585. X        n = command(str);
  1586. X    }
  1587. X    if (n == CONTINUE) {
  1588. X        if (argc < 4) {
  1589. X            (void) printf("Account: "); (void) fflush(stdout);
  1590. X            (void) FGets(acct, stdin);
  1591. X            acct[strlen(acct) - 1] = '\0';
  1592. X            argv[3] = acct; argc++;
  1593. X        }
  1594. X        (void) sprintf(str, "ACCT %s", argv[3]);
  1595. X        n = command(str);
  1596. X        aflag++;
  1597. X    }
  1598. X    if (n != COMPLETE) {
  1599. X        (void) fprintf(stdout, "Login failed.\n");
  1600. X        return (0);
  1601. X    }
  1602. X    if (!aflag && argc == 4) {
  1603. X        (void) sprintf(str, "ACCT %s", argv[3]);
  1604. X        (void) command(str);
  1605. X    }
  1606. X    return (1);
  1607. X}    /* user */
  1608. X
  1609. X
  1610. X
  1611. X
  1612. X/*
  1613. X * Print working directory.
  1614. X */
  1615. X/*ARGSUSED*/
  1616. Xint pwd(int argc, char **argv)
  1617. X{
  1618. X    int tmpverbose = verbose;
  1619. X    verbose = V_VERBOSE;
  1620. X    (void) command("PWD");
  1621. X    verbose = tmpverbose;
  1622. X}    /* pwd */
  1623. X
  1624. X
  1625. X
  1626. X
  1627. X/*
  1628. X * Make a directory.
  1629. X */
  1630. Xint makedir(int argc, char **argv)
  1631. X{
  1632. X    string str;
  1633. X
  1634. X    if (argc < 2)
  1635. X        argv = re_makeargv("(directory-name) ", &argc);
  1636. X    if (argc < 2) {
  1637. X        (void) printf("usage: %s directory-name\n", argv[0]);
  1638. X        code = -1;
  1639. X        return;
  1640. X    }
  1641. X    (void) sprintf(str, "MKD %s", argv[1]);
  1642. X    (void) command(str);
  1643. X}    /* makedir */
  1644. X
  1645. X
  1646. X
  1647. X
  1648. X/*
  1649. X * Remove a directory.
  1650. X */
  1651. Xint removedir(int argc, char **argv)
  1652. X{
  1653. X    string str;
  1654. X    if (argc < 2)
  1655. X        argv = re_makeargv("(directory-name) ", &argc);
  1656. X    if (argc < 2) {
  1657. X        (void) printf("usage: %s directory-name\n", argv[0]);
  1658. X        code = -1;
  1659. X        return;
  1660. X    }
  1661. X    if (rem_glob_one(argv[1]) == 0) {
  1662. X        (void) sprintf(str, "RMD %s", argv[1]);
  1663. X        (void) command(str);
  1664. X    }
  1665. X}    /* removedir */
  1666. X
  1667. X
  1668. X
  1669. X
  1670. X/*
  1671. X * Send a line, verbatim, to the remote machine.
  1672. X */
  1673. Xint quote(int argc, char **argv)
  1674. X{
  1675. X    int i, tmpverbose;
  1676. X    string str;
  1677. X
  1678. X    if (argc < 2)
  1679. X        argv = re_makeargv("(command line to send) ", &argc);
  1680. X    if (argc < 2) {
  1681. X        (void) printf("usage: %s line-to-send\n", argv[0]);
  1682. X        code = -1;
  1683. X        return;
  1684. X    }
  1685. X    (void) Strncpy(str, argv[1]);
  1686. X    for (i = 2; i < argc; i++) {
  1687. X        (void) Strncat(str, " ");
  1688. X        (void) Strncat(str, argv[i]);
  1689. X    }
  1690. X    tmpverbose = verbose;
  1691. X    verbose = V_VERBOSE;
  1692. X    if (command(str) == PRELIM) {
  1693. X        while (getreply(0) == PRELIM);
  1694. X    }
  1695. X    verbose = tmpverbose;
  1696. X}    /* quote */
  1697. X
  1698. X
  1699. X
  1700. X
  1701. X/*
  1702. X * Ask the other side for help.
  1703. X */
  1704. Xint rmthelp(int argc, char **argv)
  1705. X{
  1706. X    int oldverbose = verbose;
  1707. X    string str;
  1708. X
  1709. X    verbose = V_VERBOSE;
  1710. X    if (argc == 1) (void) command("HELP");
  1711. X    else {
  1712. X        (void) sprintf(str, "HELP %s", argv[1]);
  1713. X        (void) command(str);
  1714. X    }
  1715. X    verbose = oldverbose;
  1716. X}    /* rmthelp */
  1717. X
  1718. X
  1719. X
  1720. X
  1721. X/*
  1722. X * Terminate session and exit.
  1723. X */
  1724. X/*ARGSUSED*/
  1725. Xint quit(int argc, char **argv)
  1726. X{
  1727. X    close_up_shop();
  1728. X    trim_log();
  1729. X    exit(0);
  1730. X}    /* quit */
  1731. X
  1732. X
  1733. X
  1734. Xvoid close_streams(int wantShutDown)
  1735. X{
  1736. X    if (cout != NULL) {
  1737. X        if (wantShutDown)
  1738. X            (void) shutdown(fileno(cout), 1+1);
  1739. X        (void) fclose(cout);
  1740. X        cout = NULL;
  1741. X    }
  1742. X    if (cin != NULL) {
  1743. X        if (wantShutDown)
  1744. X            (void) shutdown(fileno(cin), 1+1);
  1745. X        (void) fclose(cin);
  1746. X        cin = NULL;
  1747. X    }
  1748. X}    /* close_streams */
  1749. X
  1750. X
  1751. X
  1752. X
  1753. X/*
  1754. X * Terminate session, but don't exit.
  1755. X */
  1756. X/*ARGSUSED*/
  1757. Xint disconnect(int argc, char **argv)
  1758. X{
  1759. X#ifdef SYSLOG
  1760. X    syslog (LOG_INFO, "%s disconnected from %s.", uinfo.username, hostname);
  1761. X#endif
  1762. X
  1763. X    (void) command("QUIT");
  1764. X    close_streams(0);
  1765. X    hostname[0] = cwd[0] = 0;
  1766. X    connected = 0;
  1767. X    data = -1;
  1768. X    macnum = 0;
  1769. X}    /* disconnect */
  1770. X
  1771. X
  1772. X
  1773. X
  1774. Xint confirm(char *cmd, char *file)
  1775. X{
  1776. X    str32 str;
  1777. X
  1778. X    if (!fromatty || (activemcmd && !mprompt))
  1779. X        return 1;
  1780. X    (void) printf("%s %s? ", cmd, file);
  1781. X    (void) fflush(stdout);
  1782. X    (void) Gets(str, sizeof(str));
  1783. X    return (*str != 'n' && *str != 'N');
  1784. X}    /* confirm */
  1785. X
  1786. X
  1787. X
  1788. Xvoid
  1789. Xfatal(char *msg)
  1790. X{
  1791. X    (void) fprintf(stderr, "%s: %s\n", progname, msg);
  1792. X    close_up_shop();
  1793. X    exit(1);
  1794. X}    /* fatal */
  1795. X
  1796. X
  1797. X
  1798. Xvoid
  1799. Xclose_up_shop(void)
  1800. X{
  1801. X    static int only_once = 0;
  1802. X    if (only_once++ > 0)
  1803. X        return;
  1804. X    if (connected)
  1805. X        disconnect(0, NULL);
  1806. X    if (logf != NULL) {
  1807. X        (void) fclose(logf);
  1808. X        logf = NULL;
  1809. X    }
  1810. X}    /* close_up_shop */
  1811. X
  1812. X
  1813. X
  1814. X
  1815. X/*
  1816. X * Glob a local file name specification with
  1817. X * the expectation of a single return value.
  1818. X * Can't control multiple values being expanded
  1819. X * from the expression, we return only the first.
  1820. X */
  1821. Xint globulize(char **cpp)
  1822. X{
  1823. X    char **globbed;
  1824. X
  1825. X    globbed = glob(*cpp);
  1826. X    if (globerr != NULL) {
  1827. X        (void) printf("%s: %s\n", *cpp, globerr);
  1828. X        if (globbed) {
  1829. X            blkfree(globbed);
  1830. X            free(globbed);
  1831. X        }
  1832. X        return (0);
  1833. X    }
  1834. X    if (globbed) {
  1835. X        *cpp = *globbed++;
  1836. X        /* don't waste too much memory */
  1837. X        if (*globbed) {
  1838. X            blkfree(globbed);
  1839. X            free(globbed);
  1840. X        }
  1841. X    }
  1842. X    return (1);
  1843. X}    /* globulize */
  1844. X
  1845. X
  1846. X
  1847. X/* change directory to perent directory */
  1848. X/*ARGSUSED*/
  1849. Xint cdup(int argc, char **argv)
  1850. X{
  1851. X    (void) _cd("CDUP");
  1852. X}
  1853. X
  1854. X
  1855. X/* show remote system type */
  1856. X/*ARGSUSED*/
  1857. Xint syst(int argc, char **argv)
  1858. X{
  1859. X    (void) command("SYST");
  1860. X}
  1861. X
  1862. X
  1863. X
  1864. X
  1865. Xint make_macro(char *name, FILE *fp)
  1866. X{
  1867. X    char            *tmp;
  1868. X    char            *cp;
  1869. X    string            str;
  1870. X    size_t            len;
  1871. X
  1872. X    if (macnum == MAXMACROS) {
  1873. X        (void) fprintf(stderr, "Limit of %d macros have already been defined.\n", MAXMACROS);
  1874. X        return -1;
  1875. X    }
  1876. X    (void) strncpy(macros[macnum].mac_name, name, (size_t)8);
  1877. X    if (macnum == 0)
  1878. X        macros[macnum].mac_start = macbuf;
  1879. X    else
  1880. X        macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  1881. X    tmp = macros[macnum].mac_start;
  1882. X    while (1) {
  1883. X        cp = fgets(str, sizeof(str) - 1, fp);
  1884. X        if (cp == NULL) {
  1885. X            /*
  1886. X             * If we had started a macro, we will say it is
  1887. X             * okay to skip the blank line delimiter if we
  1888. X             * are at the EOF.
  1889. X             */
  1890. X            if (tmp > macros[macnum].mac_start)
  1891. X                goto endmac;
  1892. X            (void) fprintf(stderr, "No text supplied for macro \"%s.\"\n", name);
  1893. X        }
  1894. X        /* see if we have a 'blank' line: just whitespace. */
  1895. X        while (*cp && isspace(*cp)) ++cp;
  1896. X        if (*cp == '\0') {
  1897. X            /* Blank line; end this macro. */
  1898. Xendmac:
  1899. X            macros[macnum++].mac_end = tmp;
  1900. X            return 0;
  1901. X        }
  1902. X        len = strlen(cp) + 1;    /* we need the \0 too. */
  1903. X        if (tmp + len >= macbuf + MACBUFLEN) {
  1904. X            (void) fprintf(stderr, "Macro \"%s\" not defined -- %d byte buffer exceeded.\n", name, MACBUFLEN);
  1905. X            return -1;
  1906. X        }
  1907. X        (void) strcpy(tmp, cp);
  1908. X        tmp += len;
  1909. X    }
  1910. X}    /* make_macro */
  1911. X
  1912. X
  1913. X
  1914. X
  1915. Xint macdef(int argc, char **argv)
  1916. X{
  1917. X    if (argc < 2)
  1918. X        argv = re_makeargv("(macro name) ", &argc);
  1919. X    if (argc != 2) {
  1920. X        (void) printf("Usage: %s macro_name\n", argv[0]);
  1921. X        domacro(0, NULL);
  1922. X        return;
  1923. X    }
  1924. X    (void) printf("Enter macro line by line, terminating it with a blank line\n");
  1925. X    code = make_macro(argv[1], stdin);
  1926. X}    /* macdef */
  1927. X
  1928. X
  1929. X
  1930. X
  1931. Xint domacro(int argc, char **argv)
  1932. X{
  1933. X    register int            i, j;
  1934. X    register char            *cp1, *cp2;
  1935. X    int                        count = 2, loopflg = 0;
  1936. X    string                    str;
  1937. X    struct cmd                *c;
  1938. X
  1939. X    if (argc < 2) {
  1940. X        /* print macros. */
  1941. X        if (macnum == 0)
  1942. X            (void) printf("No macros defined.\n");
  1943. X        else {
  1944. X            printf("Current macro definitions:\n");
  1945. X            for (i = 0; i < macnum; ++i) {
  1946. X                (void) printf("%s:\n", macros[i].mac_name);
  1947. X                cp1 = macros[i].mac_start;
  1948. X                cp2 = macros[i].mac_end;
  1949. X                while (cp1 < cp2) {
  1950. X                    (void) printf("   > ");
  1951. X                    while (cp1 < cp2 && *cp1)
  1952. X                        putchar(*cp1++);
  1953. X                    ++cp1;
  1954. X                }
  1955. X            }
  1956. X        }
  1957. X        if (argc == 0) return;    /* called from macdef(), above. */
  1958. X        argv = re_makeargv("(macro to run) ", &argc);
  1959. X    }            
  1960. X    if (argc < 2) {
  1961. X        (void) printf("Usage: %s macro_name.\n", argv[0]);
  1962. X        code = -1;
  1963. X        return;
  1964. X    }
  1965. X    for (i = 0; i < macnum; ++i) {
  1966. X        if (!strncmp(argv[1], macros[i].mac_name, (size_t) 9)) {
  1967. X            break;
  1968. X        }
  1969. X    }
  1970. X    if (i == macnum) {
  1971. X        (void) printf("'%s' macro not found.\n", argv[1]);
  1972. X        code = -1;
  1973. X        return;
  1974. X    }
  1975. X    (void) Strncpy(str, line);
  1976. XTOP:
  1977. X    cp1 = macros[i].mac_start;
  1978. X    while (cp1 != macros[i].mac_end) {
  1979. X        while (isspace(*cp1)) {
  1980. X            cp1++;
  1981. X        }
  1982. X        cp2 = line;
  1983. X        while (*cp1 != '\0') {
  1984. X              switch(*cp1) {
  1985. X                   case '\\':
  1986. X                 *cp2++ = *++cp1;
  1987. X                 break;
  1988. X                case '$':
  1989. X                 if (isdigit(*(cp1+1))) {
  1990. X                    j = 0;
  1991. X                    while (isdigit(*++cp1)) {
  1992. X                      j = 10*j +  *cp1 - '0';
  1993. X                    }
  1994. X                    cp1--;
  1995. X                    if (argc - 2 >= j) {
  1996. X                    (void) strcpy(cp2, argv[j+1]);
  1997. X                    cp2 += strlen(argv[j+1]);
  1998. X                    }
  1999. X                    break;
  2000. X                 }
  2001. X                 if (*(cp1+1) == 'i') {
  2002. X                    loopflg = 1;
  2003. X                    cp1++;
  2004. X                    if (count < argc) {
  2005. X                       (void) strcpy(cp2, argv[count]);
  2006. X                       cp2 += strlen(argv[count]);
  2007. X                    }
  2008. X                    break;
  2009. X                }
  2010. X                /* intentional drop through */
  2011. X                default:
  2012. X                *cp2++ = *cp1;
  2013. X                break;
  2014. X              }
  2015. X              if (*cp1 != '\0') {
  2016. X                    cp1++;
  2017. X              }
  2018. X        }
  2019. X        *cp2 = '\0';
  2020. X        makeargv();
  2021. X        c = getcmd(margv[0]);
  2022. X        if ((c == (struct cmd *)-1) && !parsing_rc) {
  2023. X            (void) printf("?Ambiguous command\n");
  2024. X            code = -1;
  2025. X        }
  2026. X        else if (c == NULL && !parsing_rc) {
  2027. X            (void) printf("?Invalid command\n");
  2028. X            code = -1;
  2029. X        } else if (c->c_conn && !connected) {
  2030. X            (void) printf("Not connected.\n");
  2031. X            code = -1;
  2032. X        } else {
  2033. X            if (IS_VVERBOSE)
  2034. X                (void) printf("%s\n",line);
  2035. X            (*c->c_handler)(margc, margv);
  2036. X            (void) strcpy(line, str);
  2037. X            makeargv();
  2038. X            argc = margc;
  2039. X            argv = margv;
  2040. X        }
  2041. X        if (cp1 != macros[i].mac_end) {
  2042. X            cp1++;
  2043. X        }
  2044. X    }
  2045. X    if (loopflg && ++count < argc) {
  2046. X        goto TOP;
  2047. X    }
  2048. X}    /* domacro */
  2049. X
  2050. X
  2051. X
  2052. X/*
  2053. X * get size of file on remote machine
  2054. X */
  2055. Xint sizecmd(int argc, char **argv)
  2056. X{
  2057. X    string str;
  2058. X    int oldv;
  2059. X
  2060. X    if (argc < 2)
  2061. X        argv = re_makeargv("(remote-file) ", &argc);
  2062. X    if (argc < 2) {
  2063. X        (void) printf("usage:%s filename\n", argv[0]);
  2064. X        code = -1;
  2065. X        return;
  2066. X    }
  2067. X    if (rem_glob_one(argv[1]) == 0) {
  2068. X        (void) sprintf(str, "SIZE %s", argv[1]);
  2069. X        oldv = verbose;
  2070. X        verbose = V_VERBOSE;
  2071. X        (void) command(str);
  2072. X        verbose = oldv;
  2073. X    }
  2074. X}    /* sizecmd */
  2075. X
  2076. X
  2077. X
  2078. X
  2079. X/*
  2080. X * get last modification time of file on remote machine
  2081. X */
  2082. Xint modtime(int argc, char **argv)
  2083. X{
  2084. X    int overbose;
  2085. X    string str;
  2086. X
  2087. X    if (argc < 2)
  2088. X        argv = re_makeargv("(remote-file) ", &argc);
  2089. X    if (argc < 2) {
  2090. X        (void) printf("usage:%s filename\n", argv[0]);
  2091. X        code = -1;
  2092. X        return;
  2093. X    }
  2094. X    if (rem_glob_one(argv[1]) == 0) {
  2095. X        overbose = verbose;
  2096. X        if (debug == 0)
  2097. X            verbose = V_QUIET;
  2098. X        (void) sprintf(str, "MDTM %s", argv[1]);
  2099. X        if (command(str) == COMPLETE) {
  2100. X            int yy, mo, day, hour, min, sec;
  2101. X            (void) sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2102. X                &day, &hour, &min, &sec);
  2103. X            /* might want to print this in local time */
  2104. X            (void) printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2105. X                mo, day, yy, hour, min, sec);
  2106. X        } else
  2107. X            (void) fputs(reply_string, stdout);
  2108. X        verbose = overbose;
  2109. X    }
  2110. X}    /* modtime */
  2111. X
  2112. X
  2113. X
  2114. Xint lookup(int argc, char **argv)
  2115. X{
  2116. X    int i, j, by_name, result = 0;
  2117. X    unsigned long addr;            /* address in host order */
  2118. X    struct hostent *host;        /* structure returned by gethostbyaddr() */
  2119. X    extern int h_errno;
  2120. X
  2121. X    if (argc < 2)
  2122. X        argv = re_makeargv("(sitename) ", &argc);
  2123. X    if (argc < 2) {
  2124. X        (void) printf("usages:\n\t%s <sitenames>\n\t%s <ip numbers>\n",
  2125. X            argv[0], argv[0]);
  2126. X    }
  2127. X
  2128. X     lasthostname[0] = 0;
  2129. X    for (i=1; i<argc; i++) {
  2130. X        /* does the argument look like an address? */
  2131. X        if (4 == sscanf (argv[i], "%d.%d.%d.%d", &j, &j, &j, &j)) {
  2132. X            /* ip */
  2133. X              if ((addr = inet_addr (argv[i])) == 0xffffffff) {
  2134. X                 (void) fprintf(stderr, "## could not convert \"%s\" into a valid IP address.\n", argv[i]);
  2135. X                 continue;
  2136. X             }
  2137. X            host = gethostbyaddr ((char *) &addr, 4, AF_INET);
  2138. X            by_name = 0;
  2139. X        } else {
  2140. X            /* name */
  2141. X            host = gethostbyname (argv[i]);
  2142. X            by_name = 1;
  2143. X        }
  2144. X        if (host == NULL) {
  2145. X            if (NOT_VQUIET) {
  2146. X                /* gethostxxx error */                
  2147. X                result = h_errno;
  2148. X                if (h_errno == HOST_NOT_FOUND) {
  2149. X                     (void) printf("%s: lookup error (%d).\n",
  2150. X                         argv[i], h_errno);
  2151. X                     result = h_errno;
  2152. X                 } else {
  2153. X                     (void) printf("%s \"%s\"\n",
  2154. X                         (by_name==0 ? "unknown address" : "unknown host"),
  2155. X                         argv[i]);
  2156. X                     result = 
  2157. X                         h_errno != 0 ? h_errno :
  2158. X                         -1;
  2159. X                }
  2160. X            }
  2161. X         } else {
  2162. X             if (*host->h_name)
  2163. X                 Strncpy(lasthostname, host->h_name);
  2164. X            if (NOT_VQUIET) {
  2165. X                (void) printf("%-32s  ", *host->h_name ? host->h_name : "???");
  2166. X                if (*host->h_addr_list) {
  2167. X                    unsigned long horder;
  2168. X    
  2169. X                    horder = ntohl (*(unsigned long *) *(char **)host->h_addr_list);
  2170. X                    (void) printf ("%lu.%lu.%lu.%lu\n",
  2171. X                        (horder >> 24),
  2172. X                        (horder >> 16) & 0xff,
  2173. X                        (horder >> 8) & 0xff,
  2174. X                        horder & 0xff);
  2175. X                }
  2176. X                else (void) printf("???\n");
  2177. X            }
  2178. X        }
  2179. X    }    /* loop thru all sites */
  2180. X    return result;
  2181. X}    /* lookup */
  2182. X
  2183. X
  2184. X
  2185. X
  2186. Xint getlocalhostname(char *host, size_t size)
  2187. X{
  2188. X    int oldv, r;
  2189. X    char *argv[2];
  2190. X
  2191. X#ifdef HOSTNAME
  2192. X    (void) strncpy(host, HOSTNAME, size);
  2193. X    return 0;
  2194. X#else
  2195. X    *host = 0;
  2196. X    if ((r = gethostname(host, size)) == 0) {
  2197. X        oldv = verbose;
  2198. X        verbose = V_QUIET;
  2199. X        argv[0] = "lookup";
  2200. X        (void) sprintf(line, "lookup %s", host);
  2201. X        (void) makeargv();
  2202. X        if (lookup(margc, margv) == 0 && lasthostname[0])
  2203. X            (void) strncpy(host, lasthostname, size);
  2204. X        verbose = oldv;
  2205. X    }
  2206. X    return r;
  2207. X#endif
  2208. X}    /* getlocalhostname */
  2209. X
  2210. X
  2211. X
  2212. X
  2213. X/*
  2214. X * show status on remote machine
  2215. X */
  2216. Xint rmtstatus(int argc, char **argv)
  2217. X{
  2218. X    string str;
  2219. X    if (argc > 1) {
  2220. X        (void) sprintf(str, "STAT %s" , argv[1]);
  2221. X        (void) command(str);
  2222. X    } else (void) command("STAT");
  2223. X}    /* rmtstatus */
  2224. X
  2225. X
  2226. X
  2227. X
  2228. X/*
  2229. X * create an empty file on remote machine.
  2230. X */
  2231. Xint create(int argc, char **argv)
  2232. X{
  2233. X    string            str;
  2234. X    FILE            *ftemp;
  2235. X
  2236. X    if (argc < 2)
  2237. X        argv = re_makeargv("(remote-file) ", &argc);
  2238. X    if (argc < 2) {
  2239. X        (void) printf("usage:%s filename\n", argv[0]);
  2240. X        code = -1;
  2241. X        return;
  2242. X    }
  2243. X    (void) tmp_name(str);
  2244. X    ftemp = fopen(str, "w");
  2245. X    /* (void) fputc('x', ftemp); */
  2246. X    (void) fclose(ftemp);
  2247. X    creating = 1;
  2248. X    sendrequest("STOR", str, argv[1]);
  2249. X    creating = 0;
  2250. X    (void) unlink(str);
  2251. X}    /* create */
  2252. X
  2253. X
  2254. X
  2255. X
  2256. X/* show version info */
  2257. X/*ARGSUSED*/
  2258. Xint show_version(int argc, char **argv)
  2259. X{
  2260. X    char    *DStrs[20];
  2261. X    int        nDStrs = 0, i, j;
  2262. X
  2263. X    (void) printf("%s\n%-30s %s\n", version, "Author:",
  2264. X        "Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu).");
  2265. X
  2266. X/* Now entering CPP hell... */
  2267. X#ifdef __DATE__
  2268. X    (void) printf("%-30s %s\n", "Compile Date:", __DATE__);
  2269. X#endif
  2270. X    (void) printf("%-30s %s (%s)\n", "Operating System:",
  2271. X#ifdef System
  2272. X    System,
  2273. X#else
  2274. X#    ifdef unix
  2275. X    "UNIX",
  2276. X#    else
  2277. X    "??",
  2278. X#    endif
  2279. X#endif
  2280. X#ifdef SYSV
  2281. X        "SYSV");
  2282. X#else
  2283. X#    ifdef BSD
  2284. X            "BSD");
  2285. X#    else
  2286. X            "neither BSD nor SYSV?");
  2287. X#    endif
  2288. X#endif
  2289. X
  2290. X    /* Show which CPP symbols were used in compilation. */
  2291. X#ifdef __GNUC__
  2292. X    DStrs[nDStrs++] = "__GNUC__";
  2293. X#endif
  2294. X#ifdef RINDEX
  2295. X    DStrs[nDStrs++] = "RINDEX";
  2296. X#endif
  2297. X#ifdef CURSES
  2298. X    DStrs[nDStrs++] = "CURSES";
  2299. X#endif
  2300. X#ifdef HERROR
  2301. X    DStrs[nDStrs++] = "HERROR";
  2302. X#endif
  2303. X#ifdef U_WAIT
  2304. X    DStrs[nDStrs++] = "U_WAIT";
  2305. X#endif
  2306. X#if defined(CONST) || defined(const)
  2307. X    DStrs[nDStrs++] = "CONST";
  2308. X#endif
  2309. X#ifdef GETPASS
  2310. X    DStrs[nDStrs++] = "GETPASS";
  2311. X#endif
  2312. X#ifdef GETCWDSIZET
  2313. X    DStrs[nDStrs++] = "GETCWDSIZET";
  2314. X#endif
  2315. X#ifdef HOSTNAME
  2316. X    DStrs[nDStrs++] = "HOSTNAME";
  2317. X#endif
  2318. X#ifdef SYSDIRH
  2319. X    DStrs[nDStrs++] = "SYSDIRH";
  2320. X#endif
  2321. X#ifdef SYSSELECTH
  2322. X    DStrs[nDStrs++] = "SYSSELECTH";
  2323. X#endif
  2324. X#ifdef NO_UNISTDH 
  2325. X    DStrs[nDStrs++] = "NO_UNISTDH";
  2326. X#endif
  2327. X#ifdef NO_STDLIBH
  2328. X    DStrs[nDStrs++] = "NO_STDLIBH";
  2329. X#endif
  2330. X#ifdef SYSLOG 
  2331. X    DStrs[nDStrs++] = "SYSLOG";
  2332. X#endif
  2333. X#ifdef REDIR
  2334. X    DStrs[nDStrs++] = "REDIR";
  2335. X#endif
  2336. X#ifdef BAD_INETADDR
  2337. X    DStrs[nDStrs++] = "BAD_INETADDR";
  2338. X#endif
  2339. X#ifdef SGTTYB
  2340. X    DStrs[nDStrs++] = "SGTTYB";
  2341. X#endif
  2342. X#ifdef TERMIOS
  2343. X    DStrs[nDStrs++] = "TERMIOS";
  2344. X#endif
  2345. X#ifdef _POSIX_SOURCE
  2346. X    DStrs[nDStrs++] = "_POSIX_SOURCE";
  2347. X#endif
  2348. X
  2349. X
  2350. X    (void) printf ("\nCompile Options:\n");
  2351. X    for (i=j=0; i<nDStrs; i++) {
  2352. X        if (j == 0)
  2353. X            (void) printf("    ");
  2354. X        (void) printf("%-15s", DStrs[i]);
  2355. X        if (++j == 4) {
  2356. X            j = 0;
  2357. X            (void) putchar('\n');
  2358. X        }
  2359. X    }
  2360. X    if (j != 0)
  2361. X        (void) putchar('\n');
  2362. X    
  2363. X    (void) printf("\nDefaults:\n");
  2364. X    (void) printf("\
  2365. X    Xfer Buf Size: %8d   Debug: %d   MPrompt: %d   Verbosity: %d\n\
  2366. X    Prompt: %s   Pager: %s  ZCat: %s\n\
  2367. X    Logname: %s   Logging: %d   Type: %s   Cmd Len: %d\n\
  2368. X    Recv Line Len: %d   #Macros: %d   Macbuf: %d  Auto-Binary: %d\n\
  2369. X    Redial Delay: %d  New Mail Message: \"%s\"\n",
  2370. X        MAX_XFER_BUFSIZE, dDEBUG, dMPROMPT, dVERBOSE,
  2371. X        dPROMPT, dPAGER, ZCAT,
  2372. X        dLOGNAME, dLOGGING, dTYPESTR, CMDLINELEN,
  2373. X        RECEIVEDLINELEN, MAXMACROS, MACBUFLEN, dAUTOBINARY,
  2374. X        dREDIALDELAY, NEWMAILMESSAGE
  2375. X    );
  2376. X}    /* show_version */
  2377. X
  2378. X
  2379. X
  2380. Xvoid Perror(char *s)
  2381. X{
  2382. X    extern int errno;
  2383. X
  2384. X    if (NOT_VQUIET) {
  2385. X        if (s != NULL)
  2386. X            (void) fprintf(stderr, "NcFTP: %s (%d): ", s, errno);
  2387. X        perror(NULL);
  2388. X    }
  2389. X}    /* Perror */
  2390. X
  2391. X
  2392. X
  2393. X#ifdef REDIR
  2394. X/*ARGSUSED*/
  2395. Xint showlsbuffer(int argc, char **argv)
  2396. X{
  2397. X    register struct lslist *a = lshead;
  2398. X    int pagemode;
  2399. X    FILE *fp;
  2400. X    void (*oldintp)(int);
  2401. X
  2402. X    if (a == NULL)
  2403. X        return;
  2404. X    pagemode= (**argv) == 'p' && pager[0] == '|';
  2405. X    if (pagemode) {
  2406. X        fp = popen(pager + 1, "w");
  2407. X        if (!fp) {
  2408. X            Perror(pager + 1);
  2409. X            return;
  2410. X        }
  2411. X    } else
  2412. X        fp = stdout;
  2413. X    oldintp = signal(SIGPIPE, SIG_IGN);
  2414. X    while (a) {
  2415. X        if (a->string)
  2416. X            (void) fprintf(fp, "%s\n", a->string);
  2417. X        a = a->next;
  2418. X    }
  2419. X    if (pagemode)
  2420. X        (void) pclose(fp);
  2421. X    if (oldintp)
  2422. X        signal(SIGPIPE, oldintp);
  2423. X}    /* showlsbuffer */
  2424. X#endif
  2425. X
  2426. X/* eof cmds.c */
  2427. END_OF_FILE
  2428.   if test 48279 -ne `wc -c <'cmds.c'`; then
  2429.     echo shar: \"'cmds.c'\" unpacked with wrong size!
  2430.   fi
  2431.   # end of 'cmds.c'
  2432. fi
  2433. if test -f 'ftp.h' -a "${1}" != "-c" ; then 
  2434.   echo shar: Will not clobber existing file \"'ftp.h'\"
  2435. else
  2436.   echo shar: Extracting \"'ftp.h'\" \(852 characters\)
  2437.   sed "s/^X//" >'ftp.h' <<'END_OF_FILE'
  2438. X/* ftp.h */
  2439. X
  2440. X#ifndef _ftp_h_
  2441. X#define _ftp_h_
  2442. X
  2443. X#define IS_FILE 1
  2444. X#define IS_STREAM 0
  2445. X#define IS_PIPE -1
  2446. X
  2447. X/* Progress-meter types. */
  2448. X#define pr_none 0
  2449. X#define pr_percent 1
  2450. X#define pr_philbar 2
  2451. X#define pr_kbytes 3
  2452. X
  2453. Xint hookup(char *host, int port);
  2454. Xint login(char *, int, int);
  2455. Xvoid cmdabort(int unused);
  2456. Xint command(char *cmd);
  2457. Xint getreply(int expecteof);
  2458. Xvoid abortsend(int unused);
  2459. Xvoid sendrequest(char *cmd, char *local, char *remote);
  2460. Xvoid abortrecv(int unused);
  2461. Xvoid recvrequest(char *cmd, char *local, char *remote, char *mode);
  2462. Xint initconn(void);
  2463. XFILE *dataconn(char *mode);
  2464. Xvoid close_file(FILE **fin, int filetype);
  2465. Xlong get_remote_size(char *remote, int filetype);
  2466. Xint start_progress(int sending, char *local);
  2467. Xvoid progress_report(int);
  2468. Xvoid end_progress(char *direction, char *local, char *remote);
  2469. X
  2470. X#endif /* _ftp_h_ */
  2471. X
  2472. X/* eof ftp.h */
  2473. END_OF_FILE
  2474.   if test 852 -ne `wc -c <'ftp.h'`; then
  2475.     echo shar: \"'ftp.h'\" unpacked with wrong size!
  2476.   fi
  2477.   # end of 'ftp.h'
  2478. fi
  2479. echo shar: End of archive 1 \(of 4\).
  2480. cp /dev/null ark1isdone
  2481. MISSING=""
  2482. for I in 1 2 3 4 ; do
  2483.     if test ! -f ark${I}isdone ; then
  2484.     MISSING="${MISSING} ${I}"
  2485.     fi
  2486. done
  2487. if test "${MISSING}" = "" ; then
  2488.     echo You have unpacked all 4 archives.
  2489.     rm -f ark[1-9]isdone
  2490. else
  2491.     echo You still must unpack the following archives:
  2492.     echo "        " ${MISSING}
  2493. fi
  2494. exit 0
  2495. exit 0 # Just in case...
  2496.