home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / sources / misc / 4284 < prev    next >
Encoding:
Text File  |  1993-01-25  |  54.5 KB  |  2,439 lines

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