home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / ncftp / part02 < prev    next >
Encoding:
Text File  |  1993-01-24  |  54.3 KB  |  2,433 lines

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