home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / ncftp / part02 < prev    next >
Encoding:
Text File  |  1992-12-07  |  54.1 KB  |  2,308 lines

  1. Newsgroups: comp.sources.misc
  2. From: mgleason@cse.unl.edu (Mike Gleason)
  3. Subject:  v34i015:  ncftp - Alternative User Interface for FTP, Part02/03
  4. Message-ID: <1992Dec7.211051.3958@sparky.imd.sterling.com>
  5. X-Md4-Signature: fc92f158a15b813b8210a82015ff7ebf
  6. Date: Mon, 7 Dec 1992 21:10:51 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
  10. Posting-number: Volume 34, Issue 15
  11. Archive-name: ncftp/part02
  12. Environment: UNIX, ANSI-C, getopt
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  cmdtab.c ftp.c ftprc.h main.c
  19. # Wrapped by kent@sparky on Mon Dec  7 15:06:54 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 2 (of 3)."'
  23. if test -f 'cmdtab.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'cmdtab.c'\"
  25. else
  26.   echo shar: Extracting \"'cmdtab.c'\" \(5796 characters\)
  27.   sed "s/^X//" >'cmdtab.c' <<'END_OF_FILE'
  28. X/* cmdtab.c */
  29. X
  30. X#include "sys.h"
  31. X#include <sys/types.h>
  32. X#include <stdio.h>
  33. X#include <sys/time.h>
  34. X#include "ftpdefs.h"
  35. X#include "cmds.h"
  36. X#include "main.h"
  37. X#include "ftp.h"
  38. X#include "ftprc.h"
  39. X#include "glob.h"
  40. X#include "copyright.h"
  41. X
  42. Xchar    asciihelp[] =     "transfer as text files";
  43. Xchar    binaryhelp[] =    "transfer as binary files";
  44. Xchar    cdhelp[] =        "change remote working directory";
  45. Xchar    cduphelp[] =     "change remote working directory to parent directory";
  46. Xchar    createhelp[] =    "create an empty file on the remote host";
  47. Xchar    deletehelp[] =    "delete remote file";
  48. Xchar    debughelp[] =    "toggle/set debugging mode";
  49. Xchar    dirhelp[] =        "list contents of remote directory";
  50. Xchar    disconhelp[] =    "terminate ftp session";
  51. Xchar    domachelp[] =     "execute macro";
  52. Xchar    helphelp[] =    "print local help information";
  53. Xchar    lcdhelp[] =        "change local working directory";
  54. Xchar    lshelp[] =        "list contents of remote directory";
  55. Xchar    lookuphelp[] =    "print IP addr given name, or name given IP";
  56. Xchar    macdefhelp[] =  "define a macro";
  57. Xchar    mdeletehelp[] =    "delete multiple files";
  58. Xchar    mdirhelp[] =    "list contents of multiple remote directories";
  59. Xchar    mgethelp[] =    "get multiple files";
  60. Xchar    mkdirhelp[] =    "make directory on the remote machine";
  61. Xchar    mlshelp[] =        "nlist contents of multiple remote directories";
  62. Xchar    modtimehelp[] = "show last modification time of remote file";
  63. Xchar    mputhelp[] =    "send multiple files";
  64. Xchar    openhelp[] =    "connect to remote ftp server (type 'open' for usage)";
  65. Xchar    pagehelp[] =    "display a remote file on your terminal";
  66. Xchar    plshelp[] =     "view contents of remote directory using your PAGER";
  67. Xchar    prompthelp[] =    "force interactive prompting on multiple commands";
  68. Xchar    pwdhelp[] =        "print working directory on remote machine";
  69. Xchar    quithelp[] =    "terminate ftp session and exit";
  70. Xchar    quotehelp[] =    "send arbitrary ftp command";
  71. Xchar    receivehelp[] =    "receive file";
  72. X#ifdef REDIR
  73. Xchar    predirhelp[] =    "view last ls, dir, list, or nlist with your PAGER";
  74. Xchar     redirhelp[] =     "re-show last ls, dir, list, or nlist.";
  75. X#endif
  76. Xchar    remotehelp[] =    "get help from remote server";
  77. Xchar    renamehelp[] =    "rename file";
  78. Xchar    rmdirhelp[] =    "remove directory on the remote machine";
  79. Xchar    rmtstatushelp[]="show status of remote machine";
  80. Xchar    sendhelp[] =    "send one file";
  81. Xchar    sethelp[] =        "set a variable's value; set alone shows all variables";
  82. Xchar    shellhelp[] =    "escape to the shell";
  83. Xchar    sizecmdhelp[] = "show size of remote file";
  84. Xchar    systemhelp[] =  "show remote system type";
  85. Xchar    typehelp[] =    "specify how to transfer files (ascii/binary)";
  86. Xchar    unsethelp[] =    "undefine a variable's value";
  87. Xchar    userhelp[] =    "send new user information";
  88. Xchar    verbosehelp[] =    "toggle verbose mode";
  89. Xchar    versionhelp[] =    "shows version information";
  90. X
  91. Xstruct cmd cmdtab[] = {
  92. X    /* name ; help ; bell-when-done ; must-be-connected ; proxy can ; hidden */
  93. X    { "!",            shellhelp,            0,    0,    0,    0,    shell },
  94. X    { "$",            domachelp,            1,    0,    0,    0,    domacro },
  95. X    { "ascii",        asciihelp,            0,    1,    0,    1,    setascii },
  96. X    { "binary",        binaryhelp,            0,    1,    0,    1,    setbinary },
  97. X    { "bye",        quithelp,            0,    0,    0,    1,    quit },
  98. X    { "cd",            cdhelp,                0,    1,    1,    0,    cd },
  99. X    { "cdup",        cduphelp,            0,    1,    1,    0,    cdup },
  100. X    { "chdir",        cdhelp,                0,    1,    1,    1,    cd },
  101. X    { "close",        disconhelp,            0,    1,    1,    1,    disconnect },
  102. X    { "connect",    openhelp,            0,    0,    1,    1,    setpeer },
  103. X    { "create",        createhelp,            0,    1,    0,    0,    create },
  104. X    { "delete",        deletehelp,            0,    1,    1,    0,    do_delete },
  105. X    { "debug",        debughelp,            0,    0,    0,    1,    setdebug },
  106. X    { "erase",        deletehelp,            0,    1,    1,    1,    do_delete },
  107. X    { "exit",        quithelp,            0,    0,    0,    1,    quit },
  108. X    { "dir",        dirhelp,            1,    1,    1,    0,    ls },
  109. X    { "get",        receivehelp,        1,    1,    1,    0,    get },
  110. X    { "help",        helphelp,            0,    0,    1,    0,    help },
  111. X    { "image",        binaryhelp,            0,    1,    0,    1,    setbinary },
  112. X    { "lcd",        lcdhelp,            0,    0,    0,    0,    lcd },
  113. X    { "lookup",     lookuphelp,         0,    0,    0,    0,  lookup },
  114. X    { "ls",            lshelp,                1,    1,    1,    0,    ls },
  115. X    { "macdef",        macdefhelp,            0,    0,    0,    0,    macdef },
  116. X    { "mdelete",    mdeletehelp,        1,    1,    1,    0,    mdelete },
  117. X    { "mdir",        mdirhelp,            1,    1,    1,    0,    mls },
  118. X    { "mget",        mgethelp,            1,    1,    1,    0,    mget },
  119. X    { "mkdir",        mkdirhelp,            0,    1,    1,    0,    makedir },
  120. X    { "mls",        mlshelp,            1,    1,    1,    0,    mls },
  121. X    { "modtime",    modtimehelp,        0,    1,    1,    0,    modtime },
  122. X    { "more",       pagehelp,           1,  1,  1,  1,  get },
  123. X    { "mput",        mputhelp,            1,    1,    1,    0,    mput },
  124. X    { "nlist",        lshelp,                1,    1,    1,    1,    ls },
  125. X    { "open",        openhelp,            0,    0,    1,    0,    setpeer },
  126. X    { "page",        pagehelp,            1,    1,    1,    0,    get },
  127. X    { "pdir",        plshelp,            1,    1,    1,    0,    ls },
  128. X    { "pls",        plshelp,            1,    1,    1,    0,    ls },
  129. X#ifdef REDIR
  130. X    { "predir",      predirhelp,          0,     1,     0,    0,    showlsbuffer },
  131. X#endif
  132. X    { "prompt",        prompthelp,            0,    0,    0,    1,    setprompt },
  133. X    { "put",        sendhelp,            1,    1,    1,    0,    put },
  134. X    { "pwd",        pwdhelp,            0,    1,    1,    0,    pwd },
  135. X    { "quit",        quithelp,            0,    0,    0,    0,    quit },
  136. X    { "quote",        quotehelp,            1,    1,    1,    0,    quote },
  137. X#ifdef REDIR
  138. X    { "redir",      redirhelp,          0,     1,     0,    0,    showlsbuffer },
  139. X#endif
  140. X    { "remotehelp",    remotehelp,            0,    1,    1,    0,    rmthelp },
  141. X    { "rm",            deletehelp,            0,    1,    1,    1,    do_delete },
  142. X    { "rstatus",    rmtstatushelp,        0,    1,    1,    0,    rmtstatus },
  143. X    { "rhelp",        remotehelp,            0,    1,    1,    0,    rmthelp },
  144. X    { "rename",        renamehelp,            0,    1,    1,    0,    renamefile },
  145. X    { "rmdir",        rmdirhelp,            0,    1,    1,    0,    removedir },
  146. X    { "send",        sendhelp,            1,    1,    1,    1,    put },
  147. X    { "set",        sethelp,            0,    0,    0,    0,    set },
  148. X    { "size",        sizecmdhelp,        1,    1,    1,    0,    sizecmd },
  149. X    { "system",        systemhelp,            0,    1,    1,    0,    syst },
  150. X    { "unset",        unsethelp,            0,    0,    0,    0,    set },
  151. X    { "user",        userhelp,            0,    1,    1,    0,    do_user },
  152. X    { "type",        typehelp,            0,    1,    0,    0,    settype },
  153. X    { "verbose",    verbosehelp,        0,    0,    0,    0,    setverbose },
  154. X    { "version",    versionhelp,        0,    0,    0,    0,    show_version },
  155. X    { "?",            helphelp,            0,    0,    1,    0,    help },
  156. X    { NULL,            NULL,                0,    0,    0,    0,    NULL }
  157. X};
  158. X
  159. Xint    NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
  160. X
  161. X/* eof cmdtab.c */
  162. END_OF_FILE
  163.   if test 5796 -ne `wc -c <'cmdtab.c'`; then
  164.     echo shar: \"'cmdtab.c'\" unpacked with wrong size!
  165.   fi
  166.   # end of 'cmdtab.c'
  167. fi
  168. if test -f 'ftp.c' -a "${1}" != "-c" ; then 
  169.   echo shar: Will not clobber existing file \"'ftp.c'\"
  170. else
  171.   echo shar: Extracting \"'ftp.c'\" \(26888 characters\)
  172.   sed "s/^X//" >'ftp.c' <<'END_OF_FILE'
  173. X/* ftp.c */
  174. X
  175. X#include "sys.h"
  176. X#include <sys/types.h>
  177. X#include <sys/param.h>
  178. X#include <setjmp.h>
  179. X#include <sys/stat.h>
  180. X#include <sys/ioctl.h>
  181. X#include <sys/socket.h>
  182. X#include <sys/time.h>
  183. X#include <sys/file.h>
  184. X
  185. X/* You may need this for declarations of fd_set, etc. */
  186. X#ifdef SYSSELECTH
  187. X#   include <sys/select.h>
  188. X#endif
  189. X
  190. X#include <netinet/in.h>
  191. X#include <arpa/ftp.h>
  192. X#include <arpa/inet.h>
  193. X#include <arpa/telnet.h>
  194. X#include <stdio.h>
  195. X#include <string.h>
  196. X#include <stdlib.h>
  197. X#include <signal.h>
  198. X#include <errno.h>
  199. X#include <netdb.h>
  200. X#include <fcntl.h>
  201. X#include <pwd.h>
  202. X#include <ctype.h>
  203. X#include "ftpdefs.h"
  204. X#include "defaults.h"
  205. X#include "ftp.h"
  206. X#include "cmds.h"
  207. X#include "main.h"
  208. X#include "copyright.h"
  209. X
  210. X/* ftp.c globals */
  211. Xstruct                sockaddr_in hisctladdr;
  212. Xstruct                sockaddr_in data_addr;
  213. Xint                    data = -1;
  214. Xint                    abrtflag = 0;
  215. Xint                    connected;            /* connected to server */
  216. Xstruct sockaddr_in    myctladdr;
  217. XFILE                *cin = NULL, *cout = NULL;
  218. Xchar                *reply_string = NULL;
  219. Xjmp_buf                sendabort, recvabort;
  220. Xint                    want_progress = 1;
  221. Xint                    sendport = -1;        /* use PORT cmd for each data connection */
  222. Xint                    code;                /* return/reply code for ftp command */
  223. Xstring                hostname;            /* name of host connected to */
  224. Xint                 cpend;                /* flag: if != 0, then pending server reply */
  225. Xchar                *xferbuf;            /* buffer for local and remote I/O */
  226. Xsize_t                xferbufsize;        /* size in bytes, of the transfer buffer. */
  227. Xlong                next_report;
  228. Xlong                bytes;
  229. Xlong                now_sec;
  230. Xlong                remote_size;
  231. Xstruct timeval        start, stop;
  232. X
  233. X
  234. X/* ftp.c externs */
  235. Xextern FILE                    *logf;
  236. Xextern string                hostname, cwd, anon_password;
  237. Xextern int                    verbose, debug, macnum, margc;
  238. Xextern int                    curtype, creating;
  239. Xextern int                    options, activemcmd, paging;
  240. Xextern char                    *line, *margv[];
  241. Xextern struct userinfo        uinfo;
  242. Xextern struct macel            macros[];
  243. X#ifdef REDIR
  244. Xextern struct lslist        *lshead, *lstail;
  245. Xextern int                    is_ls;
  246. X#endif
  247. X
  248. X
  249. X
  250. Xint hookup(char *host, int port)
  251. X{
  252. X    register struct hostent *hp = 0;
  253. X    int s, len, hErr = -1;
  254. X
  255. X    bzero((char *)&hisctladdr, sizeof (hisctladdr));
  256. X    hisctladdr.sin_addr.s_addr = inet_addr(host);
  257. X    if (hisctladdr.sin_addr.s_addr != -1) {
  258. X        hisctladdr.sin_family = AF_INET;
  259. X        (void) Strncpy(hostname, host);
  260. X    } else {
  261. X        hp = gethostbyname(host);
  262. X        if (hp == NULL) {
  263. X#ifdef HERROR
  264. X            extern int h_errno;
  265. X            if (h_errno == HOST_NOT_FOUND)
  266. X                (void) printf("%s: unknown host\n", host);
  267. X            else (void) fprintf(stderr, "%s: gethostbyname herror (%d):  ",
  268. X                host, h_errno);
  269. X            herror(NULL);
  270. X#else
  271. X            (void) printf("%s: unknown host\n", host);
  272. X#endif
  273. X            goto done;
  274. X        }
  275. X        hisctladdr.sin_family = hp->h_addrtype;
  276. X        bcopy(hp->h_addr_list[0],
  277. X            (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  278. X        (void) Strncpy(hostname, hp->h_name);
  279. X    }
  280. X    s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  281. X    if (s < 0) {
  282. X        Perror("socket");
  283. X        goto done;
  284. X    }
  285. X    hisctladdr.sin_port = port;
  286. X    while (connect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
  287. X        if (hp && hp->h_addr_list[1]) {
  288. X            int oerrno = errno;
  289. X
  290. X            (void) fprintf(stderr, "NcFTP: connect error (%d) to address %s: ",
  291. X                errno, inet_ntoa(hisctladdr.sin_addr));
  292. X            errno = oerrno;
  293. X            Perror((char *) 0);
  294. X            hp->h_addr_list++;
  295. X            bcopy(hp->h_addr_list[0],
  296. X                 (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  297. X            (void) fprintf(stdout, "Trying %s...\n",
  298. X                inet_ntoa(hisctladdr.sin_addr));
  299. X            (void) close(s);
  300. X            s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  301. X            if (s < 0) {
  302. X                Perror("socket");
  303. X                goto done;
  304. X            }
  305. X            continue;
  306. X        }
  307. X        Perror("connect");
  308. X        switch (errno) {
  309. X            case ENETDOWN:
  310. X            case ENETUNREACH:
  311. X            case ECONNABORTED:
  312. X            case ETIMEDOUT:
  313. X            case ECONNREFUSED:
  314. X            case EHOSTDOWN:
  315. X                hErr = -2;    /* we can re-try later. */
  316. X        }
  317. X        goto bad;
  318. X    }
  319. X    len = sizeof (myctladdr);
  320. X    if (getsockname(s, (char *)&myctladdr, &len) < 0) {
  321. X        Perror("getsockname");
  322. X        goto bad;
  323. X    }
  324. X    cin = fdopen(s, "r");
  325. X    cout = fdopen(s, "w");
  326. X    if (cin == NULL || cout == NULL) {
  327. X        (void) fprintf(stderr, "ftp: fdopen failed.\n");
  328. X        close_streams(0);
  329. X        goto bad;
  330. X    }
  331. X    if (IS_VVERBOSE)
  332. X        (void) printf("Connected to %s.\n", hostname);
  333. X    if (getreply(0) > 2) {     /* read startup message from server */
  334. X        close_streams(0);
  335. X        goto bad;
  336. X    }
  337. X#ifdef SO_OOBINLINE
  338. X    {
  339. X    int on = 1;
  340. X
  341. X    if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
  342. X        < 0 && debug) {
  343. X            Perror("setsockopt");
  344. X        }
  345. X    }
  346. X#endif /* SO_OOBINLINE */
  347. X
  348. X    hErr = 0;
  349. X    goto done;
  350. X
  351. Xbad:
  352. X    (void) close(s);
  353. Xdone:
  354. X    code = hErr;
  355. X    return (hErr);
  356. X}    /* hookup */
  357. X
  358. X
  359. X
  360. X
  361. Xint login(char *host, int openmode, int ignore_rc)
  362. X{
  363. X    string                tmp, str;
  364. X    char                *username, *pass, *acct;
  365. X    int                    n, aflag = 0, prompted_login;
  366. X    int                    user_in_rc, tmpverbose;
  367. X
  368. X    username = pass = acct = NULL;
  369. X    if (!ignore_rc) {
  370. X        if ((ruserpass2(host, &username, &pass, &acct)) < 0) {
  371. X            /*NOTREACHED */
  372. X            code = -1;
  373. X            return(0);
  374. X        }
  375. X    }
  376. X
  377. X    user_in_rc = 1;
  378. X    prompted_login = 0;
  379. X    if (username == NULL) {
  380. X        user_in_rc = 0;
  381. X        prompted_login = 1;
  382. X    } 
  383. X
  384. X    if (!user_in_rc) {
  385. X        /* There was no username in the rc. */
  386. X        if (openmode == OPEN_A) {
  387. X            username = "anonymous";
  388. X            prompted_login = 0;
  389. X        } else { /* openmode == OPEN_U */
  390. X            /* Prompt for a username. */
  391. X            (void) printf("Name (%s:%s): ", host, uinfo.username);
  392. X            (void) FGets(tmp, stdin);
  393. X            tmp[strlen(tmp) - 1] = '\0';
  394. X            /*
  395. X             *    User can hit return if he wants to enter his username
  396. X             *    automatically.
  397. X             */
  398. X            if (*tmp == '\0')
  399. X                username = uinfo.username;
  400. X            else
  401. X                username = tmp;
  402. X        }
  403. X    }
  404. X    (void) sprintf(str, "USER %s", username);
  405. X    n = command(str);
  406. X    if (n == CONTINUE) {
  407. X        if (pass == NULL) {
  408. X            if (strcmp("anonymous", username) == 0)
  409. X                pass = anon_password;
  410. X            else
  411. X                pass = getpass2("Password:");
  412. X        }
  413. X        (void) sprintf(str, "PASS %s", pass);
  414. X        n = command(str);
  415. X    }
  416. X    if (n == CONTINUE) {
  417. X        aflag++;
  418. X        acct = getpass2("Account:");
  419. X        (void) sprintf(str, "ACCT %s", acct);
  420. X        n = command(str);
  421. X    }
  422. X    if (n != COMPLETE) {
  423. XnoLogin:
  424. X        (void) fprintf(stderr, "Login failed.\n");
  425. X        return (0);
  426. X    }
  427. X    if (!aflag && acct != NULL) {
  428. X        (void) sprintf(str, "ACCT %s", acct);
  429. X        (void) command(str);
  430. X    }
  431. X
  432. X    /* See if remote host dropped connection. */
  433. X    tmpverbose = verbose;
  434. X    verbose = V_QUIET;
  435. X    n = command("NOOP");
  436. X    verbose = tmpverbose;
  437. X    if (n == 4)
  438. X        goto noLogin;
  439. X
  440. X    if (NOT_VQUIET && !prompted_login)
  441. X        (void) printf("Logged into %s.\n", host);
  442. X    if (!ignore_rc)
  443. X        for (n = 0; n < macnum; ++n) {
  444. X            if (!strcmp("init", macros[n].mac_name)) {
  445. X                (void) strcpy(line, "$init");
  446. X                makeargv();
  447. X                domacro(margc, margv);
  448. X                break;
  449. X            }
  450. X        }
  451. X    return (1);
  452. X}    /* login */
  453. X
  454. X
  455. X
  456. X/*ARGSUSED*/
  457. Xvoid cmdabort(int unused)
  458. X{
  459. X    (void) printf("\n");
  460. X    (void) fflush(stdout);
  461. X    abrtflag++;
  462. X}    /* cmdabort */
  463. X
  464. X
  465. X
  466. X
  467. Xcommand(char *cmd)
  468. X{
  469. X    int r;
  470. X    void (*oldintr)(int);
  471. X    string str;
  472. X
  473. X    abrtflag = 0;
  474. X    if (debug) {
  475. X        (void) printf("---> %s\n", cmd);
  476. X    }
  477. X    if (cout == NULL) {
  478. X        (void) sprintf(str, "%s: No control connection for command", cmd);
  479. X        Perror(str);
  480. X        code = -1;
  481. X        return (0);
  482. X    }
  483. X    oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
  484. X#ifndef SCO324
  485. X    if (cout != NULL)
  486. X        (void) fprintf(cout, "%s\r\n", cmd);
  487. X#else
  488. X    {
  489. X        /*
  490. X         * The fprintf() above gives me a core-dump in memcpy()...
  491. X         * This does the trick though...
  492. X         */
  493. X
  494. X        char *p = cmd;
  495. X        while (*p)
  496. X            fputc(*p++, cout);
  497. X        fputc('\r', cout);
  498. X        fputc('\n', cout);
  499. X    }
  500. X#endif /* !SCO324 */
  501. X    (void) fflush(cout);
  502. X    cpend = 1;
  503. X    r = getreply(strcmp(cmd, "QUIT") == 0);
  504. X    if (abrtflag && oldintr != SIG_IGN && oldintr != NULL)
  505. X        (*oldintr)(0);
  506. X    (void) signal(SIGINT, oldintr);
  507. X    return(r);
  508. X}    /* command */
  509. X
  510. X
  511. X
  512. X
  513. Xgetreply(int expecteof)
  514. X{
  515. X    register int c, n;
  516. X    int dig;
  517. X    char *cp, *end, *dp;
  518. X    int thiscode, originalcode = 0, continuation = 0;
  519. X    void (*oldintr)(int);
  520. X
  521. X    if (cin == NULL)
  522. X        return (-1);
  523. X    oldintr = signal(SIGINT, /* cmdabort */ SIG_IGN);
  524. X    end = reply_string + RECEIVEDLINELEN - 2;
  525. X    for (;;) {
  526. X        dig = n = code = 0;
  527. X        cp = reply_string;
  528. X        for (;;) {
  529. X            c = getc(cin);
  530. X            if (c == IAC) {     /* handle telnet commands */
  531. X                switch (c = getc(cin)) {
  532. X                case WILL:
  533. X                case WONT:
  534. X                    c = getc(cin);
  535. X                    (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
  536. X                    (void) fflush(cout);
  537. X                    break;
  538. X                case DO:
  539. X                case DONT:
  540. X                    c = getc(cin);
  541. X                    (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
  542. X                    (void) fflush(cout);
  543. X                    break;
  544. X                default:
  545. X                    break;
  546. X                }
  547. X                continue;
  548. X            }
  549. X            dig++;
  550. X            if (c == EOF) {
  551. X                if (expecteof) {
  552. X                    (void) signal(SIGINT,oldintr);
  553. X                    code = 221;
  554. X                    return (0);
  555. X                }
  556. X                lostpeer(0);
  557. X                if (NOT_VQUIET) {
  558. X                    (void) printf("421 Service not available, remote server has closed connection\n");
  559. X                    (void) fflush(stdout);
  560. X                }
  561. X                code = 421;
  562. X                return(4);
  563. X            }
  564. X            if (cp < end && c != '\r')
  565. X                *cp++ = c;
  566. X
  567. X            if (c == '\n')
  568. X                break;
  569. X            if (dig < 4 && isdigit(c))
  570. X                code = thiscode = code * 10 + (c - '0');
  571. X            else if (dig == 4 && c == '-') {
  572. X                if (continuation)
  573. X                    code = 0;
  574. X                continuation++;
  575. X            }
  576. X            if (n == 0)
  577. X                n = c;
  578. X        }    /* end for(;;) #2 */
  579. X        
  580. X        *cp = '\0';
  581. X        switch (verbose) {
  582. X            case V_QUIET:
  583. X                /* Don't print anything. */
  584. X                break;
  585. X            case V_ERRS:
  586. X                if (n == '5') {
  587. X                    dp = reply_string;
  588. X                    goto stripCode;
  589. X                }
  590. X                break;    
  591. X            case V_TERSE:
  592. X                dp = NULL;
  593. X                if (n == '5')
  594. X                    dp = reply_string;
  595. X                else if (n == '2') {
  596. X                    switch (thiscode) {
  597. X                        case 230:
  598. X                        case 214:
  599. X                        case 332:
  600. X                            dp = reply_string;
  601. X                            break;
  602. X                        case 220:
  603. X                            /*
  604. X                             * Skip the foo FTP server ready line.
  605. X                             */
  606. X                            if (strstr(reply_string, "ready.") == NULL)
  607. X                                dp = reply_string;
  608. X                            break;
  609. X                        case 250:
  610. X                            /*
  611. X                             * Print 250 lines if they aren't
  612. X                             * "250 CWD command successful."
  613. X                             */
  614. X                            if (strncmp(reply_string + 4, "CWD ", (size_t) 4))
  615. X                                dp = reply_string;
  616. X                    }
  617. X                }
  618. X                if (dp == NULL) break;            
  619. XstripCode:
  620. X                /* Try to strip out the code numbers, etc. */
  621. X                if (isdigit(*dp++) && isdigit(*dp++) && isdigit(*dp++)) {
  622. X                    if (*dp == ' ' || *dp == '-') {
  623. X                        dp++;
  624. X                        if (*dp == ' ') dp++;
  625. X                    } else dp = reply_string;            
  626. X                } else {
  627. X                    int spaces;
  628. X                    dp = reply_string;
  629. X                    for (spaces = 0; spaces < 4; ++spaces)
  630. X                        if (dp[spaces] != ' ')
  631. X                            break;
  632. X                    if (spaces == 4)
  633. X                        dp += spaces;
  634. X                }                    
  635. X                goto printLine;
  636. X            case V_VERBOSE:
  637. X                dp = reply_string;
  638. XprintLine:        (void) fputs(dp, stdout);
  639. X        }    /* end switch */
  640. X
  641. X        if (continuation && code != originalcode) {
  642. X            if (originalcode == 0)
  643. X                originalcode = code;
  644. X            continue;
  645. X        }
  646. X        if (n != '1')
  647. X            cpend = 0;
  648. X        (void) signal(SIGINT,oldintr);
  649. X        if (code == 421 || originalcode == 421)
  650. X            lostpeer(0);
  651. X        if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN && oldintr)
  652. X            (*oldintr)(0);
  653. X        return (n - '0');
  654. X    }    /* end for(;;) #1 */
  655. X}    /* getreply */
  656. X
  657. X
  658. X
  659. X
  660. Xstatic int empty(struct fd_set *mask, int sec)
  661. X{
  662. X    struct timeval t;
  663. X
  664. X    t.tv_sec = (long) sec;
  665. X    t.tv_usec = 0;
  666. X    return(select(32, (int *) mask, (int *) 0, (int *) 0, &t));
  667. X}    /* empty */
  668. X
  669. X
  670. X
  671. Xvoid progress_report(void)
  672. X{
  673. X    next_report += xferbufsize;
  674. X    (void) gettimeofday(&stop, (struct timezone *)0);
  675. X    if (stop.tv_sec > now_sec) {
  676. X        (void) printf("\b\b\b\b\b\b%3ld%%  ", 100L * bytes / remote_size);
  677. X        (void) fflush(stdout);
  678. X        now_sec = stop.tv_sec;
  679. X    }
  680. X}    /* progress_report */
  681. X
  682. X
  683. X
  684. Xvoid close_file(FILE **fin, int filetype)
  685. X{
  686. X    if (*fin != NULL) {
  687. X        if (filetype == IS_FILE) {
  688. X            (void) fclose(*fin);
  689. X            *fin = NULL;
  690. X        } else if (filetype == IS_PIPE) {
  691. X            (void) pclose(*fin);
  692. X            *fin = NULL;
  693. X        }
  694. X    }
  695. X}    /* close_file */
  696. X
  697. X
  698. X
  699. X
  700. X/*ARGSUSED*/
  701. Xvoid abortsend(int unused)
  702. X{
  703. X    activemcmd = 0;
  704. X    abrtflag = 0;
  705. X    (void) printf("\nSend aborted.\n");
  706. X    (void) fflush(stdout);
  707. X    longjmp(sendabort, 1);
  708. X}    /* abortsend */
  709. X
  710. X
  711. X
  712. Xvoid sendrequest(char *cmd, char *local, char *remote)
  713. X{
  714. X    FILE                    *fin, *dout = NULL;
  715. X    void                    (*oldintr)(int), (*oldintp)(int);
  716. X    string                    str;
  717. X    register int            c, d;
  718. X    struct stat                st;
  719. X    int                        filetype;
  720. X    int                        do_reports = 0;
  721. X    char                    *mode;
  722. X    register char            *bufp;
  723. X
  724. X    oldintr = NULL;
  725. X    oldintp = NULL;
  726. X    mode = "w";
  727. X    bytes = 0;
  728. X    if (setjmp(sendabort)) {
  729. X        while (cpend) {
  730. X            (void) getreply(0);
  731. X        }
  732. X        if (data >= 0) {
  733. X            (void) close(data);
  734. X            data = -1;
  735. X        }
  736. X        if (oldintr)
  737. X            (void) signal(SIGINT,oldintr);
  738. X        if (oldintp)
  739. X            (void) signal(SIGPIPE,oldintp);
  740. X        code = -1;
  741. X        return;
  742. X    }
  743. X    oldintr = signal(SIGINT, abortsend);
  744. X    if (strcmp(local, "-") == 0)  {
  745. X        fin = stdin;
  746. X        filetype = IS_STREAM;
  747. X    } else if (*local == '|') {
  748. X        filetype = IS_PIPE;
  749. X        oldintp = signal(SIGPIPE,SIG_IGN);
  750. X        fin = popen(local + 1, "r");
  751. X        if (fin == NULL) {
  752. X            Perror(local + 1);
  753. X            (void) signal(SIGINT, oldintr);
  754. X            (void) signal(SIGPIPE, oldintp);
  755. X            code = -1;
  756. X            return;
  757. X        }
  758. X    } else {
  759. X        filetype = IS_FILE;
  760. X        fin = fopen(local, "r");
  761. X        if (fin == NULL) {
  762. X            Perror(local);
  763. X            (void) signal(SIGINT, oldintr);
  764. X            code = -1;
  765. X            return;
  766. X        }
  767. X        if (fstat(fileno(fin), &st) < 0 ||
  768. X            (st.st_mode&S_IFMT) != S_IFREG) {
  769. X            (void) fprintf(stdout, "%s: not a plain file.\n", local);
  770. X            (void) signal(SIGINT, oldintr);
  771. X            (void) fclose(fin);
  772. X            code = -1;
  773. X            return;
  774. X        }
  775. X    }
  776. X    if (initconn()) {
  777. X        (void) signal(SIGINT, oldintr);
  778. X        if (oldintp)
  779. X            (void) signal(SIGPIPE, oldintp);
  780. X        code = -1;
  781. X        close_file(&fin, filetype);
  782. X        return;
  783. X    }
  784. X    if (setjmp(sendabort))
  785. X        goto Abort;
  786. X
  787. X    if (remote) {
  788. X        (void) sprintf(str, "%s %s", cmd, remote);
  789. X        if (command(str) != PRELIM) {
  790. X            (void) signal(SIGINT, oldintr);
  791. X            if (oldintp)
  792. X                (void) signal(SIGPIPE, oldintp);
  793. X            close_file(&fin, filetype);
  794. X            return;
  795. X        }
  796. X    } else
  797. X        if (command(cmd) != PRELIM) {
  798. X            (void) signal(SIGINT, oldintr);
  799. X            if (oldintp)
  800. X                (void) signal(SIGPIPE, oldintp);
  801. X            close_file(&fin, filetype);
  802. X            return;
  803. X        }
  804. X    dout = dataconn(mode);
  805. X    if (dout == NULL)
  806. X        goto Abort;
  807. X    (void) gettimeofday(&start, (struct timezone *)0);
  808. X    oldintp = signal(SIGPIPE, SIG_IGN);
  809. X    if (filetype == IS_FILE && NOT_VQUIET) {
  810. X        now_sec = start.tv_sec;
  811. X        do_reports = want_progress;
  812. X        (void) printf("%s:       ", local);
  813. X        (void) fflush(stdout);
  814. X    }
  815. X
  816. X    switch (curtype) {
  817. X
  818. X    case TYPE_I:
  819. X    case TYPE_L:
  820. X        errno = d = 0;
  821. X        while ((c = read(fileno(fin), xferbuf, (int)xferbufsize)) > 0) {
  822. X            bytes += c;
  823. X            for (bufp = xferbuf; c > 0; c -= d, bufp += d)
  824. X                if ((d = write(fileno(dout), bufp, c)) <= 0)
  825. X                    break;
  826. X            /* Print progress indicator. */
  827. X            if (do_reports)
  828. X                progress_report();
  829. X        }
  830. X        if (c < 0)
  831. X            Perror(local);
  832. X        if (d <= 0) {
  833. X            if (d == 0 && !creating)
  834. X                (void) fprintf(stderr, "netout: write returned 0?\n");
  835. X            else if (errno != EPIPE) 
  836. X                Perror("netout");
  837. X            bytes = -1;
  838. X        }
  839. X        break;
  840. X
  841. X    case TYPE_A:
  842. X        next_report = xferbufsize;
  843. X        while ((c = getc(fin)) != EOF) {
  844. X            if (c == '\n') {
  845. X                if (ferror(dout))
  846. X                    break;
  847. X                (void) putc('\r', dout);
  848. X                bytes++;
  849. X            }
  850. X            (void) putc(c, dout);
  851. X            bytes++;
  852. X
  853. X            /* Print progress indicator. */
  854. X            if (do_reports && bytes > next_report)
  855. X                progress_report();
  856. X        }
  857. X        if (ferror(fin))
  858. X            Perror(local);
  859. X        if (ferror(dout)) {
  860. X            if (errno != EPIPE)
  861. X                Perror("netout");
  862. X            bytes = -1;
  863. X        }
  864. X        break;
  865. X    }
  866. XDone:
  867. X    (void) gettimeofday(&stop, (struct timezone *)0);
  868. X    close_file(&fin, filetype);
  869. X    if (dout)
  870. X        (void) fclose(dout);
  871. X    (void) getreply(0);
  872. X    (void) signal(SIGINT, oldintr);
  873. X    if (oldintp)
  874. X        (void) signal(SIGPIPE, oldintp);
  875. X    if (bytes > 0)
  876. X        ptransfer("sent", bytes, &start, &stop, local, remote);
  877. X    return;
  878. XAbort:
  879. X    code = -1;
  880. X    if (!cpend)
  881. X        return;
  882. X    if (data >= 0) {
  883. X        (void) close(data);
  884. X        data = -1;
  885. X    }
  886. X    goto Done;
  887. X}    /* sendrequest */
  888. X
  889. X
  890. X
  891. Xlong get_remote_size(char *remote, int filetype)
  892. X{
  893. X    int oldverbose;
  894. X    long rmt_size;
  895. X    string str;
  896. X
  897. X    rmt_size = -1;                /*
  898. X                                 * Return -1 if we could't get it. 
  899. X                                 * Not all sites support SIZE.
  900. X                                 */
  901. X    
  902. X    if (filetype == IS_FILE) {
  903. X        /* Won't make sense for a pipe or stream. */
  904. X        (void) sprintf(str, "SIZE %s", remote);
  905. X        *reply_string = 0;
  906. X        oldverbose = verbose;
  907. X        verbose = V_QUIET;
  908. X        (void) command(str);
  909. X        verbose = oldverbose;
  910. X        if (*reply_string != 5)        /* 5xx is an error. */
  911. X            (void) sscanf(reply_string, "%*d %ld", &rmt_size);    
  912. X    }
  913. X    return rmt_size;
  914. X}    /* get_remote_size */
  915. X
  916. X
  917. X
  918. X/*ARGSUSED*/
  919. Xvoid abortrecv(int unused)
  920. X{
  921. X    activemcmd = 0;
  922. X    abrtflag = 0;
  923. X    (void) printf("(abort)\n");
  924. X    (void) fflush(stdout);
  925. X    longjmp(recvabort, 1);
  926. X}    /* abortrecv */
  927. X
  928. X
  929. X
  930. Xvoid recvrequest(char *cmd, char *local, char *remote, char *mode)
  931. X{
  932. X    FILE                        *fout, *din;
  933. X    void                        (*oldintr)(int), (*oldintp)(int); 
  934. X    int                            oldverbose, oldtype = 0, is_retr;
  935. X    int                            tcrflag, nfnd;
  936. X    char                        msg;
  937. X    string                        str;
  938. X    struct fd_set                mask;
  939. X    int                            c, d;
  940. X    int                            filetype, do_reports = 0;
  941. X#ifdef REDIR
  942. X    char                        *linePtr;
  943. X    int                            nchars;
  944. X    string                        str2;
  945. X#endif
  946. X
  947. X    bytes = 0;
  948. X    is_retr = strcmp(cmd, "RETR") == 0;
  949. X    oldintr = NULL;
  950. X    oldintp = NULL;
  951. X    tcrflag = /* !crflag && */ is_retr;
  952. X    if (setjmp(recvabort)) {
  953. X        while (cpend) {
  954. X            (void) getreply(0);
  955. X        }
  956. X        if (data >= 0) {
  957. X            (void) close(data);
  958. X            data = -1;
  959. X        }
  960. X        if (oldintr)
  961. X            (void) signal(SIGINT, oldintr);
  962. X        code = -1;
  963. X        return;
  964. X    }
  965. X    oldintr = signal(SIGINT, abortrecv);
  966. X
  967. X    if (strcmp(local, "-") == 0)
  968. X        filetype = IS_STREAM;
  969. X    else if (*local == '|')
  970. X        filetype = IS_PIPE;
  971. X    else {
  972. X        filetype = IS_FILE;  /* is_retr ? IS_FILE : IS_STREAM; */
  973. X        if (access(local, 2) < 0) {
  974. X            char *dir = rindex(local, '/');
  975. X
  976. X            if (errno != ENOENT && errno != EACCES) {
  977. X                Perror(local);
  978. X                (void) signal(SIGINT, oldintr);
  979. X                code = -1;
  980. X                return;
  981. X            }
  982. X            /* See if we have write permission on this directory. */
  983. X            if (dir != NULL) {
  984. X                /* Special case: /filename. */
  985. X                if (dir != local)
  986. X                    *dir = 0;
  987. X                if (access(dir == local ? "/" : local, 2) < 0) {
  988. X                    /*
  989. X                     *    We have a big long pathname, like /a/b/c/d,
  990. X                     *    but see if we can write into the current
  991. X                     *    directory and call the file ./d.
  992. X                     */
  993. X                    if (access(".", 2) < 0) {
  994. X                        (void) strcpy(local, " and .");
  995. X                        goto noaccess;
  996. X                    }
  997. X                    (void) strcpy(local, dir + 1);    /* use simple filename. */
  998. X                } else
  999. X                    *dir = '/';
  1000. X            } else {
  1001. X                /* We have a simple path name (file name only). */
  1002. X                if (access(".", 2) < 0) {
  1003. Xnoaccess:            Perror(local);
  1004. X                    (void) signal(SIGINT, oldintr);
  1005. X                    code = -1;
  1006. X                    return;
  1007. X                }
  1008. X            }
  1009. X        }
  1010. X    }
  1011. X    if (initconn()) {
  1012. X        (void) signal(SIGINT, oldintr);
  1013. X        code = -1;
  1014. X        return;
  1015. X    }
  1016. X    if (!is_retr) {
  1017. X        if (curtype != TYPE_A) {
  1018. X            oldtype = curtype;
  1019. X            oldverbose = verbose;
  1020. X            if (!debug)
  1021. X                verbose = V_QUIET;
  1022. X            setascii(0, NULL);
  1023. X            verbose = oldverbose;
  1024. X        }
  1025. X    }
  1026. X
  1027. X    remote_size = get_remote_size(remote, filetype);
  1028. X    if (remote) {
  1029. X        (void) sprintf(str, "%s %s", cmd, remote);
  1030. X        if (command(str) != PRELIM) 
  1031. X            goto nevrmind;
  1032. X    } else {
  1033. X        if (command(cmd) != PRELIM) {
  1034. Xnevrmind:    (void) signal(SIGINT, oldintr);
  1035. X            if (oldtype) {
  1036. X                if (!debug)
  1037. X                    verbose = V_QUIET;
  1038. X                if (oldtype == TYPE_I)
  1039. X                    setbinary(0, NULL);
  1040. X                verbose = oldverbose;
  1041. X            }
  1042. X            return;
  1043. X        }
  1044. X    }
  1045. X    din = dataconn("r");
  1046. X    if (din == NULL)
  1047. X        goto Abort;
  1048. X    if (filetype == IS_STREAM) {
  1049. X        fout = stdout;
  1050. X    } else if (filetype == IS_PIPE) {
  1051. X        oldintp = signal(SIGPIPE, SIG_IGN);
  1052. X        fout = popen(local + 1, "w");
  1053. X        if (fout == NULL) {
  1054. X            Perror(local+1);
  1055. X            goto Abort;
  1056. X        }
  1057. X    } else {
  1058. X        fout = fopen(local, mode);
  1059. X        if (fout == NULL) {
  1060. X            Perror(local);
  1061. X            goto Abort;
  1062. X        }
  1063. X    }
  1064. X
  1065. X    (void) gettimeofday(&start, (struct timezone *)0);
  1066. X    do_reports = want_progress && (remote_size > 0) && !paging;
  1067. X    if (filetype == IS_FILE && NOT_VQUIET && do_reports) {
  1068. X        now_sec = start.tv_sec;
  1069. X        (void) printf("%s:       ", local);
  1070. X        (void) fflush(stdout);
  1071. X    }
  1072. X
  1073. X    if (setjmp(recvabort))
  1074. X        goto Abort;
  1075. X
  1076. X    switch (curtype) {
  1077. X
  1078. X    case TYPE_I:
  1079. X    case TYPE_L:
  1080. X        errno = d = 0;
  1081. X        while ((c = read(fileno(din), xferbuf, (int)xferbufsize)) > 0) {
  1082. X            if ((d = write(fileno(fout), xferbuf, c)) != c)
  1083. X                break;
  1084. X            bytes += c;
  1085. X
  1086. X            /* Print progress indicator. */
  1087. X            if (do_reports)
  1088. X                progress_report();
  1089. X        }
  1090. X        if (c < 0) {
  1091. X            if (errno != EPIPE)
  1092. X                Perror("netin");
  1093. X            bytes = -1;
  1094. X        }
  1095. X        if (d < c) {
  1096. X            if (d < 0) {
  1097. X                if (errno != EPIPE)
  1098. X                    Perror(local);
  1099. X            } else
  1100. X                (void) fprintf(stderr, "%s: short write\n", local);
  1101. X        }
  1102. X        break;
  1103. X
  1104. X    case TYPE_A:
  1105. X#ifdef REDIR
  1106. X        nchars = 0;
  1107. X        linePtr = str2;
  1108. X#endif
  1109. X        next_report = xferbufsize;
  1110. X        while ((c = getc(din)) != EOF) {
  1111. X            while (c == '\r') {
  1112. X                bytes++;
  1113. X                if ((c = getc(din)) != '\n' || tcrflag) {
  1114. X                    if (ferror(fout))
  1115. X                        goto break2;
  1116. X                    (void) putc('\r', fout);
  1117. X                    if (c == '\0') {
  1118. X                        bytes++;
  1119. X                        goto contin2;
  1120. X                    }
  1121. X                    if (c == EOF)
  1122. X                        goto contin2;
  1123. X                }
  1124. X            }
  1125. X            (void) putc(c, fout);
  1126. X            bytes++;
  1127. X            
  1128. X            /* Print progress indicator. */
  1129. X            if (do_reports && bytes > next_report)
  1130. X                progress_report();
  1131. X#ifdef REDIR
  1132. X            if (nchars < sizeof(str2) - 1) {        /* No seg violations, please */
  1133. X                 *linePtr++ = c;  /* build redir string */
  1134. X                 nchars++;
  1135. X             }
  1136. X#endif
  1137. X   contin2:
  1138. X#ifdef REDIR
  1139. X            /* Save the input line in the buffer for recall later. */
  1140. X             if (c=='\n' && is_ls) {
  1141. X                register struct lslist *new;
  1142. X    
  1143. X                *--linePtr = '\0';
  1144. X                nchars--;
  1145. X                new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
  1146. X                if (new != NULL) {
  1147. X                    if (new->string = malloc(strlen(str2) + 1))
  1148. X                        (void) strcpy(new->string, str2);
  1149. X                       new->next = NULL;
  1150. X                       if (lshead == NULL)
  1151. X                           lshead = lstail = new;
  1152. X                      else {
  1153. X                          lstail->next = new;
  1154. X                          lstail = new;
  1155. X                      }
  1156. X                  }
  1157. X                  /* reset line buffer */
  1158. X                linePtr = str2;
  1159. X                nchars = 0;
  1160. X            }    /* ls mode & last char is a newline */
  1161. X#else
  1162. X            ;
  1163. X#endif
  1164. X        }    /* while ((c = getc(din)) != EOF) */
  1165. Xbreak2:
  1166. X        if (ferror(din)) {
  1167. X            if (errno != EPIPE)
  1168. X                Perror("netin");
  1169. X            bytes = -1;
  1170. X        }
  1171. X        if (ferror(fout)) {
  1172. X            if (errno != EPIPE)
  1173. X                Perror(local);
  1174. X        }
  1175. X        break;
  1176. X    }    /* end switch (curtype) */
  1177. X    
  1178. X    close_file(&fout, filetype);
  1179. X    (void) signal(SIGINT, oldintr);
  1180. X    if (oldintp)
  1181. X        (void) signal(SIGPIPE, oldintp);
  1182. X    (void) gettimeofday(&stop, (struct timezone *)0);
  1183. X    if (din)
  1184. X        (void) fclose(din);
  1185. X    (void) getreply(0);
  1186. X    if (bytes > 0 && is_retr && !paging)
  1187. X        ptransfer("received", bytes, &start, &stop, local, remote);
  1188. X    if (oldtype) {
  1189. X        if (!debug)
  1190. X            verbose = V_QUIET;
  1191. X            if (oldtype == TYPE_I)
  1192. X                setbinary(0, NULL);
  1193. X        verbose = oldverbose;
  1194. X    }
  1195. X    return;
  1196. XAbort:
  1197. X
  1198. X/* Abort using RFC959 recommended IP,SYNC sequence  */
  1199. X
  1200. X    (void) gettimeofday(&stop, (struct timezone *)0);
  1201. X    if (oldintp)
  1202. X        (void) signal(SIGPIPE, oldintr);
  1203. X    (void) signal(SIGINT,SIG_IGN);
  1204. X    if (oldtype) {
  1205. X        if (!debug)
  1206. X            verbose = V_QUIET;
  1207. X            if (oldtype == TYPE_I)
  1208. X                setbinary(0, NULL);
  1209. X        verbose = oldverbose;
  1210. X    }
  1211. X    if (!cpend) {
  1212. X        code = -1;
  1213. X        (void) signal(SIGINT,oldintr);
  1214. X        return;
  1215. X    }
  1216. X
  1217. X    if (!cout) return;
  1218. X    (void) fprintf(cout,"%c%c",IAC,IP);
  1219. X    (void) fflush(cout); 
  1220. X    msg = IAC;
  1221. X/* send IAC in urgent mode instead of DM because UNIX places oob mark */
  1222. X/* after urgent byte rather than before as now is protocol            */
  1223. X    if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
  1224. X        Perror("abort");
  1225. X    }
  1226. X    (void) fprintf(cout,"%cABOR\r\n",DM);
  1227. X    (void) fflush(cout);
  1228. X    FD_ZERO(&mask);
  1229. X    FD_SET(fileno(cin), &mask);
  1230. X    if (din) { 
  1231. X        FD_SET(fileno(din), &mask);
  1232. X    }
  1233. X    if ((nfnd = empty(&mask,10)) <= 0) {
  1234. X        if (nfnd < 0) {
  1235. X            Perror("abort");
  1236. X        }
  1237. X        code = -1;
  1238. X        lostpeer(0);
  1239. X    }
  1240. X    if (din && FD_ISSET(fileno(din), &mask)) {
  1241. X        while ((c = read(fileno(din), xferbuf, xferbufsize)) > 0)
  1242. X            ;
  1243. X    }
  1244. X    if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
  1245. X        if (data >= 0) {
  1246. X            (void) close(data);
  1247. X            data = -1;
  1248. X        }
  1249. X        (void) getreply(0);
  1250. X    }
  1251. X    (void) getreply(0);
  1252. X    code = -1;
  1253. X    if (data >= 0) {
  1254. X        (void) close(data);
  1255. X        data = -1;
  1256. X    }
  1257. X    close_file(&fout, filetype);
  1258. X    if (din)
  1259. X        (void) fclose(din);
  1260. X    if (bytes > 0)
  1261. X        ptransfer("received", bytes, &start, &stop, local, remote);
  1262. X    (void) signal(SIGINT,oldintr);
  1263. X}    /* recvrequest */
  1264. X
  1265. X
  1266. X
  1267. X
  1268. X/*
  1269. X * Need to start a listen on the data channel
  1270. X * before we send the command, otherwise the
  1271. X * server's connect may fail.
  1272. X */
  1273. X
  1274. Xinitconn(void)
  1275. X{
  1276. X    register char        *p, *a;
  1277. X    int                    result, len, tmpno = 0;
  1278. X    int                    on = 1, rval;
  1279. X    string                str;
  1280. X    void                (*oldintr)(int);
  1281. X
  1282. X    oldintr = signal(SIGINT, SIG_IGN);
  1283. Xnoport:
  1284. X    data_addr = myctladdr;
  1285. X    if (sendport)
  1286. X        data_addr.sin_port = 0;    /* let system pick one */ 
  1287. X    if (data != -1)
  1288. X        (void) close (data);
  1289. X    data = socket(AF_INET, SOCK_STREAM, 0);
  1290. X    if (data < 0) {
  1291. X        Perror("socket");
  1292. X        if (tmpno)
  1293. X            sendport = 1;
  1294. X        rval = 1;  goto Return;
  1295. X    }
  1296. X    if (!sendport)
  1297. X        if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
  1298. X            Perror("setsockopt (reuse address)");
  1299. X            goto bad;
  1300. X        }
  1301. X    if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
  1302. X        Perror("bind");
  1303. X        goto bad;
  1304. X    }
  1305. X    if (options & SO_DEBUG &&
  1306. X        setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  1307. X        Perror("setsockopt (ignored)");
  1308. X    len = sizeof (data_addr);
  1309. X    if (getsockname(data, (char *)&data_addr, &len) < 0) {
  1310. X        Perror("getsockname");
  1311. X        goto bad;
  1312. X    }
  1313. X    if (listen(data, 1) < 0)
  1314. X        Perror("listen");
  1315. X    if (sendport) {
  1316. X        a = (char *)&data_addr.sin_addr;
  1317. X        p = (char *)&data_addr.sin_port;
  1318. X#define UC(x) (int) (((int) x) & 0xff)
  1319. X        (void) sprintf(str, "PORT %d,%d,%d,%d,%d,%d",
  1320. X            UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1321. X        result = command(str);
  1322. X        if (result == ERROR && sendport == -1) {
  1323. X            sendport = 0;
  1324. X            tmpno = 1;
  1325. X            goto noport;
  1326. X        }
  1327. X        rval = (result != COMPLETE);  goto Return;
  1328. X    }
  1329. X    if (tmpno)
  1330. X        sendport = 1;
  1331. X    rval = 0;  goto Return;
  1332. Xbad:
  1333. X    (void) close(data), data = -1;
  1334. X    if (tmpno)
  1335. X        sendport = 1;
  1336. X    rval = 1;
  1337. XReturn:
  1338. X    (void) signal(SIGINT, oldintr);
  1339. X    return (rval);
  1340. X}    /* initconn */
  1341. X
  1342. X
  1343. X
  1344. X
  1345. XFILE *
  1346. Xdataconn(char *mode)
  1347. X{
  1348. X    struct sockaddr_in from;
  1349. X    FILE *fp;
  1350. X    int s, fromlen = sizeof (from);
  1351. X
  1352. X    s = accept(data, (struct sockaddr *) &from, &fromlen);
  1353. X    if (s < 0) {
  1354. X        Perror("accept");
  1355. X        (void) close(data), data = -1;
  1356. X        fp = NULL;
  1357. X    } else {
  1358. X        (void) close(data);
  1359. X        data = s;
  1360. X        fp = fdopen(data, mode);
  1361. X    }
  1362. X    return (fp);
  1363. X}    /* dataconn */
  1364. X
  1365. X
  1366. X
  1367. Xstatic void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
  1368. X{
  1369. X    tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  1370. X    tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  1371. X    if (tdiff->tv_usec < 0)
  1372. X        tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  1373. X}    /* tvsub */
  1374. X
  1375. X
  1376. X
  1377. X/*ARGSUSED*/
  1378. Xvoid ptransfer(char *direction, long nbytes, struct timeval *t0, struct timeval *t1, char *local, char *remote)
  1379. X{
  1380. X    struct timeval            td;
  1381. X    float                    s, bs;
  1382. X    char                    *cp;
  1383. X    string                    str;
  1384. X
  1385. X    if (NOT_VQUIET || (logf != NULL)) {
  1386. X        tvsub(&td, t1, t0);
  1387. X        s = td.tv_sec + (td.tv_usec / 1000000.0);
  1388. X        if (s != 0.0)
  1389. X            bs = nbytes / s;
  1390. X        (void) printf("\b\b\b\b\b\b%ld bytes %s in %.2f seconds, ",
  1391. X            nbytes, direction, s);
  1392. X        if (logf != NULL) {
  1393. X            /* if a simple path is given, try to log the full path */
  1394. X            if (rindex(remote, '/') == NULL && cwd != NULL) {
  1395. X                (void) sprintf(str, "%s/%s", cwd, remote);
  1396. X                cp = str;
  1397. X            } else
  1398. X                cp = remote;
  1399. X            (void) fprintf(logf, "\t-> \"%s\" %s, ", cp, direction);
  1400. X        }
  1401. X        if (bs > 1024.0) {
  1402. X            bs /= 1024.0;
  1403. X            cp = "%.2f K/s.\n";
  1404. X        } else cp = "%.2f Bytes/s.\n";
  1405. X        if (NOT_VQUIET) (void) printf(cp, bs);
  1406. X        if (logf != NULL)
  1407. X            (void) fprintf(logf, cp, bs);
  1408. X    } 
  1409. X}   /* ptransfer */
  1410. X
  1411. X/* eof ftp.c */
  1412. END_OF_FILE
  1413.   if test 26888 -ne `wc -c <'ftp.c'`; then
  1414.     echo shar: \"'ftp.c'\" unpacked with wrong size!
  1415.   fi
  1416.   # end of 'ftp.c'
  1417. fi
  1418. if test -f 'ftprc.h' -a "${1}" != "-c" ; then 
  1419.   echo shar: Will not clobber existing file \"'ftprc.h'\"
  1420. else
  1421.   echo shar: Extracting \"'ftprc.h'\" \(423 characters\)
  1422.   sed "s/^X//" >'ftprc.h' <<'END_OF_FILE'
  1423. X/* ftprc.h */
  1424. X
  1425. X#ifndef _ftprc_h_
  1426. X#define _ftprc_h_
  1427. X
  1428. X#ifndef RCNAME
  1429. X#define RCNAME "netrc"
  1430. X#endif
  1431. X
  1432. X#define RC_DELIM " \n\t,"
  1433. X
  1434. Xtypedef struct site *siteptr;
  1435. Xtypedef struct site {
  1436. X    char *name;            /* name (or IP address) of site */
  1437. X    siteptr next;
  1438. X} site;
  1439. X
  1440. Xint thrash_rc(void);
  1441. Xvoid AddNewSitePtr(char *word);
  1442. Xint ruserpass2(char *host, char **user, char **pass, char **acct);
  1443. Xvoid GetFullSiteName(char *host);
  1444. X
  1445. X#endif
  1446. X/* eof */
  1447. END_OF_FILE
  1448.   if test 423 -ne `wc -c <'ftprc.h'`; then
  1449.     echo shar: \"'ftprc.h'\" unpacked with wrong size!
  1450.   fi
  1451.   # end of 'ftprc.h'
  1452. fi
  1453. if test -f 'main.c' -a "${1}" != "-c" ; then 
  1454.   echo shar: Will not clobber existing file \"'main.c'\"
  1455. else
  1456.   echo shar: Extracting \"'main.c'\" \(17355 characters\)
  1457.   sed "s/^X//" >'main.c' <<'END_OF_FILE'
  1458. X/* main.c */
  1459. X
  1460. X#define _main_c_
  1461. X
  1462. X#include "sys.h"
  1463. X#include <sys/types.h>
  1464. X#include <sys/param.h>
  1465. X#include <sys/socket.h>
  1466. X#include <sys/ioctl.h>
  1467. X#include <sys/stat.h>
  1468. X#include <sys/time.h>
  1469. X#include <arpa/ftp.h>
  1470. X#include <setjmp.h>
  1471. X#include <signal.h>
  1472. X#include <stdio.h>
  1473. X#include <stdlib.h>
  1474. X#include <string.h>
  1475. X#include <errno.h>
  1476. X#include <ctype.h>
  1477. X#include <netdb.h>
  1478. X#include <unistd.h>
  1479. X#include <pwd.h>
  1480. X#ifdef TCAP
  1481. X#    undef HZ        /* Collides with HaZeltine ! */
  1482. X#    include <tcap.h>
  1483. X#endif    /* TCAP */
  1484. X#include "ftpdefs.h"
  1485. X#include "defaults.h"
  1486. X#include "cmds.h"
  1487. X#include "main.h"
  1488. X#include "ftp.h"
  1489. X#include "ftprc.h"
  1490. X#include "copyright.h"
  1491. X
  1492. X/* main.c globals */
  1493. Xint                    slrflag;
  1494. Xint                    fromatty;            /* input is from a terminal */
  1495. Xchar                *altarg;            /* argv[1] with no shell-like preprocessing  */
  1496. Xstruct    servent        *sp;                /* service spec for tcp/ftp */
  1497. Xjmp_buf                toplevel;            /* non-local goto stuff for cmd scanner */
  1498. Xchar                *line;                /* input line buffer */
  1499. Xchar                *stringbase;        /* current scan point in line buffer */
  1500. Xchar                *argbuf;            /* argument storage buffer */
  1501. Xchar                *argbase;            /* current storage point in arg buffer */
  1502. Xint                    margc;                /* count of arguments on input line */
  1503. Xchar                *margv[20];            /* args parsed from input line */
  1504. Xstruct userinfo        uinfo;                /* a copy of their pwent really */
  1505. Xint                    ansi_escapes;        /* for fancy graphics */
  1506. Xint                    ignore_rc;            /* are we supposed to ignore the netrc */
  1507. Xstring                progname;            /* simple filename */
  1508. Xstring                prompt, prompt2;    /* shell prompt string */
  1509. Xstring                anon_password;        /* most likely your email address */
  1510. Xstring                pager;                /* program to browse text files */
  1511. Xstring                version = FTP_VERSION;
  1512. Xlong                eventnumber;        /* number of commands we've done */
  1513. XFILE                *logf = NULL;        /* log user activity */
  1514. Xstring                logfname;            /* name of the logfile */
  1515. Xlong                logsize = 4096L;    /* max log size. 0 == no limit */
  1516. Xint                    percent_flags;        /* "%" in prompt string? */
  1517. Xint                    at_flags;            /* "@" in prompt string? */
  1518. Xstring                 mail_path;            /* your mailbox */
  1519. Xint                    newmail;            /* how many new letters you have */
  1520. Xtime_t                mbox_time;            /* last modified time of mbox */
  1521. X
  1522. Xstatic char            *tcap_normal = "\033[0m";    /* Default ANSI escapes */
  1523. Xstatic char            *tcap_boldface = "\033[1m";
  1524. Xstatic char            *tcap_underline = "\033[4m";
  1525. Xstatic char            *tcap_reverse = "\033[7m";
  1526. X
  1527. X#ifdef TCAP
  1528. Xstatic char            tcbuf[2048];
  1529. X#endif
  1530. X
  1531. X/* main.c externs */
  1532. Xextern int            debug, verbose, mprompt;
  1533. Xextern int            options, cpend, data, connected;
  1534. Xextern int            curtype, macnum;
  1535. Xextern FILE            *cout;
  1536. Xextern struct cmd    cmdtab[];
  1537. Xextern str32        curtypename;
  1538. Xextern char            *macbuf;
  1539. Xextern char            *reply_string;
  1540. Xextern string        hostname, cwd, lcwd;
  1541. Xextern int            optind;
  1542. Xextern char            *optarg;
  1543. X
  1544. Xmain(int argc, char **argv)
  1545. X{
  1546. X    register char        *cp;
  1547. X    int                    top, opt;
  1548. X
  1549. X    if ((cp = rindex(argv[0], '/'))) cp++;
  1550. X    else cp = argv[0];
  1551. X    (void) Strncpy(progname, cp);
  1552. X    
  1553. X    sp = getservbyname("ftp", "tcp");
  1554. X    if (sp == 0) fatal("ftp/tcp: unknown service");
  1555. X
  1556. X    if (init_arrays())            /* Reserve large blocks of memory now */
  1557. X        fatal("could not reserve large amounts of memory.");
  1558. X
  1559. X    /*
  1560. X     * Set up defaults for FTP.
  1561. X     */
  1562. X    mprompt = dMPROMPT;
  1563. X    verbose = dVERBOSE;
  1564. X    debug = dDEBUG;
  1565. X
  1566. X    (void) Strncpy(curtypename, dTYPESTR);
  1567. X    curtype = dTYPE;
  1568. X    (void) Strncpy(prompt, dPROMPT);
  1569. X    
  1570. X    /*    Setup our pager variable, before we run through the rc,
  1571. X        which may change it. */
  1572. X    set_pager(getenv("PAGER"), 0);
  1573. X
  1574. X    ansi_escapes = 0;
  1575. X    if ((cp = getenv("TERM")) != NULL && *cp++ == 'v' && *cp++ == 't')
  1576. X        ansi_escapes = 1;    /* only if a vt100ish terminal */
  1577. X    (void) getuserinfo();
  1578. X    newmail = 0;
  1579. X    (void) time(&mbox_time);
  1580. X    (void) Strncpy(anon_password, uinfo.username);
  1581. X    if (getlocalhostname(uinfo.hostname, sizeof(uinfo.hostname)) == 0) {
  1582. X        (void) Strncat(anon_password, "@");
  1583. X        (void) Strncat(anon_password, uinfo.hostname);
  1584. X    }
  1585. X#if dLOGGING
  1586. X    (void) sprintf(logfname, "%s/%s", uinfo.homedir, dLOGNAME);
  1587. X#else
  1588. X    *logfname = 0;
  1589. X#endif
  1590. X    (void) get_cwd(lcwd, (int) sizeof(lcwd));
  1591. X
  1592. X    ignore_rc = 0;
  1593. X
  1594. X    while ((opt = getopt(argc, argv, "dvinr0hH")) >= 0) {
  1595. X        switch(opt) {
  1596. X            case 'd':
  1597. X                /* options |= SO_DEBUG; done below... */
  1598. X                debug++;
  1599. X                break;
  1600. X            
  1601. X            case 'v':
  1602. X                verbose++;
  1603. X                break;
  1604. X
  1605. X            case 'i':
  1606. X                mprompt = !mprompt;
  1607. X                break;
  1608. X
  1609. X            case 'n':
  1610. X            case 'r':
  1611. X            case '0':
  1612. X                ignore_rc = !ignore_rc;
  1613. X                break;
  1614. X
  1615. X            case 'H':
  1616. X            case 'h':
  1617. X                show_version(0, NULL);
  1618. X                exit (0);
  1619. X
  1620. X            default:
  1621. X                (void) fprintf(stderr,
  1622. X                  "%s: unknown option \"%c\"\n", progname, (int) *cp);
  1623. X        }
  1624. X    }
  1625. X
  1626. X    if (ignore_rc == 0)
  1627. X        (void) thrash_rc();
  1628. X
  1629. X    (void) fix_options();    /* adjust "options" according to "debug"  */
  1630. X    
  1631. X    fromatty = isatty(fileno(stdin));
  1632. X    cpend = 0;  /* no pending replies */
  1633. X    
  1634. X    if (*logfname)
  1635. X        logf = fopen (logfname, "a");
  1636. X
  1637. X    eventnumber = 0L;
  1638. X    cp = argv[optind];
  1639. X    /* The user specified a host on the command line.  Open it now... */
  1640. X    if (argc > 1 && cp) {
  1641. X        if (setjmp(toplevel))
  1642. X            exit(0);
  1643. X        (void) signal(SIGINT, intr);
  1644. X        (void) signal(SIGPIPE, lostpeer);
  1645. X        (void) strcpy(line, "open ");
  1646. X        (void) strcat(line, cp);
  1647. X        makeargv();
  1648. X        (void) setpeer(margc, margv);
  1649. X    }
  1650. X
  1651. X    (void) init_prompt();
  1652. X
  1653. X    eventnumber = 1L;
  1654. X    if (ansi_escapes) {
  1655. X#ifndef TCAP
  1656. X        (void) printf("%s%s Ready.%s\n", 
  1657. X                tcap_boldface, FTP_VERSION, tcap_normal);
  1658. X#else
  1659. X        char vis[BUFSIZ];
  1660. X        (void) sprintf(vis, "%s%s Ready.%s\n", 
  1661. X                tcap_boldface, FTP_VERSION, tcap_normal);
  1662. X        tcap_put(vis);
  1663. X#endif /* !TCAP */
  1664. X    }
  1665. X    else
  1666. X        (void) printf("%s Ready.\n", FTP_VERSION);
  1667. X    top = setjmp(toplevel) == 0;
  1668. X    if (top) {
  1669. X        (void) signal(SIGINT, intr);
  1670. X        (void) signal(SIGPIPE, lostpeer);
  1671. X    }
  1672. X    for (;;) {
  1673. X        (void) cmdscanner(top);
  1674. X        top = 1;
  1675. X    }
  1676. X}    /* main */
  1677. X
  1678. X
  1679. X
  1680. X/*ARGSUSED*/
  1681. Xvoid intr(int unused)
  1682. X{
  1683. X    (void) longjmp(toplevel, 1);
  1684. X}    /* intr */
  1685. X
  1686. X
  1687. X
  1688. Xint getuserinfo(void)
  1689. X{
  1690. X    register char            *cp;
  1691. X    struct passwd            *pw = NULL;
  1692. X    string                    str;
  1693. X    extern char                *home;    /* for glob.c */
  1694. X    
  1695. X    cp = getlogin();
  1696. X    if (cp != NULL)
  1697. X        pw = getpwnam(cp);
  1698. X    if (pw == NULL)
  1699. X        pw = getpwuid(getuid());
  1700. X    if (pw != NULL) {
  1701. X        (void) Strncpy(uinfo.username, pw->pw_name);
  1702. X        (void) Strncpy(uinfo.shell, pw->pw_shell);
  1703. X        (void) Strncpy(uinfo.homedir, pw->pw_dir);
  1704. X        uinfo.uid = pw->pw_uid;
  1705. X        home = uinfo.homedir;    /* for glob.c */
  1706. X        if (((cp = getenv("MAIL")) == NULL) && ((cp = getenv("mail")) == NULL)) {
  1707. X            (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username);
  1708. X            cp = str;
  1709. X        }
  1710. X        /*    mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you),
  1711. X            so try to find the first mail path.  */
  1712. X        while (*cp != '/')
  1713. X            cp++;
  1714. X        (void) Strncpy(mail_path, cp);
  1715. X        if ((cp = index(mail_path, ' ')) != NULL)
  1716. X            *cp = '\0';
  1717. X        return (0);
  1718. X    } else {
  1719. X        (void) Strncpy(uinfo.username, "unknown");
  1720. X        (void) Strncpy(uinfo.shell, "/bin/sh");
  1721. X        (void) Strncpy(uinfo.homedir, ".");    /* current directory */
  1722. X        uinfo.uid = 999;
  1723. X        return (-1);
  1724. X    }
  1725. X}    /* getuserinfo */
  1726. X
  1727. X
  1728. X
  1729. X
  1730. Xint init_arrays(void)
  1731. X{
  1732. X    if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL)
  1733. X        goto barf;
  1734. X    if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  1735. X        goto barf;
  1736. X    if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  1737. X        goto barf;
  1738. X    if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL)
  1739. X        goto barf;
  1740. X    
  1741. X    *macbuf = '\0';
  1742. X    init_transfer_buffer();
  1743. X    return (0);
  1744. Xbarf:
  1745. X    return (-1);
  1746. X}    /* init_arrays */
  1747. X
  1748. X
  1749. X
  1750. Xvoid init_transfer_buffer(void)
  1751. X{
  1752. X    extern char *xferbuf;
  1753. X    extern size_t xferbufsize;
  1754. X    
  1755. X    xferbufsize = MAX_XFER_BUFSIZE;
  1756. X    while (1) {
  1757. X        xferbuf = (char *) malloc (xferbufsize);
  1758. X        if (xferbuf != NULL || xferbufsize < 1024)
  1759. X            break;
  1760. X        xferbufsize >>= 2;
  1761. X    }
  1762. X    
  1763. X    if (xferbuf != NULL) return;
  1764. X    fatal("out of memory for transfer buffer.");
  1765. X}    /* init_transfer_buffer */
  1766. X
  1767. X
  1768. X
  1769. X
  1770. Xvoid init_prompt(void)
  1771. X{
  1772. X    register char *cp;
  1773. X    
  1774. X    percent_flags = at_flags = 0;
  1775. X    for (cp = prompt; *cp; cp++) {
  1776. X        if (*cp == '%') percent_flags = 1;
  1777. X        else if (*cp == '@') at_flags = 1;
  1778. X    }
  1779. X}    /* init_prompt */
  1780. X
  1781. X
  1782. X
  1783. X/*ARGSUSED*/
  1784. Xvoid lostpeer(int unused)
  1785. X{
  1786. X    if (connected) {
  1787. X        close_streams(1);
  1788. X        if (data >= 0) {
  1789. X            (void) shutdown(data, 1+1);
  1790. X            (void) close(data);
  1791. X            data = -1;
  1792. X        }
  1793. X        connected = 0;
  1794. X    }
  1795. X    if (connected) {
  1796. X        close_streams(1);
  1797. X        connected = 0;
  1798. X    }
  1799. X    hostname[0] = cwd[0] = 0;
  1800. X    macnum = 0;
  1801. X}    /* lostpeer */
  1802. X
  1803. X
  1804. X
  1805. X/*
  1806. X * Command parser.
  1807. X */
  1808. Xvoid cmdscanner(int top)
  1809. X{
  1810. X    register struct cmd *c;
  1811. X#ifdef TCAP
  1812. X    char vis[BUFSIZ], *vp;
  1813. X#endif
  1814. X
  1815. X    if (!top)
  1816. X        (void) putchar('\n');
  1817. X    for (;;) {
  1818. X        if (fromatty) {
  1819. X#ifndef TCAP
  1820. X            (void) printf(strprompt());
  1821. X#else
  1822. X            (void) sprintf(vis, "%s", strprompt());
  1823. X            tcap_put(vis);
  1824. X
  1825. X#endif /* !TCAP */
  1826. X            (void) fflush(stdout);
  1827. X        }
  1828. X        if (gets(line) == 0) {
  1829. X            if (feof(stdin) || ferror(stdin))
  1830. X                (void) quit(0, NULL);    /* control-d */
  1831. X            break;
  1832. X        }
  1833. X        if (line[0] == 0)    /* blank line */
  1834. X            break;
  1835. X        eventnumber++;
  1836. X        if (debug > 1)
  1837. X            (void) printf("---> \"%s\"\n", line);
  1838. X        (void) makeargv();
  1839. X        if (margc == 0) {
  1840. X            continue;    /* blank line... */
  1841. X        }
  1842. X        c = getcmd(margv[0]);
  1843. X        if (c == (struct cmd *) -1) {
  1844. X            (void) printf("?Ambiguous command\n");
  1845. X            continue;
  1846. X        }
  1847. X        if (c == 0) {
  1848. X            if (!implicit_cd(margv[0]))
  1849. X                (void) printf("?Invalid command\n");
  1850. X            continue;
  1851. X        }
  1852. X        if (c->c_conn && !connected) {
  1853. X            (void) printf ("Not connected.\n");
  1854. X            continue;
  1855. X        }
  1856. X        (*c->c_handler)(margc, margv);
  1857. X        if (c->c_handler != help)
  1858. X            break;
  1859. X    }
  1860. X    (void) signal(SIGINT, intr);
  1861. X    (void) signal(SIGPIPE, lostpeer);
  1862. X}    /* cmdscanner */
  1863. X
  1864. X
  1865. X
  1866. X
  1867. Xchar *strprompt(void)
  1868. X{
  1869. X    time_t                    tyme;
  1870. X    char                    eventstr[8];
  1871. X    register char            *p, *q;
  1872. X    string                    str;
  1873. X    extern int                percent_flags, at_flags;
  1874. X#ifdef TCAP
  1875. X    static int                 virgin = 0;
  1876. X
  1877. X    if (!virgin++ && ansi_escapes)
  1878. X        termcap_init();
  1879. X#endif /* TCAP */
  1880. X
  1881. X
  1882. X    if (at_flags == 0 && percent_flags == 0)
  1883. X        return (prompt);    /* But don't overwrite it! */
  1884. X
  1885. X    if (at_flags) {
  1886. X        for (p = prompt, q = prompt2, *q = 0; (*p); p++)
  1887. X            if (*p == '@') switch ((toupper(*++p))) {
  1888. X                case '\0':
  1889. X                    --p;
  1890. X                    break;
  1891. X                case 'M':
  1892. X                    if (CheckNewMail() > 0)
  1893. X                        q = Strpcpy(q, "(Mail) ");
  1894. X                    break;
  1895. X                case 'P':    /* reset to no bold, no uline, no inverse, etc. */
  1896. X                    if (ansi_escapes)
  1897. X                        q = Strpcpy(q, tcap_normal);
  1898. X                    break;
  1899. X                case 'B':    /* toggle boldface */
  1900. X                    if (ansi_escapes)
  1901. X                        q = Strpcpy(q, tcap_boldface);
  1902. X                    break;
  1903. X                case 'U':    /* toggle underline */
  1904. X                    if (ansi_escapes)
  1905. X                        q = Strpcpy(q, tcap_underline);
  1906. X                    break;
  1907. X                case 'R':
  1908. X                case 'I':    /* toggle inverse (reverse) video */
  1909. X                    if (ansi_escapes)
  1910. X                        q = Strpcpy(q, tcap_reverse);
  1911. X                    break;
  1912. X                case 'D':    /* insert current directory */
  1913. X                    if (cwd != NULL)
  1914. X                        q = Strpcpy(q, cwd);
  1915. X                    break;
  1916. X                case 'H':    /* insert name of connected host */
  1917. X                    if (hostname != NULL)
  1918. X                        q = Strpcpy(q, hostname);
  1919. X                    break;
  1920. X                case '!':
  1921. X                case 'E':    /* insert event number */
  1922. X                    (void) sprintf(eventstr, "%ld", eventnumber);
  1923. X                    q = Strpcpy(q, eventstr);
  1924. X                    break;
  1925. X                default:
  1926. X                    *q++ = *p;    /* just copy it; unknown switch */
  1927. X            } else
  1928. X                *q++ = *p;
  1929. X        *q = '\0';
  1930. X    } else 
  1931. X        (void) strcpy(prompt2, prompt);
  1932. X    
  1933. X    if (percent_flags) {
  1934. X        /*    only strftime if the user requested it (with a %something),
  1935. X            otherwise don't waste time doing nothing. */
  1936. X        (void) time(&tyme);
  1937. X        (void) Strncpy(str, prompt2);
  1938. X        (void) strftime(prompt2, sizeof(str), str, localtime(&tyme));
  1939. X    }        
  1940. X    return (prompt2);
  1941. X}    /* strprompt */
  1942. X
  1943. X
  1944. X
  1945. Xchar *Strpcpy(char *dst, char *src)
  1946. X{
  1947. X    while (*dst++ = *src++)
  1948. X        ;
  1949. X    return (--dst);    /* return current value of dst, NOT original value! */
  1950. X}    /* Strpcpy */
  1951. X
  1952. X
  1953. X
  1954. X
  1955. Xstruct cmd *getcmd(char *name)
  1956. X{
  1957. X    register char *p, *q;
  1958. X    register struct cmd *c, *found;
  1959. X    register int nmatches, longest;
  1960. X
  1961. X    if (name == NULL)
  1962. X        return (NULL);
  1963. X    longest = 0;
  1964. X    nmatches = 0;
  1965. X    found = 0;
  1966. X    for (c = cmdtab; p = c->c_name; c++) {
  1967. X        for (q = name; *q == *p++; q++)
  1968. X            if (*q == 0)        /* exact match? */
  1969. X                return (c);
  1970. X        if (!*q) {            /* the name was a prefix */
  1971. X            if (q - name > longest) {
  1972. X                longest = q - name;
  1973. X                nmatches = 1;
  1974. X                found = c;
  1975. X            } else if (q - name == longest)
  1976. X                nmatches++;
  1977. X        }
  1978. X    }
  1979. X    if (nmatches > 1)
  1980. X        return ((struct cmd *)-1);
  1981. X    return (found);
  1982. X}    /* getcmd */
  1983. X
  1984. X
  1985. X
  1986. X
  1987. X/*
  1988. X * Slice a string up into argc/argv.
  1989. X */
  1990. X
  1991. Xvoid makeargv(void)
  1992. X{
  1993. X    char **argp;
  1994. X
  1995. X    margc = 0;
  1996. X    argp = margv;
  1997. X    stringbase = line;        /* scan from first of buffer */
  1998. X    argbase = argbuf;        /* store from first of buffer */
  1999. X    slrflag = 0;
  2000. X    while (*argp++ = slurpstring())
  2001. X        margc++;
  2002. X}    /* makeargv */
  2003. X
  2004. X
  2005. X
  2006. X
  2007. X/*
  2008. X * Parse string into argbuf;
  2009. X * implemented with FSM to
  2010. X * handle quoting and strings
  2011. X */
  2012. Xchar *slurpstring(void)
  2013. X{
  2014. X    int got_one = 0;
  2015. X    register char *sb = stringbase;
  2016. X    register char *ap = argbase;
  2017. X    char *tmp = argbase;        /* will return this if token found */
  2018. X
  2019. X    if (*sb == '!' || *sb == '$') {    /* recognize ! as a token for shell */
  2020. X        switch (slrflag) {    /* and $ as token for macro invoke */
  2021. X            case 0:
  2022. X                slrflag++;
  2023. X                stringbase++;
  2024. X                return ((*sb == '!') ? "!" : "$");
  2025. X                /* NOTREACHED */
  2026. X            case 1:
  2027. X                slrflag++;
  2028. X                altarg = stringbase;
  2029. X                break;
  2030. X            default:
  2031. X                break;
  2032. X        }
  2033. X    }
  2034. X
  2035. XS0:
  2036. X    switch (*sb) {
  2037. X
  2038. X    case '\0':
  2039. X        goto OUT;
  2040. X
  2041. X    case ' ':
  2042. X    case '\t':
  2043. X    case '\n':
  2044. X    case '=':
  2045. X        sb++; goto S0;
  2046. X
  2047. X    default:
  2048. X        switch (slrflag) {
  2049. X            case 0:
  2050. X                slrflag++;
  2051. X                break;
  2052. X            case 1:
  2053. X                slrflag++;
  2054. X                altarg = sb;
  2055. X                break;
  2056. X            default:
  2057. X                break;
  2058. X        }
  2059. X        goto S1;
  2060. X    }
  2061. X
  2062. XS1:
  2063. X    switch (*sb) {
  2064. X
  2065. X    case ' ':
  2066. X    case '\t':
  2067. X    case '\n':
  2068. X    case '=':
  2069. X    case '\0':
  2070. X        goto OUT;    /* end of token */
  2071. X
  2072. X    case '\\':
  2073. X        sb++; goto S2;    /* slurp next character */
  2074. X
  2075. X    case '"':
  2076. X        sb++; goto S3;    /* slurp quoted string */
  2077. X
  2078. X    default:
  2079. X        *ap++ = *sb++;    /* add character to token */
  2080. X        got_one = 1;
  2081. X        goto S1;
  2082. X    }
  2083. X
  2084. XS2:
  2085. X    switch (*sb) {
  2086. X
  2087. X    case '\0':
  2088. X        goto OUT;
  2089. X
  2090. X    default:
  2091. X        *ap++ = *sb++;
  2092. X        got_one = 1;
  2093. X        goto S1;
  2094. X    }
  2095. X
  2096. XS3:
  2097. X    switch (*sb) {
  2098. X
  2099. X    case '\0':
  2100. X        goto OUT;
  2101. X
  2102. X    case '"':
  2103. X        sb++; goto S1;
  2104. X
  2105. X    default:
  2106. X        *ap++ = *sb++;
  2107. X        got_one = 1;
  2108. X        goto S3;
  2109. X    }
  2110. X
  2111. XOUT:
  2112. X    if (got_one)
  2113. X        *ap++ = '\0';
  2114. X    argbase = ap;            /* update storage pointer */
  2115. X    stringbase = sb;        /* update scan pointer */
  2116. X    if (got_one) {
  2117. X        return(tmp);
  2118. X    }
  2119. X    switch (slrflag) {
  2120. X        case 0:
  2121. X            slrflag++;
  2122. X            break;
  2123. X        case 1:
  2124. X            slrflag++;
  2125. X            altarg = (char *) 0;
  2126. X            break;
  2127. X        default:
  2128. X            break;
  2129. X    }
  2130. X    return((char *)0);
  2131. X}    /* slurpstring */
  2132. X
  2133. X
  2134. X
  2135. X
  2136. X#define HELPINDENT (sizeof ("directory"))
  2137. X
  2138. X/*
  2139. X * Help command.
  2140. X * Call each command handler with argc == 0 and argv[0] == name.
  2141. X */
  2142. Xhelp(int argc, char **argv)
  2143. X{
  2144. X    register struct cmd        *c;
  2145. X    int                        i, showall = 0;
  2146. X    char                    *arg;
  2147. X
  2148. X    if (argc == 2)
  2149. X        showall = strcmp(argv[1], "all") == 0;
  2150. X    if (argc == 1 || showall)  {
  2151. X        (void) printf("Commands may be abbreviated.  'help all' shows aliases,\ninvisible and unsupported commands.  'help <command>' \ngives a brief description of <command>.  Commands are:\n");
  2152. X        for (c = cmdtab, i=0; c->c_name != NULL; c++) {
  2153. X            if (c->c_hidden && !showall) continue;
  2154. X            (void) printf("%-13s", c->c_name);
  2155. X            if (++i == 6) {
  2156. X                i = 0;
  2157. X                putchar('\n');
  2158. X            }
  2159. X        }
  2160. X        if (i < 6)
  2161. X            putchar('\n');
  2162. X    } else while (--argc > 0) {
  2163. X        arg = *++argv;
  2164. X        c = getcmd(arg);
  2165. X        if (c == (struct cmd *)-1)
  2166. X            (void) printf("?Ambiguous help command %s\n", arg);
  2167. X        else if (c == (struct cmd *)0)
  2168. X            (void) printf("?Invalid help command %s\n", arg);
  2169. X        else
  2170. X            (void) printf("%-*s\t%s\n", HELPINDENT,
  2171. X                c->c_name, c->c_help);
  2172. X    }
  2173. X}    /* help */
  2174. X
  2175. X
  2176. X/*
  2177. X * If the user wants to, s/he can specify the maximum size of the log
  2178. X * file, so it doesn't waste too much disk space.  If the log is too
  2179. X * fat, trim the older lines (at the top) until we're under the limit.
  2180. X */
  2181. Xvoid trim_log(void)
  2182. X{
  2183. X    FILE                *new, *old;
  2184. X    struct stat            st;
  2185. X    long                fat;
  2186. X    string                tmplogname, str;
  2187. X
  2188. X    if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) ||
  2189. X        (old = fopen(logfname, "r")) == NULL)
  2190. X        return;    /* never trim, or no log */
  2191. X    fat = st.st_size - logsize;
  2192. X    if (fat <= 0L) return;    /* log too small yet */
  2193. X    while (fat > 0L) {
  2194. X        if (FGets(str, old) == NULL) return;
  2195. X        fat -= (long) strlen(str);
  2196. X    }
  2197. X    /* skip lines until a new site was opened */
  2198. X    while (1) {
  2199. X        if (FGets(str, old) == NULL) {
  2200. X            (void) fclose(old);
  2201. X            (void) unlink(logfname);
  2202. X            return;    /* nothing left, start anew */
  2203. X        }
  2204. X        if (*str != '\t') break;
  2205. X    }
  2206. X    
  2207. X    /* copy the remaining lines in "old" to "new" */
  2208. X    (void) Strncpy(tmplogname, logfname);
  2209. X    tmplogname[strlen(tmplogname) - 1] = 'T';
  2210. X    if ((new = fopen(tmplogname, "w")) == NULL) {
  2211. X        (void) Perror(tmplogname);
  2212. X        return;
  2213. X    }
  2214. X    (void) fputs(str, new);
  2215. X    while (FGets(str, old))
  2216. X        (void) fputs(str, new);
  2217. X    (void) fclose(old); (void) fclose(new);
  2218. X    if (unlink(logfname) < 0)
  2219. X        Perror(logfname);
  2220. X    if (rename(tmplogname, logfname) < 0)
  2221. X        Perror(tmplogname);
  2222. X}    /* trim_log */
  2223. X
  2224. X
  2225. X
  2226. X
  2227. Xint CheckNewMail(void)
  2228. X{
  2229. X    struct stat stbuf;
  2230. X
  2231. X    if (*mail_path == '\0') return 0;
  2232. X    if (stat(mail_path, &stbuf) < 0) {    /* cant find mail_path so we'll */
  2233. X        *mail_path = '\0';                /* never check it again */
  2234. X        return 0;
  2235. X    }
  2236. X
  2237. X    if (stbuf.st_mtime > mbox_time) {
  2238. X        newmail++;
  2239. X        (void) printf("%s\n", NEWMAILMESSAGE);
  2240. X        (void) time(&mbox_time);                /* only notify once. */
  2241. X    }
  2242. X    
  2243. X    return newmail;
  2244. X}    /* CheckNewMail */
  2245. X
  2246. X
  2247. X#ifdef TCAP
  2248. Xtermcap_init()
  2249. X{
  2250. X    static char area[1024];
  2251. X    static char *s = area;
  2252. X    char *getenv(), *tgetstr();
  2253. X    char *term;
  2254. X
  2255. X    if (tgetent(tcbuf,(term = getenv("TERM"))) != 1)
  2256. X    {
  2257. X        (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term);
  2258. X        return (0);
  2259. X    }
  2260. X
  2261. X    if (!(tcap_normal = tgetstr("se", &s)))
  2262. X        tcap_normal = "";
  2263. X    if (!(tcap_boldface = tgetstr("md", &s)))
  2264. X        tcap_boldface = "";
  2265. X    if (!(tcap_underline = tgetstr("us", &s)))
  2266. X        tcap_underline = "";
  2267. X    if (!(tcap_reverse = tgetstr("so", &s)))
  2268. X        tcap_reverse = "";
  2269. X}
  2270. X
  2271. Xstatic int c_output(c)
  2272. Xint c;
  2273. X{
  2274. X    putchar(c);
  2275. X}
  2276. X
  2277. Xtcap_put(cap)
  2278. Xchar *cap;
  2279. X{
  2280. X    tputs(cap, 0, c_output);
  2281. X}
  2282. X
  2283. X#endif /* TCAP */
  2284. X/* eof main.c */
  2285. END_OF_FILE
  2286.   if test 17355 -ne `wc -c <'main.c'`; then
  2287.     echo shar: \"'main.c'\" unpacked with wrong size!
  2288.   fi
  2289.   # end of 'main.c'
  2290. fi
  2291. echo shar: End of archive 2 \(of 3\).
  2292. cp /dev/null ark2isdone
  2293. MISSING=""
  2294. for I in 1 2 3 ; do
  2295.     if test ! -f ark${I}isdone ; then
  2296.     MISSING="${MISSING} ${I}"
  2297.     fi
  2298. done
  2299. if test "${MISSING}" = "" ; then
  2300.     echo You have unpacked all 3 archives.
  2301.     rm -f ark[1-9]isdone
  2302. else
  2303.     echo You still must unpack the following archives:
  2304.     echo "        " ${MISSING}
  2305. fi
  2306. exit 0
  2307. exit 0 # Just in case...
  2308.