home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / ncftp / part02 < prev    next >
Encoding:
Text File  |  1993-11-02  |  60.6 KB  |  2,700 lines

  1. Newsgroups: comp.sources.misc
  2. From: mgleason@cse.unl.edu (Mike Gleason)
  3. Subject: v40i077:  ncftp - Alternative User Interface for FTP, v1.6, Part02/06
  4. Message-ID: <1993Nov2.232324.6305@sparky.sterling.com>
  5. X-Md4-Signature: 6eaee01feea8bc9c183dad2a3ee460f2
  6. Keywords: ncftp
  7. Sender: kent@sparky.sterling.com (Kent Landfield)
  8. Organization: NCEMRSoft
  9. Date: Tue, 2 Nov 1993 23:23:24 GMT
  10. Approved: kent@sparky.sterling.com
  11.  
  12. Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
  13. Posting-number: Volume 40, Issue 77
  14. Archive-name: ncftp/part02
  15. Environment: UNIX, ANSI-C, !SVR4
  16. Supersedes: ncftp: Volume 39, Issue 53-57
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then feed it
  20. # into a shell via "sh file" or similar.  To overwrite existing files,
  21. # type "sh file -c".
  22. # Contents:  ftp.c glob.h util.c
  23. # Wrapped by kent@sparky on Mon Nov  1 16:19:16 1993
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 2 (of 6)."'
  27. if test -f 'ftp.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'ftp.c'\"
  29. else
  30.   echo shar: Extracting \"'ftp.c'\" \(39896 characters\)
  31.   sed "s/^X//" >'ftp.c' <<'END_OF_FILE'
  32. X/* ftp.c */
  33. X
  34. X/*  $RCSfile: ftp.c,v $
  35. X *  $Revision: 14020.12 $
  36. X *  $Date: 93/07/09 11:30:28 $
  37. X */
  38. X
  39. X#include "sys.h"
  40. X
  41. X#include <setjmp.h>
  42. X#include <sys/stat.h>
  43. X#include <sys/file.h>
  44. X
  45. X#ifndef AIX /* AIX-2.2.1 declares utimbuf in unistd.h */
  46. X#ifdef NO_UTIMEH
  47. Xstruct    utimbuf {time_t actime; time_t modtime;};
  48. X#else
  49. X#    include <utime.h>
  50. X#endif
  51. X#endif /*AIX*/
  52. X
  53. X#ifdef SYSLOG
  54. X#    include <syslog.h>
  55. X#endif
  56. X
  57. X/* You may need this for declarations of fd_set, etc. */
  58. X#ifdef SYSSELECTH
  59. X#   include <sys/select.h>
  60. X#else
  61. X#ifdef STRICT_PROTOS
  62. Xextern int select (int, void *, void *, void *, struct timeval *);
  63. X#endif
  64. X#endif
  65. X
  66. X#include <netinet/in.h>
  67. X#include <arpa/ftp.h>
  68. X#include <arpa/inet.h>
  69. X#include <arpa/telnet.h>
  70. X#include <signal.h>
  71. X#include <errno.h>
  72. X#ifdef NET_ERRNO_H
  73. X#       include <net/errno.h>
  74. X#endif
  75. X#include <netdb.h>
  76. X#include <fcntl.h>
  77. X#include <pwd.h>
  78. X#include <ctype.h>
  79. X#include "util.h"
  80. X#include "ftp.h"
  81. X#include "cmds.h"
  82. X#include "main.h"
  83. X#include "ftprc.h"
  84. X#include "getpass.h"
  85. X#include "defaults.h"
  86. X#include "copyright.h"
  87. X
  88. X#ifdef TERM_FTP
  89. Xextern int compress_toggle;
  90. X#endif
  91. X
  92. X/* ftp.c globals */
  93. Xstruct                sockaddr_in hisctladdr;
  94. Xstruct                sockaddr_in data_addr;
  95. Xint                    data = -1;
  96. Xint                    abrtflag = 0;
  97. Xstruct sockaddr_in    myctladdr;
  98. XFILE                *cin = NULL, *cout = NULL;
  99. Xchar                *reply_string = NULL;
  100. Xjmp_buf                sendabort, recvabort;
  101. Xint                    progress_meter = dPROGRESS;
  102. Xint                    cur_progress_meter;
  103. Xint                    sendport = -1;        /* use PORT cmd for each data connection */
  104. Xint                    code;                /* return/reply code for ftp command */
  105. Xstring                indataline;            
  106. Xint                 cpend;                /* flag: if != 0, then pending server reply */
  107. Xchar                *xferbuf;            /* buffer for local and remote I/O */
  108. Xsize_t                xferbufsize;        /* size in bytes, of the transfer buffer. */
  109. Xlong                next_report;
  110. Xlong                bytes;
  111. Xlong                now_sec;
  112. Xlong                file_size;
  113. Xstruct timeval        start, stop;
  114. Xint                    buffer_only = 0;    /* True if reading into redir line
  115. X                                         * buffer only (not echoing to
  116. X                                         * stdout).
  117. X                                         */
  118. X
  119. X/* ftp.c externs */
  120. Xextern FILE                    *logf;
  121. Xextern string                cwd, anon_password;
  122. Xextern Hostname                hostname;
  123. Xextern int                    verbose, debug, macnum, margc;
  124. Xextern int                    curtype, creating, toatty;
  125. Xextern int                    options, activemcmd, paging;
  126. Xextern int                    ansi_escapes, logged_in, macnum;
  127. Xextern char                    *line, *margv[];
  128. Xextern char                    *tcap_normal, *tcap_boldface;
  129. Xextern char                    *tcap_underline, *tcap_reverse;
  130. Xextern struct userinfo        uinfo;
  131. Xextern struct macel            macros[];
  132. Xextern struct lslist        *lshead, *lstail;
  133. Xextern int                    is_ls;
  134. X
  135. X#ifdef GATEWAY
  136. Xextern string                gateway;
  137. Xextern string                gate_login;
  138. X#endif
  139. X
  140. X#ifdef TERM_FTP
  141. X#include "client.h"
  142. Xextern int lcompression, rcompression;
  143. Xint compress_toggle = 0;
  144. X#endif
  145. X
  146. X
  147. X#ifdef TERM_FTP
  148. X
  149. Xint hookup(char *host, unsigned int port)
  150. X{
  151. X      int s;
  152. X
  153. X      lcompression = rcompression = compress_toggle;
  154. X
  155. X      if ((s = connect_server(0)) < 0) {
  156. X          perror("ftp: connect to term server");
  157. X          return -1;
  158. X      }
  159. X      send_command(s, C_PORT, 0, "%s:%d", host, ntohs(port));
  160. X      send_command(s, C_DUMB, 1, 0);
  161. X
  162. X      cin = fdopen(s, "r");
  163. X      cout = fdopen(s, "w");
  164. X      if (cin == NULL || cout == NULL) {
  165. X              fprintf(stderr, "ftp: fdopen failed.\n");
  166. X              if (cin)
  167. X                      fclose(cin);
  168. X              if (cout)
  169. X                      fclose(cout);
  170. X              code = -1;
  171. X              goto bad;
  172. X      }
  173. X      Strncpy(hostname, host);
  174. X      if (verbose)
  175. X              printf("Connected to %s.\n", hostname);
  176. X      if (getreply(0) > 2) {  /* read startup message from server */
  177. X              if (cin)
  178. X                      fclose(cin);
  179. X              if (cout)
  180. X                      fclose(cout);
  181. X              code = -1;
  182. X              goto bad;
  183. X      }
  184. X      return 0;
  185. Xbad:
  186. X      (void) close(s);
  187. X      return code;
  188. X}
  189. X#else
  190. X
  191. Xint hookup(char *host, unsigned int port)
  192. X{
  193. X    register struct hostent *hp = 0;
  194. X    int s, len, hErr = -1;
  195. X    string errstr;
  196. X
  197. X    bzero((char *)&hisctladdr, sizeof (hisctladdr));
  198. X#ifdef BAD_INETADDR
  199. X    hisctladdr.sin_addr = inet_addr(host);
  200. X#else
  201. X     hisctladdr.sin_addr.s_addr = inet_addr(host);
  202. X#endif
  203. X    if (hisctladdr.sin_addr.s_addr != -1) {
  204. X        hisctladdr.sin_family = AF_INET;
  205. X        (void) Strncpy(hostname, host);
  206. X    } else {
  207. X        hp = gethostbyname(host);
  208. X        if (hp == NULL) {
  209. X#ifdef HERROR
  210. X            extern int h_errno;
  211. X            if (h_errno == HOST_NOT_FOUND)
  212. X                (void) printf("%s: unknown host\n", host);
  213. X            else (void) fprintf(stderr, "%s: gethostbyname herror (%d):  ",
  214. X                host, h_errno);
  215. X            herror(NULL);
  216. X#else
  217. X            (void) printf("%s: unknown host\n", host);
  218. X#endif
  219. X            goto done;
  220. X        }
  221. X        hisctladdr.sin_family = hp->h_addrtype;
  222. X        bcopy(hp->h_addr_list[0],
  223. X            (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  224. X        (void) Strncpy(hostname, hp->h_name);
  225. X    }
  226. X    s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  227. X    if (s < 0) {
  228. X        PERROR("hookup", "socket");
  229. X        goto done;
  230. X    }
  231. X    hisctladdr.sin_port = port;
  232. X#ifdef SOCKS
  233. X    while (Rconnect(s, (struct sockaddr *) &hisctladdr, (int) sizeof (hisctladdr)) < 0) {
  234. X#else
  235. X    while (Connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
  236. X#endif
  237. X        if (hp && hp->h_addr_list[1]) {
  238. X            (void) sprintf(errstr, "connect error to address %s",
  239. X                inet_ntoa(hisctladdr.sin_addr));
  240. X            PERROR("hookup", errstr);
  241. X            hp->h_addr_list++;
  242. X            bcopy(hp->h_addr_list[0],
  243. X                 (caddr_t)&hisctladdr.sin_addr, hp->h_length);
  244. X            (void) fprintf(stdout, "Trying %s...\n",
  245. X                inet_ntoa(hisctladdr.sin_addr));
  246. X            (void) close(s);
  247. X            s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  248. X            if (s < 0) {
  249. X                PERROR("hookup", "socket");
  250. X                goto done;
  251. X            }
  252. X            continue;
  253. X        }
  254. X        PERROR("hookup", "connect");
  255. X        switch (errno) {
  256. X            case ENETDOWN:
  257. X            case ENETUNREACH:
  258. X            case ECONNABORTED:
  259. X            case ETIMEDOUT:
  260. X            case ECONNREFUSED:
  261. X            case EHOSTDOWN:
  262. X                hErr = -2;    /* we can re-try later. */
  263. X        }
  264. X        goto bad;
  265. X    }
  266. X    len = sizeof (myctladdr);
  267. X    if (Getsockname(s, (char *)&myctladdr, &len) < 0) {
  268. X        PERROR("hookup", "getsockname");
  269. X        goto bad;
  270. X    }
  271. X    cin = fdopen(s, "r");
  272. X    cout = fdopen(s, "w");
  273. X    if (cin == NULL || cout == NULL) {
  274. X        (void) fprintf(stderr, "ftp: fdopen failed.\n");
  275. X        close_streams(0);
  276. X        goto bad;
  277. X    }
  278. X    if (IS_VVERBOSE)
  279. X        (void) printf("Connected to %s.\n", hostname);
  280. X    if (getreply(0) > 2) {     /* read startup message from server */
  281. X        close_streams(0);
  282. X        if (code == 421)
  283. X            hErr = -2;    /* We can try again later. */
  284. X        goto bad;
  285. X    }
  286. X#ifdef SO_OOBINLINE
  287. X    {
  288. X    int on = 1;
  289. X
  290. X    if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(on))
  291. X        < 0 && debug) {
  292. X            PERROR("hookup", "setsockopt");
  293. X        }
  294. X    }
  295. X#endif /* SO_OOBINLINE */
  296. X
  297. X    hErr = 0;
  298. X    goto done;
  299. X
  300. Xbad:
  301. X    (void) close(s);
  302. Xdone:
  303. X    return (hErr);
  304. X}    /* hookup */
  305. X#endif
  306. X
  307. X
  308. X/* This registers the user's username, password, and account with the remote
  309. X * host which validates it.  If we get on, we also do some other things, like
  310. X * enter a log entry and execute the startup macro.
  311. X */
  312. Xint Login(char *userNamePtr, char *passWordPtr, char *accountPtr, int doInit)
  313. X{
  314. X    string userName;
  315. X    string str;
  316. X    int n;
  317. X    int sentAcct = 0;
  318. X    int userWasPrompted = 0;
  319. X    int result = CMDERR;
  320. X    time_t now;
  321. X
  322. X    if (userNamePtr == NULL) {
  323. X        /* Prompt for a username. */
  324. X        (void) sprintf(str, "Login Name (%s): ", uinfo.username);
  325. X        ++userWasPrompted;
  326. X        if (Gets(str, userName, sizeof(userName)) == NULL)
  327. X            goto done;
  328. X        else if (userName[0]) {
  329. X            /* User didn't just hit return. */
  330. X            userNamePtr = userName;
  331. X        } else {
  332. X            /*
  333. X             * User can hit return if he wants to enter his username
  334. X             * automatically.
  335. X             */
  336. X            if (*uinfo.username != '\0')
  337. X                userNamePtr = uinfo.username;
  338. X            else
  339. X                goto done;
  340. X        }
  341. X    }
  342. X
  343. X    if (passWordPtr == NULL) {
  344. X        if (((strcmp("anonymous", userName) == 0) ||
  345. X             (strcmp("ftp", userName) == 0)) && (*anon_password != '\0'))
  346. X            passWordPtr = anon_password;
  347. X        else {
  348. X            /* Prompt for a password. */
  349. X            ++userWasPrompted;
  350. X            passWordPtr = Getpass("Password:");
  351. X        }
  352. X    }
  353. X
  354. X#ifdef GATEWAY
  355. X    if (*gateway)
  356. X        (void) sprintf(str, "USER %s@%s",
  357. X                (*gate_login ? gate_login : dGATEWAY_LOGIN),
  358. X                hostname);
  359. X    else
  360. X#endif
  361. X        (void) sprintf(str, "USER %s", userNamePtr);
  362. X
  363. X    /* Send the user name. */
  364. X    n = command(str);
  365. X    if (n == CONTINUE) {
  366. X        /* The remote site is requesting us to send the password now. */
  367. X        (void) sprintf(str, "PASS %s", passWordPtr);
  368. X        n = command(str);
  369. X        if (n == CONTINUE) {
  370. X            /* The remote site is requesting us to send the account now. */
  371. X            if (accountPtr == NULL) {
  372. X                /* Prompt for a username. */
  373. X                (void) sprintf(str, "ACCT %s", Getpass("Account:"));
  374. X                ++userWasPrompted;
  375. X            } else {
  376. X                (void) sprintf(str, "ACCT %s", accountPtr);
  377. X            }
  378. X            ++sentAcct;    /* Keep track that we've sent the account already. */
  379. X            n = command(str);
  380. X        }
  381. X    }
  382. X
  383. X    if (n != COMPLETE) {
  384. X        (void) printf("Login failed.\n");
  385. X        goto done;
  386. X    }
  387. X    
  388. X    /* If you specified an account, and the remote-host didn't request it
  389. X     * (maybe it's optional), we will send the account information.
  390. X     */
  391. X    if (!sentAcct && accountPtr != NULL) {
  392. X        (void) sprintf(str, "ACCT %s", accountPtr);
  393. X        (void) command(str);
  394. X    }
  395. X
  396. X    /* See if remote host dropped connection.  Some sites will let you log
  397. X     * in anonymously, only to tell you that they already have too many
  398. X     * anon users, then drop you.  We do a no-op here to see if they've
  399. X     * ditched us.
  400. X     */
  401. X    n = quiet_command("NOOP");
  402. X    if (n == TRANSIENT)
  403. X        goto done;
  404. X
  405. X#ifdef SYSLOG
  406. X    syslog(LOG_INFO, "%s connected to %s as %s.",
  407. X           uinfo.username, hostname, userNamePtr);
  408. X#endif
  409. X
  410. X    /* Save which sites we opened to the user's logfile. */
  411. X    if (logf != NULL) {
  412. X        (void) time(&now);
  413. X        (void) fprintf(logf, "%s opened at %s",
  414. X                       hostname,
  415. X                       ctime(&now));
  416. X    }
  417. X
  418. X    /* Let the user know we are logged in, unless he was prompted for some
  419. X     * information already.
  420. X     */
  421. X    if (!userWasPrompted)
  422. X        if (NOT_VQUIET)
  423. X            (void) printf("Logged into %s.\n", hostname);
  424. X
  425. X    if ((doInit) && (macnum > 0)) {
  426. X        /* Run the startup macro, if any. */
  427. X        /* If macnum is non-zero, the init macro was defined from
  428. X         * ruserpass.  It would be the only macro defined at this
  429. X         * point.
  430. X         */
  431. X        (void) strcpy(line, "$init");
  432. X        makeargv();
  433. X        (void) domacro(margc, margv);
  434. X    }
  435. X
  436. X    _cd(NULL);    /* Init cwd variable. */
  437. X
  438. X    result = NOERR;
  439. X    logged_in = 1;
  440. X
  441. Xdone:
  442. X    return (result);
  443. X}                                       /* Login */
  444. X
  445. X
  446. X
  447. X/*ARGSUSED*/
  448. Xvoid cmdabort SIG_PARAMS
  449. X{
  450. X    (void) printf("\n");
  451. X    (void) fflush(stdout);
  452. X    abrtflag++;
  453. X}    /* cmdabort */
  454. X
  455. X
  456. X
  457. X
  458. Xint CommandWithFlags(char *cmd, int flags)
  459. X{
  460. X    int r;
  461. X    Sig_t oldintr;
  462. X    string str;
  463. X
  464. X    abrtflag = 0;
  465. X    dbprintf("cmd: \"%s\" (length %d)\n", cmd, (int) strlen(cmd));
  466. X    if (cout == NULL) {
  467. X        (void) sprintf(str, "%s: No control connection for command", cmd);
  468. X        PERROR("command", str);
  469. X        return (0);
  470. X    }
  471. X    oldintr = Signal(SIGINT, /* cmdabort */ SIG_IGN);
  472. X#ifndef BROKEN_MEMCPY
  473. X    if (cout != NULL)
  474. X        (void) fprintf(cout, "%s\r\n", cmd);
  475. X#else
  476. X    {
  477. X        /*
  478. X         * The fprintf() above gives me a core-dump in memcpy()...
  479. X         * This does the trick though...
  480. X         */
  481. X
  482. X        char *p = cmd;
  483. X        while (*p)
  484. X            fputc(*p++, cout);
  485. X        fputc('\r', cout);
  486. X        fputc('\n', cout);
  487. X    }
  488. X#endif /* !SCO324 */
  489. X    (void) fflush(cout);
  490. X    cpend = 1;
  491. X    r = (flags == WAIT_FOR_REPLY) ?
  492. X            (getreply(strcmp(cmd, "QUIT") == 0)) : PRELIM;
  493. X    if (abrtflag && oldintr != SIG_IGN && oldintr != NULL)
  494. X        (*oldintr)(0);
  495. X    (void) Signal(SIGINT, oldintr);
  496. X    return(r);
  497. X}    /* CommandWithFlags */
  498. X
  499. X
  500. X
  501. X/* This stub runs 'CommandWithFlags' above, telling it to wait for
  502. X * reply after the command is sent.
  503. X */
  504. Xint command(char *cmd)
  505. X{
  506. X    return (CommandWithFlags(cmd, WAIT_FOR_REPLY));
  507. X}    /* command */
  508. X
  509. X/* This stub runs 'CommandWithFlags' above, telling it to NOT wait for
  510. X * reply after the command is sent.
  511. X */
  512. Xint command_noreply(char *cmd)
  513. X{
  514. X    return(CommandWithFlags(cmd, DONT_WAIT_FOR_REPLY));
  515. X}    /* command */
  516. X
  517. X
  518. X
  519. Xint quiet_command(char *cmd)
  520. X{
  521. X    register int oldverbose, result;
  522. X    
  523. X    oldverbose = verbose;
  524. X    verbose = V_QUIET;
  525. X    result = command(cmd);
  526. X    verbose = oldverbose;
  527. X    return (result);
  528. X}    /* quiet_command */
  529. X
  530. X
  531. X
  532. X
  533. Xint verbose_command(char *cmd)
  534. X{
  535. X    register int oldverbose, result;
  536. X    
  537. X    oldverbose = verbose;
  538. X    verbose = V_VERBOSE;
  539. X    result = command(cmd);
  540. X    verbose = oldverbose;
  541. X    return (result);
  542. X}    /* quiet_command */
  543. X
  544. X
  545. X
  546. X
  547. Xint getreply(int expecteof)
  548. X{
  549. X    register int c, n = 0;
  550. X    int dig;
  551. X    char *cp, *end, *dp;
  552. X    int thiscode, originalcode = 0, continuation = 0;
  553. X    Sig_t oldintr;
  554. X
  555. X    if (cin == NULL)
  556. X        return (-1);
  557. X    /* oldintr = Signal(SIGINT, SIG_IGN); */
  558. X    oldintr = Signal(SIGINT, cmdabort);
  559. X    end = reply_string + RECEIVEDLINELEN - 2;
  560. X    for (;abrtflag==0;) {
  561. X        dig = n = thiscode = code = 0;
  562. X        cp = reply_string;
  563. X        for (;abrtflag==0;) {
  564. X            c = fgetc(cin);
  565. X            if (c == IAC) {     /* handle telnet commands */
  566. X                switch (c = fgetc(cin)) {
  567. X                case WILL:
  568. X                case WONT:
  569. X                    c = fgetc(cin);
  570. X                    (void) fprintf(cout, "%c%c%c",IAC,DONT,c);
  571. X                    (void) fflush(cout);
  572. X                    break;
  573. X                case DO:
  574. X                case DONT:
  575. X                    c = fgetc(cin);
  576. X                    (void) fprintf(cout, "%c%c%c",IAC,WONT,c);
  577. X                    (void) fflush(cout);
  578. X                    break;
  579. X                default:
  580. X                    break;
  581. X                }
  582. X                continue;
  583. X            }
  584. X            dig++;
  585. X            if (c == EOF) {
  586. X                if (expecteof) {
  587. X                    (void) Signal(SIGINT, oldintr);
  588. X                    code = 221;
  589. X                    return (0);
  590. X                }
  591. X                lostpeer(0);
  592. X                if (NOT_VQUIET) {
  593. X                    (void) printf("421 Service not available, remote server has closed connection\n");
  594. X                    (void) fflush(stdout);
  595. X                }
  596. X                code = 421;
  597. X                return(4);
  598. X            }
  599. X            if (cp < end && c != '\r')
  600. X                *cp++ = c;
  601. X
  602. X            if (c == '\n')
  603. X                break;
  604. X            if (dig < 4 && isdigit(c))
  605. X                code = thiscode = code * 10 + (c - '0');
  606. X            else if (dig == 4 && c == '-') {
  607. X                if (continuation)
  608. X                    code = 0;
  609. X                continuation++;
  610. X            }
  611. X            if (n == 0)
  612. X                n = c;
  613. X        }    /* end for(;;) #2 */
  614. X        
  615. X        *cp = '\0';
  616. X        switch (verbose) {
  617. X            case V_QUIET:
  618. X                /* Don't print anything. */
  619. X                break;
  620. X            case V_ERRS:
  621. X                if (n == '5') {
  622. X                    dp = reply_string;
  623. X                    goto stripCode;
  624. X                }
  625. X                break;    
  626. X            case V_IMPLICITCD:
  627. X            case V_TERSE:
  628. X                dp = NULL;
  629. X                if (n == '5' && verbose == V_TERSE)
  630. X                    dp = reply_string;
  631. X                else {
  632. X                    switch (thiscode) {
  633. X                        case 230:
  634. X                        case 214:
  635. X                        case 332:
  636. X                        case 421:    /* For ftp.apple.com, etc. */
  637. X                            dp = reply_string;
  638. X                            break;
  639. X                        case 220:
  640. X                            /*
  641. X                             * Skip the foo FTP server ready line.
  642. X                             */
  643. X                            if (strstr(reply_string, "ready.") == NULL)
  644. X                                dp = reply_string;
  645. X                            break;
  646. X                        case 250:
  647. X                            /*
  648. X                             * Print 250 lines if they aren't
  649. X                             * "250 CWD command successful."
  650. X                             */
  651. X                            if (strncmp(reply_string + 4, "CWD ", (size_t) 4))
  652. X                                dp = reply_string;
  653. X                    }
  654. X                }
  655. X                if (dp == NULL) break;            
  656. XstripCode:
  657. X                /* Try to strip out the code numbers, etc. */
  658. X                if (isdigit(*dp++) && isdigit(*dp++) && isdigit(*dp++)) {
  659. X                    if (*dp == ' ' || *dp == '-') {
  660. X                        dp++;
  661. X                        if (*dp == ' ') dp++;
  662. X                    } else dp = reply_string;            
  663. X                } else {
  664. X                    int spaces;
  665. X                    dp = reply_string;
  666. X                    for (spaces = 0; spaces < 4; ++spaces)
  667. X                        if (dp[spaces] != ' ')
  668. X                            break;
  669. X                    if (spaces == 4)
  670. X                        dp += spaces;
  671. X                }                    
  672. X                goto printLine;
  673. X            case V_VERBOSE:
  674. X                dp = reply_string;
  675. XprintLine:        (void) fputs(dp, stdout);
  676. X        }    /* end switch */
  677. X
  678. X        if (continuation && code != originalcode) {
  679. X            if (originalcode == 0)
  680. X                originalcode = code;
  681. X            continue;
  682. X        }
  683. X        if (n != '1')
  684. X            cpend = 0;
  685. X        (void) Signal(SIGINT,oldintr);
  686. X        if (code == 421 || originalcode == 421)
  687. X            lostpeer(0);
  688. X        if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN && oldintr)
  689. X            (*oldintr)(0);
  690. X        break;
  691. X    }    /* end for(;;) #1 */
  692. X    return (n - '0');
  693. X}    /* getreply */
  694. X
  695. X
  696. X
  697. X
  698. Xstatic int empty(struct fd_set *mask, int sec)
  699. X{
  700. X    struct timeval t;
  701. X
  702. X    t.tv_sec = (long) sec;
  703. X    t.tv_usec = 0;
  704. X
  705. X    return(Select(32, mask, NULL, NULL, &t));
  706. X}    /* empty */
  707. X
  708. X
  709. X
  710. X
  711. Xstatic void tvsub(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
  712. X{
  713. X    tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  714. X    tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  715. X    if (tdiff->tv_usec < 0)
  716. X        tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  717. X}    /* tvsub */
  718. X
  719. X
  720. X/* Variables private to progress_report code. */
  721. Xstatic int barlen;
  722. Xstatic long last_dot;
  723. Xstatic int dots;
  724. X
  725. Xint start_progress(int sending, char *local)
  726. X{
  727. X    long s;
  728. X    str32 spec;
  729. X
  730. X    cur_progress_meter = toatty ? progress_meter : 0;
  731. X    if ((cur_progress_meter > pr_last) || (cur_progress_meter < 0))
  732. X        cur_progress_meter = dPROGRESS;
  733. X    if ((file_size <= 0) && ((cur_progress_meter == pr_percent) || (cur_progress_meter == pr_philbar) || (cur_progress_meter == pr_last)))
  734. X        cur_progress_meter = pr_kbytes;
  735. X    if (!ansi_escapes && (cur_progress_meter == pr_philbar))
  736. X        cur_progress_meter = pr_dots;
  737. X
  738. X    (void) Gettimeofday(&start);
  739. X    now_sec = start.tv_sec;
  740. X
  741. X    switch (cur_progress_meter) {
  742. X        case pr_none:
  743. X            break;
  744. X        case pr_percent:
  745. X            (void) printf("%s:     ", local);
  746. X            goto zz;
  747. X        case pr_kbytes:
  748. X            (void) printf("%s:       ", local);
  749. X            goto zz;
  750. X        case pr_philbar:
  751. X            (void) printf("%s%s file: %s %s\n", 
  752. X                tcap_boldface,
  753. X                sending ? "Sending" : "Receiving",
  754. X                local,
  755. X                tcap_normal
  756. X            );
  757. X            barlen = 63;
  758. X            for (s = file_size; s > 0; s /= 10L) barlen--;
  759. X            (void) sprintf(spec, "      0 %%%ds %%ld bytes.\r", barlen);
  760. X            (void) printf(spec, " ", file_size);
  761. X            goto zz;
  762. X        case pr_dots:
  763. X            last_dot = (file_size / 10) + 1;
  764. X            dots = 0;
  765. X            (void) printf("%s: ", local);
  766. X        zz:
  767. X            (void) fflush(stdout);
  768. X            echo(stdin, 0);
  769. X    }    /* end switch */
  770. X    return (cur_progress_meter);
  771. X}    /* start_progress */
  772. X
  773. X
  774. X
  775. X
  776. Xint progress_report(int finish_up)
  777. X{
  778. X    int size;
  779. X    long perc;
  780. X    str32 spec;
  781. X
  782. X    next_report += xferbufsize;
  783. X    (void) Gettimeofday(&stop);
  784. X    if ((stop.tv_sec > now_sec) || (finish_up && file_size)) {
  785. X        switch (cur_progress_meter) {
  786. X            case pr_none:
  787. X                break;
  788. X            case pr_percent:
  789. X                perc = 100L * bytes / file_size;
  790. X                if (perc > 100L) perc = 100L;
  791. X                (void) printf("\b\b\b\b%3ld%%", perc);
  792. X                (void) fflush(stdout);
  793. X                break;
  794. X            case pr_philbar:
  795. X                size = (int) ((float)barlen * ((float) (bytes > file_size ?
  796. X                    file_size : bytes)/file_size));
  797. X                (void) sprintf(spec, "%%3ld%%%%  0 %%s%%%ds%%s\r", size);
  798. X                (void) printf(
  799. X                    spec,
  800. X                    100L * (bytes > file_size ? file_size : bytes) / file_size,
  801. X                    tcap_reverse,
  802. X                    " ",
  803. X                    tcap_normal
  804. X                );
  805. X                (void) fflush(stdout);
  806. X                break;
  807. X            case pr_kbytes:
  808. X                if ((bytes / 1024) > 0) {
  809. X                    (void) printf("\b\b\b\b\b\b%5ldK", bytes / 1024);
  810. X                    (void) fflush(stdout);
  811. X                }
  812. X                break;
  813. X            case pr_dots:
  814. X                if (bytes > last_dot) {
  815. X                    (void) fputc('.', stdout);
  816. X                    (void) fflush(stdout);
  817. X                    last_dot += (file_size / 10) + 1;
  818. X                    dots++;
  819. X                }    
  820. X        }    /* end switch */
  821. X        now_sec = stop.tv_sec;
  822. X    }    /* end if we updated */
  823. X    return (UserLoggedIn());
  824. X}    /* progress_report */
  825. X
  826. X
  827. X
  828. X
  829. Xvoid end_progress(char *direction, char *local, char *remote)
  830. X{
  831. X    struct timeval            td;
  832. X    float                    s, bs = 0.0;
  833. X    char                    *cp, *bsstr;
  834. X    string                    str;
  835. X
  836. X    if (bytes <= 0)
  837. X        return;
  838. X    (void) progress_report(1);        /* tell progress proc to cleanup. */
  839. X
  840. X    tvsub(&td, &stop, &start);
  841. X    s = td.tv_sec + (td.tv_usec / 1000000.0);
  842. X    if (s != 0.0)
  843. X        bs = bytes / s;
  844. X    if (bs > 1024.0) {
  845. X        bs /= 1024.0;
  846. X        bsstr = "K/s.\n";
  847. X    } else
  848. X        bsstr = "Bytes/s.\n";
  849. X
  850. X    if (NOT_VQUIET) switch(cur_progress_meter) {
  851. X        case pr_none:
  852. X        zz:
  853. X            (void) printf("%s: %ld bytes %s in %.2f seconds, %.2f %s", local, bytes, direction, s, bs, bsstr);
  854. X            break;
  855. X        case pr_kbytes:
  856. X        case pr_percent:
  857. X            (void) printf("%s%ld bytes %s in %.2f seconds, %.2f %s",
  858. X            cur_progress_meter == pr_kbytes ? "\b\b\b\b\b\b" : "\b\b\b\b",
  859. X            bytes, direction, s, bs, bsstr);
  860. X            echo(stdin, 1);
  861. X            break;
  862. X        case pr_philbar:
  863. X            (void) printf("\n");
  864. X            echo(stdin, 1);
  865. X            goto zz;
  866. X        case pr_dots:
  867. X            for (; dots < 10; dots++)
  868. X                (void) fputc('.', stdout);
  869. X            (void) fputc('\n', stdout);
  870. X            echo(stdin, 1);
  871. X            goto zz;
  872. X    }
  873. X    
  874. X    /* Save transfers to the logfile. */
  875. X    /* if a simple path is given, try to log the full path */
  876. X    if (rindex(remote, '/') == NULL && cwd != NULL) {
  877. X        (void) sprintf(str, "%s/%s", cwd, remote);
  878. X         cp = str;
  879. X    } else
  880. X        cp = remote;
  881. X    if (logf != NULL) {
  882. X        (void) fprintf(logf, "\t-> \"%s\" %s, %.2f %s", cp, direction, bs, bsstr);
  883. X    } 
  884. X#ifdef SYSLOG
  885. X    if (direction[0] == 'r')
  886. X        syslog (LOG_INFO, "%s received %s as %s from %s (%ld bytes).",
  887. X            uinfo.username, cp, local, hostname, bytes);
  888. X    else
  889. X        syslog (LOG_INFO, "%s sent %s as %s to %s (%ld bytes).",
  890. X            uinfo.username, local, cp, hostname, bytes);
  891. X#endif
  892. X}   /* end_progress */
  893. X
  894. X
  895. X
  896. Xvoid close_file(FILE **fin, int filetype)
  897. X{
  898. X    if (*fin != NULL) {
  899. X        if (filetype == IS_FILE) {
  900. X            (void) fclose(*fin);
  901. X            *fin = NULL;
  902. X        } else if (filetype == IS_PIPE) {
  903. X            (void) pclose(*fin);
  904. X            *fin = NULL;
  905. X        }
  906. X    }
  907. X}    /* close_file */
  908. X
  909. X
  910. X
  911. X
  912. X/*ARGSUSED*/
  913. Xvoid abortsend SIG_PARAMS
  914. X{
  915. X    activemcmd = 0;
  916. X    abrtflag = 0;
  917. X    (void) fprintf(stderr, "\nSend aborted.\n");
  918. X    echo(stdin, 1);
  919. X    longjmp(sendabort, 1);
  920. X}    /* abortsend */
  921. X
  922. X
  923. X
  924. Xint sendrequest(char *cmd, char *local, char *remote)
  925. X{
  926. X    FILE                    *fin, *dout = NULL;
  927. X    Sig_t                    oldintr, oldintp;
  928. X    string                    str;
  929. X    register int            c, d;
  930. X    struct stat                st;
  931. X    int                        filetype, result = NOERR;
  932. X    int                        do_reports = 0;
  933. X    char                    *mode;
  934. X    register char            *bufp;
  935. X
  936. X    dbprintf("cmd: %s;  rmt: %s;  loc: %s.\n", cmd, remote, local);
  937. X    oldintr = NULL;
  938. X    oldintp = NULL;
  939. X    mode = "w";
  940. X    bytes = file_size = 0L;
  941. X    if (setjmp(sendabort)) {
  942. X        while (cpend) {
  943. X            (void) getreply(0);
  944. X        }
  945. X        if (data >= 0) {
  946. X            (void) close(data);
  947. X            data = -1;
  948. X        }
  949. X        if (oldintr)
  950. X            (void) Signal(SIGINT, oldintr);
  951. X        if (oldintp)
  952. X            (void) Signal(SIGPIPE, oldintp);
  953. X        result = -1;
  954. X        goto xx;
  955. X    }
  956. X    oldintr = Signal(SIGINT, abortsend);
  957. X    file_size = -1;
  958. X    if (strcmp(local, "-") == 0)  {
  959. X        fin = stdin;
  960. X        filetype = IS_STREAM;
  961. X    } else if (*local == '|') {
  962. X        filetype = IS_PIPE;
  963. X        oldintp = Signal(SIGPIPE,SIG_IGN);
  964. X        fin = popen(local + 1, "r");
  965. X        if (fin == NULL) {
  966. X            PERROR("sendrequest", local + 1);
  967. X            (void) Signal(SIGINT, oldintr);
  968. X            (void) Signal(SIGPIPE, oldintp);
  969. X            result = -1;
  970. X            goto xx;
  971. X        }
  972. X    } else {
  973. X        filetype = IS_FILE;
  974. X        fin = fopen(local, "r");
  975. X        if (fin == NULL) {
  976. X            PERROR("sendrequest", local);
  977. X            (void) Signal(SIGINT, oldintr);
  978. X            result = -1;
  979. X            goto xx;
  980. X        }
  981. X        if (fstat(fileno(fin), &st) < 0 ||
  982. X            (st.st_mode&S_IFMT) != S_IFREG) {
  983. X            (void) fprintf(stdout, "%s: not a plain file.\n", local);
  984. X            (void) Signal(SIGINT, oldintr);
  985. X            (void) fclose(fin);
  986. X            result = -1;
  987. X            goto xx;
  988. X        }
  989. X        file_size = st.st_size;
  990. X    }
  991. X    if (initconn()) {
  992. X        (void) Signal(SIGINT, oldintr);
  993. X        if (oldintp)
  994. X            (void) Signal(SIGPIPE, oldintp);
  995. X        result = -1;
  996. X        close_file(&fin, filetype);
  997. X        goto xx;
  998. X    }
  999. X    if (setjmp(sendabort))
  1000. X        goto Abort;
  1001. X
  1002. X#ifdef TRY_NOREPLY
  1003. X    if (remote) {
  1004. X        (void) sprintf(str, "%s %s", cmd, remote);
  1005. X        (void) command_noreply(str);
  1006. X    } else {
  1007. X        (void) command_noreply(cmd);
  1008. X    }
  1009. X
  1010. X    dout = dataconn(mode);
  1011. X    if (dout == NULL)
  1012. X        goto Abort;
  1013. X
  1014. X    if(getreply(0) != PRELIM) {
  1015. X        (void) Signal(SIGINT, oldintr);
  1016. X         if (oldintp)
  1017. X             (void) Signal(SIGPIPE, oldintp);
  1018. X         close_file(&fin, filetype);
  1019. X         return -1;
  1020. X     }
  1021. X#else
  1022. X     if (remote) {
  1023. X         (void) sprintf(str, "%s %s", cmd, remote);
  1024. X         if (command(str) != PRELIM) {
  1025. X             (void) Signal(SIGINT, oldintr);
  1026. X             if (oldintp)
  1027. X                 (void) Signal(SIGPIPE, oldintp);
  1028. X             close_file(&fin, filetype);
  1029. X             goto xx;
  1030. X         }
  1031. X     } else {
  1032. X         if (command(cmd) != PRELIM) {
  1033. X             (void) Signal(SIGINT, oldintr);
  1034. X             if (oldintp)
  1035. X                 (void) Signal(SIGPIPE, oldintp);
  1036. X             close_file(&fin, filetype);
  1037. X             goto xx;
  1038. X         }
  1039. X     }
  1040. X
  1041. X     dout = dataconn(mode);
  1042. X     if (dout == NULL)
  1043. X         goto Abort;
  1044. X#endif
  1045. X
  1046. X    (void) Gettimeofday(&start);
  1047. X    oldintp = Signal(SIGPIPE, SIG_IGN);
  1048. X    if ((do_reports = (filetype == IS_FILE && NOT_VQUIET)) != 0)
  1049. X        do_reports = start_progress(1, local);
  1050. X
  1051. X    switch (curtype) {
  1052. X
  1053. X    case TYPE_I:
  1054. X    case TYPE_L:
  1055. X        errno = d = 0;
  1056. X        while ((c = read(fileno(fin), xferbuf, (int)xferbufsize)) > 0) {
  1057. X            bytes += c;
  1058. X            for (bufp = xferbuf; c > 0; c -= d, bufp += d)
  1059. X                if ((d = write(fileno(dout), bufp, c)) <= 0)
  1060. X                    break;
  1061. X            /* Print progress indicator. */
  1062. X            if (do_reports)
  1063. X                do_reports = progress_report(0);
  1064. X        }
  1065. X        if (c < 0)
  1066. X            PERROR("sendrequest", local);
  1067. X        if (d <= 0) {
  1068. X            if (d == 0 && !creating)
  1069. X                (void) fprintf(stderr, "netout: write returned 0?\n");
  1070. X            else if (errno != EPIPE) 
  1071. X                PERROR("sendrequest", "netout");
  1072. X            bytes = -1;
  1073. X        }
  1074. X        break;
  1075. X
  1076. X    case TYPE_A:
  1077. X        next_report = xferbufsize;
  1078. X        while ((c = getc(fin)) != EOF) {
  1079. X            if (c == '\n') {
  1080. X                if (ferror(dout))
  1081. X                    break;
  1082. X                (void) putc('\r', dout);
  1083. X                bytes++;
  1084. X            }
  1085. X            (void) putc(c, dout);
  1086. X            bytes++;
  1087. X
  1088. X            /* Print progress indicator. */
  1089. X            if (do_reports && bytes > next_report)
  1090. X                do_reports = progress_report(0);
  1091. X        }
  1092. X        if (ferror(fin))
  1093. X            PERROR("sendrequest", local);
  1094. X        if (ferror(dout)) {
  1095. X            if (errno != EPIPE)
  1096. X                PERROR("sendrequest", "netout");
  1097. X            bytes = -1;
  1098. X        }
  1099. X        break;
  1100. X    }
  1101. XDone:
  1102. X    close_file(&fin, filetype);
  1103. X    if (dout)
  1104. X        (void) fclose(dout);
  1105. X    (void) getreply(0);
  1106. X    (void) Signal(SIGINT, oldintr);
  1107. X    if (oldintp)
  1108. X        (void) Signal(SIGPIPE, oldintp);
  1109. X    if (do_reports)
  1110. X        end_progress("sent", local, remote);
  1111. Xxx:
  1112. X    return (result);
  1113. XAbort:
  1114. X    result = -1;
  1115. X    if (!cpend)
  1116. X        goto xx;
  1117. X    if (data >= 0) {
  1118. X        (void) close(data);
  1119. X        data = -1;
  1120. X    }
  1121. X    goto Done;
  1122. X}    /* sendrequest */
  1123. X
  1124. X
  1125. X
  1126. X
  1127. X/*ARGSUSED*/
  1128. Xvoid abortrecv SIG_PARAMS
  1129. X{
  1130. X    activemcmd = 0;
  1131. X    abrtflag = 0;
  1132. X    (void) fprintf(stderr, 
  1133. X#ifdef TRY_ABOR
  1134. X    "(abort)\n");
  1135. X#else
  1136. X    "\nAborting, please wait...");
  1137. X#endif
  1138. X    (void) fflush(stderr);
  1139. X    echo(stdin, 1);
  1140. X    longjmp(recvabort, 1);
  1141. X}    /* abortrecv */
  1142. X
  1143. X
  1144. X
  1145. X
  1146. Xvoid GetLSRemoteDir(char *remote, char *remote_dir)
  1147. X{
  1148. X    char *cp;
  1149. X
  1150. X    /*
  1151. X     * The ls() function can specify a directory to list along with ls flags,
  1152. X     * if it sends the flags first followed by the directory name.
  1153. X     *
  1154. X     * So far, we don't care about the remote directory being listed.  I put
  1155. X     * it now so I won't forget in case I need to do something with it later.
  1156. X     */
  1157. X    remote_dir[0] = 0;
  1158. X    if (remote != NULL) {
  1159. X        cp = index(remote, LS_FLAGS_AND_FILE);
  1160. X        if (cp == NULL)
  1161. X            (void) Strncpy(remote_dir, remote);
  1162. X        else {
  1163. X            *cp++ = ' ';
  1164. X            (void) Strncpy(remote_dir, cp);
  1165. X        }
  1166. X    }
  1167. X}    /* GetLSRemoteDir */
  1168. X
  1169. X
  1170. X
  1171. X
  1172. Xint AdjustLocalFileName(char *local)
  1173. X{
  1174. X    char *dir;
  1175. X
  1176. X    /*
  1177. X     * Make sure we are writing to a valid local path.
  1178. X     * First check the local directory, and see if we can write to it.
  1179. X     */
  1180. X    if (access(local, 2) < 0) {
  1181. X        dir = rindex(local, '/');
  1182. X
  1183. X        if (errno != ENOENT && errno != EACCES) {
  1184. X            /* Report an error if it's one we can't handle. */
  1185. X            PERROR("AdjustLocalFileName", local);
  1186. X            return -1;
  1187. X        }
  1188. X        /* See if we have write permission on this directory. */
  1189. X        if (dir != NULL) {
  1190. X            /* Special case: /filename. */
  1191. X            if (dir != local)
  1192. X                *dir = 0;
  1193. X            if (access(dir == local ? "/" : local, 2) < 0) {
  1194. X                /*
  1195. X                 *    We have a big long pathname, like /a/b/c/d,
  1196. X                 *    but see if we can write into the current
  1197. X                 *    directory and call the file ./d.
  1198. X                 */
  1199. X                if (access(".", 2) < 0) {
  1200. X                    (void) strcpy(local, " and .");
  1201. X                    goto noaccess;
  1202. X                }
  1203. X                (void) strcpy(local, dir + 1);    /* use simple filename. */
  1204. X            } else
  1205. X                *dir = '/';
  1206. X        } else {
  1207. X            /* We have a simple path name (file name only). */
  1208. X            if (access(".", 2) < 0) {
  1209. Xnoaccess:        PERROR("AdjustLocalFileName", local);
  1210. X                return -1;
  1211. X            }
  1212. X        }
  1213. X    }
  1214. X    return (NOERR);
  1215. X}    /* AdjustLocalFileName */
  1216. X    
  1217. X
  1218. X
  1219. Xint SetToAsciiForLS(int is_retr, int currenttype)
  1220. X{
  1221. X    int oldt = -1, oldv;
  1222. X
  1223. X    if (!is_retr) {
  1224. X        if (currenttype != TYPE_A) {
  1225. X            oldt = currenttype;
  1226. X            oldv = verbose;
  1227. X            if (!debug)
  1228. X                verbose = V_QUIET;
  1229. X            (void) setascii(0, NULL);
  1230. X            verbose = oldv;
  1231. X        }
  1232. X    }
  1233. X    return oldt;
  1234. X}    /* SetToAsciiForLS */
  1235. X
  1236. X
  1237. X
  1238. Xint IssueCommand(char *ftpcmd, char *remote)
  1239. X{
  1240. X    string str;
  1241. X    int result = NOERR;
  1242. X
  1243. X    if (remote)
  1244. X        (void) sprintf(str, "%s %s", ftpcmd, remote);
  1245. X    else
  1246. X        (void) Strncpy(str, ftpcmd);
  1247. X    
  1248. X#ifdef TRY_NOREPLY
  1249. X    if (command_noreply(str) != PRELIM)
  1250. X#else
  1251. X    if (command(str) != PRELIM)
  1252. X#endif
  1253. X        result = -1;
  1254. X    return (result);
  1255. X}    /* IssueCommand */
  1256. X
  1257. X
  1258. X
  1259. XFILE *OpenOutputFile(int filetype, char *local, char *mode, Sig_t *oldintp)
  1260. X{
  1261. X    FILE *fout;
  1262. X
  1263. X    if (filetype == IS_STREAM) {
  1264. X        fout = stdout;
  1265. X    } else if (filetype == IS_PIPE) {
  1266. X        /* If it is a pipe, the pipecmd will have a | as the first char. */
  1267. X        ++local;
  1268. X        fout = popen(local, "w");
  1269. X        *oldintp = Signal(SIGPIPE, abortrecv);
  1270. X    } else {
  1271. X        fout = fopen(local, mode);
  1272. X    }
  1273. X    if (fout == NULL)
  1274. X        PERROR("OpenOutputFile", local);
  1275. X    return (fout);
  1276. X}    /* OpenOutputFile */
  1277. X
  1278. X
  1279. X
  1280. Xvoid ReceiveBinary(FILE *din, FILE *fout, int *do_reports, char *localfn)
  1281. X{
  1282. X    int                            c, d, do2;
  1283. X
  1284. X    errno = 0;            /* Clear any old error left around. */
  1285. X    do2 = *do_reports;    /* A slight optimization :-) */
  1286. X    bytes = 0;            /* Init the byte-transfer counter. */
  1287. X
  1288. X    for (;;) {
  1289. X        /* Read a block from the input stream. */
  1290. X        c = read(fileno(din), xferbuf, (int)xferbufsize);
  1291. X
  1292. X        /* If c is zero, then we've read the whole file. */
  1293. X        if (c == 0)
  1294. X            break;
  1295. X
  1296. X        /* Check for errors that may have occurred while reading. */
  1297. X        if (c < 0) {
  1298. X            /* Error occurred while reading. */
  1299. X            if (errno != EPIPE)
  1300. X                PERROR("ReceiveBinary", "netin");
  1301. X            bytes = -1;
  1302. X            break;
  1303. X        }
  1304. X
  1305. X        /* Write out the same block we just read in. */
  1306. X        d = write(fileno(fout), xferbuf, c);
  1307. X
  1308. X        /* Check for write errors. */
  1309. X        if ((d < 0) || (ferror(fout))) {
  1310. X            /* Error occurred while writing. */
  1311. X            PERROR("ReceiveBinary", "outfile");
  1312. X            break;
  1313. X        }
  1314. X        if (d < c) {
  1315. X            (void) fprintf(stderr, "%s: short write\n", localfn);
  1316. X            break;
  1317. X        }
  1318. X
  1319. X        /* Update the byte counter. */
  1320. X        bytes += (long) c;
  1321. X
  1322. X        /* Print progress indicator. */
  1323. X        if (do2 != 0)
  1324. X            do2 = progress_report(0);
  1325. X    }
  1326. X
  1327. X    *do_reports = do2;    /* Update the real do_reports variable. */
  1328. X}    /* ReceiveBinary */
  1329. X
  1330. X
  1331. X
  1332. Xvoid AddRedirLine(char *str2)
  1333. X{
  1334. X    register struct lslist *new;
  1335. X
  1336. X    (void) Strncpy(indataline, str2);
  1337. X    new = (struct lslist *) malloc((size_t) sizeof(struct lslist));
  1338. X    if (new != NULL) {
  1339. X        if ((new->string = NewString(str2)) != NULL) {
  1340. X               new->next = NULL;
  1341. X            if (lshead == NULL)
  1342. X                lshead = lstail = new;
  1343. X            else {
  1344. X                lstail->next = new;
  1345. X                lstail = new;
  1346. X            }
  1347. X        }
  1348. X    }
  1349. X}    /* AddRedirLine */
  1350. X
  1351. X
  1352. X
  1353. Xvoid ReceiveAscii(FILE *din, FILE *fout, int *do_reports, char *localfn, int
  1354. XlineMode)
  1355. X{
  1356. X    string str2;
  1357. X    int nchars = 0, c;
  1358. X    char *linePtr;
  1359. X    int do2 = *do_reports, stripped;
  1360. X
  1361. X    next_report = xferbufsize;
  1362. X    bytes = errno = 0;
  1363. X    if (lineMode) {
  1364. X        while ((linePtr = FGets(str2, din)) != NULL) {
  1365. X            bytes += (long) RemoveTrailingNewline(linePtr, &stripped);
  1366. X            if (is_ls || debug > 0)
  1367. X                AddRedirLine(linePtr);
  1368. X
  1369. X            /* Shutup while getting remote size and mod time. */
  1370. X            if (!buffer_only) {
  1371. X                c = fputs(linePtr, fout);
  1372. X
  1373. X                if (c != EOF) {
  1374. X                    if (stripped > 0)
  1375. X                        c = fputc('\n', fout);
  1376. X                }
  1377. X                if ((c == EOF) || (ferror(fout))) {
  1378. X                    PERROR("ReceiveAscii", "outfile");
  1379. X                    break;
  1380. X                }
  1381. X            }
  1382. X
  1383. X            /* Print progress indicator. */
  1384. X            if (do2 && bytes > next_report)
  1385. X                do2 = progress_report(0);
  1386. X        }
  1387. X    } else while ((c = getc(din)) != EOF) {
  1388. X        linePtr = str2;
  1389. X        while (c == '\r') {
  1390. X            bytes++;
  1391. X            if ((c = getc(din)) != '\n') {
  1392. X                if (ferror(fout))
  1393. X                    goto break2;
  1394. X                /* Shutup while getting remote size and mod time. */
  1395. X                if (!buffer_only)
  1396. X                    (void) putc('\r', fout);
  1397. X                if (c == '\0') {
  1398. X                    bytes++;
  1399. X                    goto contin2;
  1400. X                }
  1401. X                if (c == EOF)
  1402. X                    goto contin2;
  1403. X            }
  1404. X        }
  1405. X        /* Shutup while getting remote size and mod time. */
  1406. X        if (!buffer_only)
  1407. X            (void) putc(c, fout);
  1408. X        bytes++;
  1409. X        
  1410. X        /* Print progress indicator. */
  1411. X        if (do2 && bytes > next_report)
  1412. X            do2 = progress_report(0);
  1413. X
  1414. X        /* No seg violations, please */
  1415. X        if (nchars < sizeof(str2) - 1) {
  1416. X             *linePtr++ = c;  /* build redir string */
  1417. X            nchars++;
  1418. X        }
  1419. X
  1420. X   contin2:
  1421. X        /* Save the input line in the buffer for recall later. */
  1422. X        if (c == '\n' && is_ls) {
  1423. X            *--linePtr = 0;
  1424. X            AddRedirLine(str2);
  1425. X            nchars = 0;
  1426. X        }
  1427. X       
  1428. X    }    /* while ((c = getc(din)) != EOF) */
  1429. Xbreak2:
  1430. X    if (ferror(din)) {
  1431. X        if (errno != EPIPE)
  1432. X            PERROR("ReceiveAscii", "netin");
  1433. X        bytes = -1;
  1434. X    }
  1435. X    if (ferror(fout)) {
  1436. X        if (errno != EPIPE)
  1437. X            PERROR("ReceiveAscii", localfn);
  1438. X    }
  1439. X    *do_reports = do2;
  1440. X}    /* ReceiveAscii */
  1441. X
  1442. X
  1443. X
  1444. Xvoid CloseOutputFile(FILE *f, int filetype, char *name, time_t mt)
  1445. X{
  1446. X    struct utimbuf                ut;
  1447. X
  1448. X    if (f != NULL) {
  1449. X        (void) fflush(f);
  1450. X        if (filetype == IS_FILE) {
  1451. X            (void) fclose(f);
  1452. X            if (mt != (time_t)0) {
  1453. X                ut.actime = ut.modtime = mt;
  1454. X                (void) utime(name, &ut);
  1455. X            }
  1456. X        } else if (filetype == IS_PIPE) {
  1457. X            (void)pclose(f);
  1458. X        }
  1459. X    }
  1460. X}    /* close_file */
  1461. X
  1462. X
  1463. X
  1464. Xvoid ResetOldType(int oldtype)
  1465. X{
  1466. X    int oldv;
  1467. X
  1468. X    if (oldtype >= 0) {
  1469. X        oldv = verbose;
  1470. X        if (!debug)
  1471. X            verbose = V_QUIET;
  1472. X        (void) SetTypeByNumber(oldtype);
  1473. X        verbose = oldv;
  1474. X    }
  1475. X}    /* ResetOldType */
  1476. X
  1477. X
  1478. X
  1479. Xint FileType(char *fname)
  1480. X{
  1481. X    int ft = IS_FILE;
  1482. X
  1483. X    if (strcmp(fname, "-") == 0)
  1484. X        ft = IS_STREAM;
  1485. X    else if (*fname == '|')
  1486. X        ft = IS_PIPE;
  1487. X    return (ft);
  1488. X}    /* FileType */
  1489. X
  1490. X
  1491. X
  1492. X
  1493. Xvoid CloseData(void) {
  1494. X    if (data >= 0) {
  1495. X        (void) close(data);
  1496. X        data = -1;
  1497. X    }
  1498. X}    /* CloseData */
  1499. X
  1500. X
  1501. X
  1502. X
  1503. Xint recvrequest(char *cmd, char *local, char *remote, char *mode)
  1504. X{
  1505. X    FILE                        *fout = NULL, *din = NULL;
  1506. X    Sig_t                        oldintr = NULL, oldintp = NULL;
  1507. X    int                            oldtype = 0, is_retr;
  1508. X    int                            nfnd;
  1509. X    char                        msg;
  1510. X    struct fd_set                mask;
  1511. X    int                            filetype, do_reports = 0;
  1512. X    string                        remote_dir;
  1513. X    time_t                        remfTime = 0;
  1514. X    int                            result = -1;
  1515. X
  1516. X    dbprintf("---> cmd: %s;  rmt: %s;  loc: %s;  mode: %s.\n",
  1517. X        cmd, remote, local, mode);
  1518. X    is_retr = strcmp(cmd, "RETR") == 0;
  1519. X
  1520. X    GetLSRemoteDir(remote, remote_dir);
  1521. X    if ((filetype = FileType(local)) == IS_FILE) {
  1522. X        if (AdjustLocalFileName(local))
  1523. X            goto xx;
  1524. X    }
  1525. X
  1526. X    file_size = -1;
  1527. X    if (filetype == IS_FILE)
  1528. X        file_size = GetDateAndSize(remote, (unsigned long *) &remfTime);
  1529. X
  1530. X    if (initconn())
  1531. X        goto xx;
  1532. X
  1533. X    oldtype = SetToAsciiForLS(is_retr, curtype);
  1534. X
  1535. X     /* Issue the NLST command but don't wait for the reply.  Some FTP 
  1536. X      * servers make the data connection before issuing the 
  1537. X      * "150 Opening ASCII mode data connection for /bin/ls" reply.
  1538. X      */
  1539. X    if (IssueCommand(cmd, remote))
  1540. X        goto xx;
  1541. X    
  1542. X    if ((fout = OpenOutputFile(filetype, local, mode, &oldintp)) == NULL)
  1543. X        goto xx;
  1544. X
  1545. X    if ((din = dataconn("r")) == NULL)
  1546. X        goto Abort;
  1547. X
  1548. X#ifdef TRY_NOREPLY
  1549. X     /* Now get the reply we skipped above. */
  1550. X     (void) getreply(0);
  1551. X#endif
  1552. X
  1553. X    do_reports = NOT_VQUIET && is_retr && filetype == IS_FILE;
  1554. X    if (do_reports)
  1555. X        do_reports = start_progress(0, local);
  1556. X
  1557. X    if (setjmp(recvabort)) {
  1558. X#ifdef TRY_ABOR
  1559. X        goto Abort;
  1560. X#else
  1561. X        /* Just read the rest of the stream without doing anything with
  1562. X         * the results.
  1563. X         */
  1564. X        (void) Signal(SIGINT, SIG_IGN);
  1565. X        (void) Signal(SIGPIPE, SIG_IGN);    /* Don't bug us while aborting. */
  1566. X        while (read(fileno(din), xferbuf, (int)xferbufsize) > 0)
  1567. X            ;
  1568. X        (void) fprintf(stderr, "\rAborted.                   \n");
  1569. X#endif
  1570. X    } else {
  1571. X        oldintr = Signal(SIGINT, abortrecv);
  1572. X
  1573. X        if (curtype == TYPE_A)
  1574. X            ReceiveAscii(din, fout, &do_reports, local, 1);
  1575. X        else
  1576. X            ReceiveBinary(din, fout, &do_reports, local);
  1577. X        result = NOERR;
  1578. X        /* Don't interrupt us now, since we finished successfully. */
  1579. X        (void) Signal(SIGPIPE, SIG_IGN);
  1580. X        (void) Signal(SIGINT, SIG_IGN);
  1581. X    }    
  1582. X    CloseData();
  1583. X    (void) getreply(0);
  1584. X
  1585. X    goto xx;
  1586. X
  1587. XAbort:
  1588. X
  1589. X/* Abort using RFC959 recommended IP,SYNC sequence  */
  1590. X
  1591. X    (void) Signal(SIGPIPE, SIG_IGN);    /* Don't bug us while aborting. */
  1592. X    (void) Signal(SIGINT, SIG_IGN);
  1593. X    if (!cpend || !cout) goto xx;
  1594. X    (void) fprintf(cout,"%c%c",IAC,IP);
  1595. X    (void) fflush(cout); 
  1596. X    msg = IAC;
  1597. X/* send IAC in urgent mode instead of DM because UNIX places oob mark */
  1598. X/* after urgent byte rather than before as now is protocol            */
  1599. X    if (send(fileno(cout),&msg,1,MSG_OOB) != 1)
  1600. X        PERROR("recvrequest", "abort");
  1601. X    (void) fprintf(cout,"%cABOR\r\n",DM);
  1602. X    (void) fflush(cout);
  1603. X    FD_ZERO(&mask);
  1604. X    FD_SET(fileno(cin), &mask);
  1605. X    if (din)
  1606. X        FD_SET(fileno(din), &mask);
  1607. X    if ((nfnd = empty(&mask,10)) <= 0) {
  1608. X        if (nfnd < 0)
  1609. X            PERROR("recvrequest", "abort");
  1610. X        lostpeer(0);
  1611. X    }
  1612. X    if (din && FD_ISSET(fileno(din), &mask)) {
  1613. X        while ((read(fileno(din), xferbuf, xferbufsize)) > 0)
  1614. X            ;
  1615. X    }
  1616. X    if ((getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
  1617. X        CloseData();
  1618. X        (void) getreply(0);
  1619. X    }
  1620. X    (void) getreply(0);
  1621. X    result = -1;
  1622. X    CloseData();
  1623. X
  1624. Xxx:
  1625. X    CloseOutputFile(fout, filetype, local, remfTime);
  1626. X    dbprintf("outfile closed.\n");
  1627. X    if (din)
  1628. X        (void) fclose(din);
  1629. X    if (do_reports)
  1630. X        end_progress("received", local, remote);
  1631. X    if (oldintr)
  1632. X        (void) Signal(SIGINT, oldintr);
  1633. X    if (oldintp)
  1634. X        (void) Signal(SIGPIPE, oldintp);
  1635. X    dbprintf("recvrequest result = %d.\n", result);
  1636. X    ResetOldType(oldtype);
  1637. X    return (result);
  1638. X}    /* recvrequest */
  1639. X
  1640. X
  1641. X
  1642. X
  1643. X/*
  1644. X * Need to start a listen on the data channel
  1645. X * before we send the command, otherwise the
  1646. X * server's connect may fail.
  1647. X */
  1648. X
  1649. X#ifdef TERM_FTP
  1650. X
  1651. X/*
  1652. X * Need to request that the server go into passive mode and
  1653. X * then get the address and port for the term server to connect to.
  1654. X */
  1655. Xint initconn(void)
  1656. X{
  1657. X      int result;
  1658. X      int n[6];
  1659. X      int s;
  1660. X
  1661. X      if (data != -1)
  1662. X              (void) close(data);
  1663. X      result = command("PASV");
  1664. X      if (result == COMPLETE) {
  1665. X              if (sscanf(reply_string, "%*[^(](%d,%d,%d,%d,%d,%d)",
  1666. X                      &n[0], &n[1], &n[2], &n[3], &n[4], &n[5]) != 6) {
  1667. X                      fprintf(stderr, "Cannot parse PASV response: %s\n",
  1668. X                               reply_string);
  1669. X                      return 1;
  1670. X              }
  1671. X              close(data);
  1672. X              lcompression = rcompression = compress_toggle;
  1673. X              if ((s = connect_server(0)) < 0) {
  1674. X                      perror("ftp: connect to term server");
  1675. X                      data = -1;
  1676. X                      return 1;
  1677. X              }
  1678. X              data = s;
  1679. X              send_command(s, C_PORT, 0, "%d.%d.%d.%d:%d",
  1680. X                      n[0], n[1], n[2], n[3], 256*n[4] + n[5]);
  1681. X              send_command(s, C_COMPRESS, 1, "n");
  1682. X              send_command(s, C_DUMB, 1, 0);
  1683. X              return 0;
  1684. X      }
  1685. X      return 1;
  1686. X}
  1687. X
  1688. XFILE *
  1689. Xdataconn(lmode)
  1690. X      char *lmode;
  1691. X{
  1692. X      return (fdopen(data, lmode));
  1693. X}
  1694. X#else /* TERM_FTP */
  1695. X
  1696. X
  1697. Xint initconn(void)
  1698. X{
  1699. X    register char        *p, *a;
  1700. X    int                    result, len, tmpno = 0;
  1701. X    int                    on = 1, rval;
  1702. X    string                str;
  1703. X    Sig_t                oldintr;
  1704. X
  1705. X    oldintr = Signal(SIGINT, SIG_IGN);
  1706. Xnoport:
  1707. X    data_addr = myctladdr;
  1708. X    if (sendport)
  1709. X        data_addr.sin_port = 0;    /* let system pick one */ 
  1710. X    if (data != -1)
  1711. X        (void) close (data);
  1712. X    data = socket(AF_INET, SOCK_STREAM, 0);
  1713. X    if (data < 0) {
  1714. X        PERROR("initconn", "socket");
  1715. X        if (tmpno)
  1716. X            sendport = 1;
  1717. X        rval = 1;  goto Return;
  1718. X    }
  1719. X    if (!sendport)
  1720. X        if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
  1721. X            PERROR("initconn", "setsockopt (reuse address)");
  1722. X            goto bad;
  1723. X        }
  1724. X#ifdef SOCKS
  1725. X    if (Rbind(data, (struct sockaddr *)&data_addr, sizeof (data_addr), hisctladdr.sin_addr.s_addr) < 0) {
  1726. X#else
  1727. X    if (Bind(data, &data_addr, sizeof (data_addr)) < 0) {
  1728. X#endif
  1729. X        PERROR("initconn", "bind");
  1730. X        goto bad;
  1731. X    }
  1732. X#ifdef LINGER    /* If puts don't complete, you could try this. */
  1733. X    {
  1734. X        struct linger li;
  1735. X        li.l_onoff = 1;
  1736. X        li.l_linger = 900;
  1737. X
  1738. X        if (setsockopt(data, SOL_SOCKET, SO_LINGER,
  1739. X            (char *)&li, sizeof(struct linger)) < 0)
  1740. X        {
  1741. X            PERROR("initconn", "setsockopt(SO_LINGER)");
  1742. X        }
  1743. X    }
  1744. X#endif    /* LINGER */
  1745. X    if (options & SO_DEBUG &&
  1746. X        setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  1747. X        PERROR("initconn", "setsockopt (ignored)");
  1748. X    len = sizeof (data_addr);
  1749. X    if (Getsockname(data, (char *)&data_addr, &len) < 0) {
  1750. X        PERROR("initconn", "getsockname");
  1751. X        goto bad;
  1752. X    }
  1753. X#ifdef SOCKS 
  1754. X    if (Rlisten(data, 1) < 0)
  1755. X#else
  1756. X    if (listen(data, 1) < 0)
  1757. X#endif
  1758. X        PERROR("initconn", "listen");
  1759. X    if (sendport) {
  1760. X        a = (char *)&data_addr.sin_addr;
  1761. X        p = (char *)&data_addr.sin_port;
  1762. X#define UC(x) (int) (((int) x) & 0xff)
  1763. X        (void) sprintf(str, "PORT %d,%d,%d,%d,%d,%d",
  1764. X            UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  1765. X        result = command(str);
  1766. X        if (result == ERROR && sendport == -1) {
  1767. X            sendport = 0;
  1768. X            tmpno = 1;
  1769. X            goto noport;
  1770. X        }
  1771. X        rval = (result != COMPLETE);  goto Return;
  1772. X    }
  1773. X    if (tmpno)
  1774. X        sendport = 1;
  1775. X    rval = 0;  goto Return;
  1776. Xbad:
  1777. X    (void) close(data), data = -1;
  1778. X    if (tmpno)
  1779. X        sendport = 1;
  1780. X    rval = 1;
  1781. XReturn:
  1782. X    (void) Signal(SIGINT, oldintr);
  1783. X    return (rval);
  1784. X}    /* initconn */
  1785. X
  1786. X
  1787. X
  1788. X
  1789. XFILE *
  1790. Xdataconn(char *mode)
  1791. X{
  1792. X    struct sockaddr_in from;
  1793. X    FILE *fp;
  1794. X    int s, fromlen = sizeof (from);
  1795. X
  1796. X#ifdef SOCKS
  1797. X    s = Raccept(data, (struct sockaddr *) &from, &fromlen);
  1798. X#else
  1799. X    s = Accept(data, &from, &fromlen);
  1800. X#endif
  1801. X    if (s < 0) {
  1802. X        PERROR("dataconn", "accept");
  1803. X        (void) close(data), data = -1;
  1804. X        fp = NULL;
  1805. X    } else {
  1806. X        (void) close(data);
  1807. X        data = s;
  1808. X        fp = fdopen(data, mode);
  1809. X    }
  1810. X    return (fp);
  1811. X}    /* dataconn */
  1812. X#endif
  1813. X
  1814. X/* eof ftp.c */
  1815. END_OF_FILE
  1816.   if test 39896 -ne `wc -c <'ftp.c'`; then
  1817.     echo shar: \"'ftp.c'\" unpacked with wrong size!
  1818.   fi
  1819.   # end of 'ftp.c'
  1820. fi
  1821. if test -f 'glob.h' -a "${1}" != "-c" ; then 
  1822.   echo shar: Will not clobber existing file \"'glob.h'\"
  1823. else
  1824.   echo shar: Extracting \"'glob.h'\" \(375 characters\)
  1825.   sed "s/^X//" >'glob.h' <<'END_OF_FILE'
  1826. X/* glob.h */
  1827. X
  1828. X#ifndef _glob_h_
  1829. X#define _glob_h_ 1
  1830. X
  1831. X/*  $RCSfile: glob.h,v $
  1832. X *  $Revision: 14020.11 $
  1833. X *  $Date: 93/05/21 05:45:32 $
  1834. X */
  1835. X
  1836. Xchar **glob(char *v);
  1837. Xint letter(char c);
  1838. Xint digit(char c);
  1839. Xint any(int c, char *s);
  1840. Xint blklen(char **av);
  1841. Xchar **blkcpy(char **oav, char **bv);
  1842. Xvoid blkfree(char **av0);
  1843. Xchar **copyblk(char **v);
  1844. Xint gethdir(char *home_dir);
  1845. X
  1846. X#endif
  1847. X
  1848. END_OF_FILE
  1849.   if test 375 -ne `wc -c <'glob.h'`; then
  1850.     echo shar: \"'glob.h'\" unpacked with wrong size!
  1851.   fi
  1852.   # end of 'glob.h'
  1853. fi
  1854. if test -f 'util.c' -a "${1}" != "-c" ; then 
  1855.   echo shar: Will not clobber existing file \"'util.c'\"
  1856. else
  1857.   echo shar: Extracting \"'util.c'\" \(16681 characters\)
  1858.   sed "s/^X//" >'util.c' <<'END_OF_FILE'
  1859. X/* Util.c */
  1860. X
  1861. X/*  $RCSfile: util.c,v $
  1862. X *  $Revision: 14020.13 $
  1863. X *  $Date: 93/05/23 09:38:13 $
  1864. X */
  1865. X
  1866. X#include "sys.h"
  1867. X
  1868. X#include <errno.h>
  1869. X#include <ctype.h>
  1870. X#include <pwd.h>
  1871. X
  1872. X#ifndef NO_VARARGS
  1873. X#    include <stdarg.h>
  1874. X#endif
  1875. X
  1876. X#ifdef READLINE
  1877. X#    include <readline/readline.h>
  1878. X#endif /* READLINE */
  1879. X
  1880. X#ifdef GETLINE
  1881. X#    include <getline.h>
  1882. X#endif
  1883. X
  1884. X#include "util.h"
  1885. X#include "cmds.h"
  1886. X#include "main.h"
  1887. X#include "ftp.h"
  1888. X#include "ftprc.h"
  1889. X#include "defaults.h"
  1890. X#include "copyright.h"
  1891. X
  1892. X/* Util.c globals */
  1893. Xint                    Opterr = 1;            /* if error message should be printed */
  1894. Xint                    Optind = 1;            /* index into parent argv vector */
  1895. Xint                    Optopt;                /* character checked for validity */
  1896. Xchar                *Optarg;            /* argument associated with option */
  1897. Xchar                *Optplace = EMSG;    /* saved position in an arg */
  1898. X
  1899. X/* Util.c externs */
  1900. Xextern int            toatty, fromatty;
  1901. Xextern int            verbose;
  1902. Xextern string        prompt2;
  1903. Xextern char            *line, *margv[];
  1904. Xextern int            margc;
  1905. Xextern int            debug, mprompt, activemcmd;
  1906. Xextern string        progname;
  1907. Xextern struct cmd    cmdtab[];
  1908. Xextern struct userinfo uinfo;
  1909. X
  1910. X#ifndef NO_VARARGS
  1911. Xvoid dbprintf(char *fmt, ...)
  1912. X{
  1913. X    va_list ap;
  1914. X
  1915. X    if (debug) {
  1916. X        (void) fprintf(DB_STREAM, "#DB# ");
  1917. X        va_start(ap, fmt);
  1918. X        (void) vfprintf(DB_STREAM, fmt, ap);
  1919. X        va_end(ap);
  1920. X        (void) fflush(DB_STREAM);
  1921. X    }
  1922. X}    /* dbprintf */
  1923. X#endif
  1924. X
  1925. X
  1926. X
  1927. X
  1928. X/*
  1929. X * Concatenate src on the end of dst.  The resulting string will have at most
  1930. X * n-1 characters, not counting the NUL terminator which is always appended
  1931. X * unlike strncat.  The other big difference is that strncpy uses n as the
  1932. X * max number of characters _appended_, while this routine uses n to limit
  1933. X * the overall length of dst.
  1934. X */
  1935. Xchar *_Strncat(char *dst, char *src, register size_t n)
  1936. X{
  1937. X    register size_t i;
  1938. X    register char *d, *s;
  1939. X
  1940. X    if (n != 0 && ((i = strlen(dst)) < (n - 1))) {
  1941. X        d = dst + i;
  1942. X        s = src;
  1943. X        /* If they specified a maximum of n characters, use n - 1 chars to
  1944. X         * hold the copy, and the last character in the array as a NUL.
  1945. X         * This is the difference between the regular strncpy routine.
  1946. X         * strncpy doesn't guarantee that your new string will have a
  1947. X         * NUL terminator, but this routine does.
  1948. X         */
  1949. X        for (++i; i<n; i++) {
  1950. X            if ((*d++ = *s++) == 0) {
  1951. X                /* Pad with zeros. */
  1952. X                for (; i<n; i++)
  1953. X                    *d++ = 0;
  1954. X                return dst;
  1955. X            }
  1956. X        }
  1957. X        /* If we get here, then we have a full string, with n - 1 characters,
  1958. X         * so now we NUL terminate it and go home.
  1959. X         */
  1960. X        *d = 0;
  1961. X    }
  1962. X    return (dst);
  1963. X}    /* _Strncat */
  1964. X
  1965. X
  1966. X/*
  1967. X * Copy src to dst, truncating or null-padding to always copy n-1 bytes.
  1968. X * Return dst.
  1969. X */
  1970. Xchar *_Strncpy(char *dst, char *src, register size_t n)
  1971. X{
  1972. X    register char *d;
  1973. X    register char *s;
  1974. X    register size_t i;
  1975. X
  1976. X    d = dst;
  1977. X    *d = 0;
  1978. X    if (n != 0) {
  1979. X        s = src;
  1980. X        /* If they specified a maximum of n characters, use n - 1 chars to
  1981. X         * hold the copy, and the last character in the array as a NUL.
  1982. X         * This is the difference between the regular strncpy routine.
  1983. X         * strncpy doesn't guarantee that your new string will have a
  1984. X         * NUL terminator, but this routine does.
  1985. X         */
  1986. X        for (i=1; i<n; i++) {
  1987. X            if ((*d++ = *s++) == 0) {
  1988. X                /* Pad with zeros. */
  1989. X                for (; i<n; i++)
  1990. X                    *d++ = 0;
  1991. X                return dst;
  1992. X            }
  1993. X        }
  1994. X        /* If we get here, then we have a full string, with n - 1 characters,
  1995. X         * so now we NUL terminate it and go home.
  1996. X         */
  1997. X        *d = 0;
  1998. X    }
  1999. X    return (dst);
  2000. X}    /* _Strncpy */
  2001. X
  2002. X
  2003. X
  2004. X
  2005. Xchar *Strpcpy(char *dst, char *src)
  2006. X{
  2007. X    while ((*dst++ = *src++) != '\0')
  2008. X        ;
  2009. X    return (--dst);    /* return current value of dst, NOT original value! */
  2010. X}    /* Strpcpy */
  2011. X
  2012. X
  2013. X
  2014. X/*
  2015. X * malloc's a copy of oldstr.
  2016. X */
  2017. Xchar *NewString(char *oldstr)
  2018. X{
  2019. X    size_t howLong;
  2020. X    char *newstr;
  2021. X
  2022. X    howLong = strlen(oldstr);
  2023. X    if ((newstr = malloc(howLong + 1)) != NULL)
  2024. X        (void) strcpy(newstr, oldstr);
  2025. X    return newstr;
  2026. X}    /* NewString */
  2027. X
  2028. X
  2029. X
  2030. X
  2031. X
  2032. Xvoid Getopt_Reset(void)
  2033. X{
  2034. X    Optind = 1;
  2035. X    Optplace = "";
  2036. X}    /* Getopt_Reset */
  2037. X
  2038. Xstatic char *NextOption(char *ostr)
  2039. X{
  2040. X    if ((Optopt = (int) *Optplace++) == (int) ':')
  2041. X        return 0;
  2042. X    return index(ostr, Optopt);
  2043. X}
  2044. X
  2045. Xint Getopt(int nargc, char **nargv, char *ostr)
  2046. X{
  2047. X    register char *oli;                   /* Option letter list index */
  2048. X
  2049. X    if (!*Optplace) {                       /* update scanning pointer */
  2050. X        if (Optind >= nargc || *(Optplace = nargv[Optind]) != '-')
  2051. X            return (EOF);
  2052. X        if (Optplace[1] && *++Optplace == '-') {    /* found "--" */
  2053. X            ++Optind;
  2054. X            return (EOF);
  2055. X        }
  2056. X    }                                   /* Option letter okay? */
  2057. X    oli = NextOption(ostr);
  2058. X    if (oli == NULL) {
  2059. X        if (!*Optplace)
  2060. X            ++Optind;
  2061. X        if (Opterr) {
  2062. X            (void) fprintf(stderr, "%s%s%c\n", *nargv, ": illegal option -- ", Optopt);
  2063. X            return(BADCH);
  2064. X        }
  2065. X    }
  2066. X    if (*++oli != ':') {               /* don't need argument */
  2067. X        Optarg = NULL;
  2068. X        if (!*Optplace)
  2069. X            ++Optind;
  2070. X    } else {                           /* need an argument */
  2071. X        if (*Optplace)                       /* no white space */
  2072. X            Optarg = Optplace;
  2073. X        else if (nargc <= ++Optind) {  /* no arg */
  2074. X            Optplace = EMSG;
  2075. X            if (Opterr) {
  2076. X                (void) fprintf(stderr, "%s%s%c\n", *nargv, ": option requires an argument -- ", Optopt);
  2077. X                return(BADCH);
  2078. X            }
  2079. X        } else                           /* white space */
  2080. X            Optarg = nargv[Optind];
  2081. X        Optplace = EMSG;
  2082. X        ++Optind;
  2083. X    }
  2084. X    return (Optopt);                   /* dump back Option letter */
  2085. X}                                       /* Getopt */
  2086. X
  2087. X
  2088. X
  2089. X
  2090. X/*
  2091. X * Converts an ls date, in either the "Feb  4  1992" or "Jan 16 13:42"
  2092. X * format to a time_t.
  2093. X */
  2094. Xunsigned long UnLSDate(char *dstr)
  2095. X{
  2096. X#ifdef NO_MKTIME
  2097. X    return (0);
  2098. X#else
  2099. X    char *cp = dstr;
  2100. X    int long mon, day, year, hr, min;
  2101. X    time_t now;
  2102. X    struct tm ut, *t;
  2103. X
  2104. X    switch (*cp++) {
  2105. X        case 'A':
  2106. X            mon = (*cp == 'u') ? 7 : 3;
  2107. X            break;
  2108. X        case 'D':
  2109. X            mon = 11;
  2110. X            break;
  2111. X        case 'F':
  2112. X            mon = 1;
  2113. X            break;
  2114. X        default:                       /* shut up un-init warning */
  2115. X        case 'J':
  2116. X            if (*cp++ == 'u')
  2117. X                mon = (*cp == 'l') ? 6 : 5;
  2118. X            else
  2119. X                mon = 0;
  2120. X            break;
  2121. X        case 'M':
  2122. X            mon = (*++cp == 'r') ? 2 : 4;
  2123. X            break;
  2124. X        case 'N':
  2125. X            mon = 10;
  2126. X            break;
  2127. X        case 'O':
  2128. X            mon = 9;
  2129. X            break;
  2130. X        case 'S':
  2131. X            mon = 8;
  2132. X    }
  2133. X    cp = dstr + 4;
  2134. X    day = 0;
  2135. X    if (*cp != ' ')
  2136. X        day = 10 * (*cp - '0');
  2137. X    cp++;
  2138. X    day += *cp++ - '0';
  2139. X    min = 0;
  2140. X    
  2141. X    (void) time(&now);
  2142. X    t = localtime(&now);
  2143. X
  2144. X    if (*++cp != ' ') {
  2145. X        /* It's a time, XX:YY, not a year. */
  2146. X        cp[2] = ' ';
  2147. X        (void) sscanf(cp, "%ld %ld", &hr, &min);
  2148. X        cp[2] = ':';
  2149. X        year = t->tm_year;
  2150. X        if (mon > t->tm_mon)
  2151. X            --year;
  2152. X    } else {
  2153. X        hr = min = 0;
  2154. X        (void) sscanf(cp, "%ld", &year);
  2155. X        year -= 1900;
  2156. X    }
  2157. X    ut.tm_sec = 1;
  2158. X    ut.tm_min = min;
  2159. X    ut.tm_hour = hr;
  2160. X    ut.tm_mday = day;
  2161. X    ut.tm_mon = mon;
  2162. X    ut.tm_year = year;
  2163. X    ut.tm_isdst = t->tm_isdst;
  2164. X    ut.tm_wday = ut.tm_yday = 0;
  2165. X    return ((unsigned long) mktime(&ut));
  2166. X#endif    /* NO_MKTIME */
  2167. X}    /* UnLSDate */
  2168. X
  2169. X
  2170. X
  2171. X
  2172. Xvoid Perror(
  2173. X#ifdef DB_ERRS
  2174. X            char *fromProc
  2175. X            ,
  2176. X#ifdef __LINE__
  2177. X            int lineNum,
  2178. X#endif
  2179. X#endif
  2180. X            char *msg
  2181. X            )
  2182. X{
  2183. X    extern int errno;
  2184. X
  2185. X    if (NOT_VQUIET) {
  2186. X#ifdef sun
  2187. X    /*
  2188. X     * There is a problem in the SunOS headers when compiling with an ANSI
  2189. X     * compiler.  The problem is that there are macros in the form of
  2190. X     * #define MAC(x) 'x', and this will always be the character x instead
  2191. X     * of whatever parameter was passed to MAC.  If we get these errors, it
  2192. X     * usually means that you are trying to compile with gcc when you haven't
  2193. X     * run the 'fixincludes' script that fixes these macros.  We will ignore
  2194. X     * the error, but it means that the echo() function won't work correctly,
  2195. X     * and you will see your password echo.
  2196. X     */
  2197. X        if (errno == ENOTTY)
  2198. X            return;
  2199. X#endif
  2200. X        (void) fprintf(stderr, "NcFTP");
  2201. X#ifdef DB_ERRS
  2202. X        if (fromProc != NULL)
  2203. X            (void) fprintf(stderr, "/%s", fromProc);
  2204. X#ifdef __LINE__
  2205. X        (void) fprintf(stderr, "/%d", lineNum);
  2206. X#endif
  2207. X#endif
  2208. X        (void) fprintf(stderr, ": ");
  2209. X        if (msg != NULL)
  2210. X            (void) fprintf(stderr, "%s (%d): ", msg, errno);
  2211. X        perror(NULL);
  2212. X    }
  2213. X}    /* Perror */
  2214. X
  2215. X
  2216. X
  2217. X
  2218. Xsize_t RemoveTrailingNewline(char *cp, int *stripped)
  2219. X{
  2220. X    size_t len;
  2221. X    int nBytesStripped = 0;
  2222. X
  2223. X    if (cp != NULL) {
  2224. X        cp += (len = strlen(cp)) - 1;
  2225. X        if (*cp == '\n') {
  2226. X            *cp-- = 0;    /* get rid of the newline. */
  2227. X            nBytesStripped++;
  2228. X        }
  2229. X        if (*cp == '\r') { /* no returns either, please. */
  2230. X            *cp = 0;
  2231. X            nBytesStripped++;
  2232. X        }
  2233. X        if (stripped != NULL)
  2234. X            *stripped = nBytesStripped;
  2235. X        return len;
  2236. X    }
  2237. X    return (size_t)0;
  2238. X}    /* RemoveTrailingNewline */
  2239. X
  2240. X
  2241. X
  2242. X#ifdef GETLINE
  2243. Xextern size_t epromptlen;
  2244. X
  2245. X/*
  2246. X * The Getline library doesn't detect the ANSI escape sequences, so the
  2247. X * library would think that a string is longer than actually appears on
  2248. X * screen.  This function lets Getline work properly.  This function is
  2249. X * intended to fix that problem for the main command prompt only.  If any
  2250. X * other prompts want to use ANSI escapes, a (costly) function would have
  2251. X * to scan the prompt for all escape sequences.
  2252. X */
  2253. X/*ARGSUSED*/
  2254. Xstatic size_t MainPromptLen(char *pr)
  2255. X{
  2256. X    return (int)epromptlen;
  2257. X}
  2258. X#endif
  2259. X
  2260. Xstatic char *StdioGets(char *promptstr, char *sline, size_t size)
  2261. X{
  2262. X    char *cp;
  2263. X
  2264. X    if (fromatty) {
  2265. X        /* It's okay to print a prompt if we are redirecting stdout,
  2266. X         * as long as stdin is still a tty.  Otherwise, don't print
  2267. X         * a prompt at all if stdin is redirected.
  2268. X         */
  2269. X#ifdef CURSES
  2270. X        tcap_put(promptstr);
  2271. X#else
  2272. X        (void) fputs(promptstr, stdout);
  2273. X#endif
  2274. X    }
  2275. X    sline[0] = 0;
  2276. X    cp = fgets(sline, (int)(size - 2), stdin);
  2277. X    (void) RemoveTrailingNewline(sline, NULL);
  2278. X    return cp;
  2279. X}    /* StdioGets */
  2280. X
  2281. X
  2282. X/* Given a prompt string, a destination string, and it's size, return feedback
  2283. X * from the user in the destination string, with any trailing newlines
  2284. X * stripped.  Returns NULL if EOF encountered.
  2285. X */
  2286. Xchar *Gets(char *promptstr, char *sline, size_t size)
  2287. X{
  2288. X    char *cp, ch;
  2289. X    string plines;
  2290. X#ifdef GETLINE
  2291. X    int ismainprompt = (promptstr == prompt2);
  2292. X#endif
  2293. X
  2294. X    if (!fromatty || !toatty) {
  2295. X        /* Don't worry about a cmdline/history editor if you redirected a
  2296. X         * file at me.
  2297. X         */
  2298. X        return (StdioGets(promptstr, sline, size));
  2299. X    }
  2300. X
  2301. X    sline[0] = 0;    /* Clear it, in case of an error later. */
  2302. X
  2303. X    /*
  2304. X     * The prompt string may actually be several lines if the user put a
  2305. X     * newline in it with the @N option.  In this case we only want to print
  2306. X     * the very last line, so the command-line editors won't screw up.  So
  2307. X     * now we print all the lines except the last line.
  2308. X     */
  2309. X    cp = rindex(promptstr, '\n');
  2310. X    if (cp != NULL) {
  2311. X        ch = *++cp;
  2312. X        *cp = 0;
  2313. X        (void) Strncpy(plines, promptstr);
  2314. X        *cp = ch;
  2315. X        promptstr = cp;
  2316. X#ifdef CURSES
  2317. X        tcap_put(plines);
  2318. X#else
  2319. X        (void) fputs(plines, stdout);
  2320. X#endif
  2321. X    }
  2322. X
  2323. X#ifdef READLINE
  2324. X    if ((cp = readline(promptstr)) != NULL) {
  2325. X        (void) _Strncpy(sline, cp, size);
  2326. X        free(cp);
  2327. X        (void) RemoveTrailingNewline(cp = sline, NULL);
  2328. X        if (*cp != 0)    /* Don't add blank lines to history buffer. */
  2329. X            add_history(cp);
  2330. X    }
  2331. X#else    /* READLINE */
  2332. X
  2333. X#ifdef GETLINE
  2334. X    if (toatty) {
  2335. X        if (ismainprompt)
  2336. X            gl_strwidth(MainPromptLen);
  2337. X        if ((cp = getline(promptstr)) != NULL) {
  2338. X            if (*cp == '\0')    /* You hit ^D. */
  2339. X                return NULL;
  2340. X            cp = _Strncpy(sline, cp, size);
  2341. X            (void) RemoveTrailingNewline(cp, NULL);
  2342. X            if (*cp != '\0') {    /* Don't add blank lines to history buffer. */
  2343. X                gl_histadd(cp);
  2344. X            }
  2345. X        }
  2346. X        /* Hope your strlen is declared as returning a size_t. */
  2347. X        gl_strwidth(strlen);
  2348. X    } else {
  2349. X        cp = StdioGets(promptstr, sline, size);
  2350. X    }
  2351. X#else /* !GETLINE */
  2352. X    cp = StdioGets(promptstr, sline, size);
  2353. X#endif /* !GETLINE */
  2354. X#endif /* !READLINE */
  2355. X    return cp;
  2356. X}    /* Gets */
  2357. X
  2358. X
  2359. X
  2360. X
  2361. Xchar **re_makeargv(char *promptstr, int *argc)
  2362. X{
  2363. X    size_t sz;
  2364. X
  2365. X    (void) strcat(line, " ");
  2366. X    sz = strlen(line);
  2367. X    (void) Gets(promptstr, &line[sz], (size_t) (CMDLINELEN - sz)) ;
  2368. X    (void) makeargv();
  2369. X    *argc = margc;
  2370. X    return (margv);
  2371. X}    /* re_makeargv */
  2372. X
  2373. X
  2374. X
  2375. X#ifndef HAS_GETCWD
  2376. Xextern char *getwd(char *);
  2377. X#endif
  2378. X
  2379. Xchar *get_cwd(char *buf, int size)
  2380. X{
  2381. X#ifdef HAS_GETCWD
  2382. X#    ifdef NO_UNISTDH
  2383. X#        ifdef GETCWDSIZET
  2384. X            extern char *getcwd(char *, size_t);
  2385. X#        else
  2386. X            extern char *getcwd(char *, int);
  2387. X#        endif
  2388. X#    endif
  2389. X    return (getcwd(buf, size - 1));
  2390. X#else
  2391. X#ifndef MAXPATHLEN
  2392. X#    define MAXPATHLEN (1024)
  2393. X#endif
  2394. X    static char *cwdbuf = NULL;
  2395. X
  2396. X    if (cwdbuf == NULL) {
  2397. X        cwdbuf = (char *)malloc((size_t) MAXPATHLEN);
  2398. X        if (cwdbuf == NULL)
  2399. X            fatal("out of memory for getwd buffer.");
  2400. X    }
  2401. X    return (_Strncpy(buf, getwd(cwdbuf), (size_t)size));
  2402. X#endif
  2403. X}   /* get_cwd */
  2404. X
  2405. X
  2406. X
  2407. Xint tmp_name(char *str)
  2408. X{
  2409. X    (void) strcpy(str, "/tmp/ncftpXXXXXX");
  2410. X    return (!mktemp(str));
  2411. X}    /* tmp_name */
  2412. X
  2413. X
  2414. X
  2415. X
  2416. Xchar *onoff(int boolf)
  2417. X{
  2418. X    return (boolf ? "on" : "off");
  2419. X}   /* onoff */
  2420. X
  2421. X
  2422. X
  2423. X
  2424. Xint StrToBool(char *s)
  2425. X{
  2426. X    int c;
  2427. X    int result;
  2428. X
  2429. X    c = tolower(*s);
  2430. X    result = 0;
  2431. X    switch (c) {
  2432. X        case 'f':           /* false */
  2433. X        case 'n':            /* no */
  2434. X            break;
  2435. X        case 'o':           /* test for "off" and "on" */
  2436. X            c = tolower(s[1]);
  2437. X            if (c == 'f')
  2438. X                break;
  2439. X            /* fall through */
  2440. X        case 't':           /* true */
  2441. X        case 'y':            /* yes */
  2442. X            result = 1;
  2443. X            break;
  2444. X        default:            /* 1, 0, -1, other number? */
  2445. X            if (atoi(s) != 0)
  2446. X                result = 1;
  2447. X    }
  2448. X    return result;
  2449. X}   /* StrToBool */
  2450. X
  2451. X
  2452. X
  2453. X
  2454. Xint confirm(char *cmd, char *file)
  2455. X{
  2456. X    string str, pr;
  2457. X
  2458. X    if (!fromatty || (activemcmd && !mprompt))
  2459. X        return 1;
  2460. X    (void) sprintf(pr, "%s %s? ", cmd, file);
  2461. X    (void) Gets(pr, str, sizeof(str));
  2462. X    return (*str != 'n' && *str != 'N');
  2463. X}    /* confirm */
  2464. X
  2465. X
  2466. X
  2467. Xvoid fatal(char *msg)
  2468. X{
  2469. X    (void) fprintf(stderr, "%s: %s\n", progname, msg);
  2470. X    close_up_shop();
  2471. X    exit(1);
  2472. X}    /* fatal */
  2473. X
  2474. X
  2475. X
  2476. X
  2477. Xint UserLoggedIn(void)
  2478. X{
  2479. X    static int inited = 0;
  2480. X    static int parent_pid, stderr_was_tty;
  2481. X
  2482. X    if (!inited) {
  2483. X        stderr_was_tty = isatty(2);
  2484. X        parent_pid = getppid();
  2485. X        inited++;
  2486. X    }
  2487. X    if ((stderr_was_tty && !isatty(2)) || (getppid() != parent_pid))
  2488. X        return 0;
  2489. X    return 1;
  2490. X}    /* UserLoggedIn */
  2491. X
  2492. X
  2493. X
  2494. X
  2495. Xstruct cmd *getcmd(char *name)
  2496. X{
  2497. X    struct cmd *c, *found;
  2498. X    int nmatches;
  2499. X    size_t len;
  2500. X    char *p;
  2501. X
  2502. X    found = (struct cmd *)0;
  2503. X    if (name != NULL) {
  2504. X        len = strlen(name);
  2505. X        nmatches = 0;
  2506. X        for (c = cmdtab; (p = c->c_name) != NULL; c++) {
  2507. X            if (strcmp(name, p) == 0) {
  2508. X                /* Exact match. */
  2509. X                found = c;
  2510. X                goto xx;
  2511. X            }
  2512. X            if (c->c_handler == unimpl)
  2513. X                continue;
  2514. X            if (strncmp(name, p, len) == 0) {
  2515. X                if (++nmatches > 1) {
  2516. X                    found = ((struct cmd *) -1);    
  2517. X                    goto xx;
  2518. X                }                
  2519. X                found = c;
  2520. X            } else if (found != NULL)
  2521. X                break;
  2522. X        }
  2523. X    }
  2524. Xxx:
  2525. X    return (found);
  2526. X}    /* getcmd */
  2527. X
  2528. X
  2529. X
  2530. X
  2531. Xvoid cmd_help(struct cmd *c)
  2532. X{
  2533. X    (void) printf("%s: %s.\n",
  2534. X        c->c_name,
  2535. X        c->c_help
  2536. X    );
  2537. X}    /* cmd_help */
  2538. X
  2539. X
  2540. X
  2541. X
  2542. Xvoid cmd_usage(struct cmd *c)
  2543. X{
  2544. X    if (c->c_usage != NULL)
  2545. X        (void) printf("Usage: %s%s\n",
  2546. X            c->c_name,
  2547. X            c->c_usage
  2548. X        );
  2549. X}    /* cmd_usage */
  2550. X
  2551. X
  2552. X
  2553. X
  2554. X/*
  2555. X * A simple function that translates most pathnames with ~, ~user, or
  2556. X * environment variables as the first item.  It won't do paths with env vars
  2557. X * or ~s in the middle of the path, but those are extremely rare.
  2558. X */
  2559. Xchar *LocalPath(char *path)
  2560. X{
  2561. X    longstring orig;
  2562. X    struct passwd *pw;
  2563. X    char *firstent = NULL;
  2564. X    char *cp, *dp, *rest;
  2565. X
  2566. X    (void) Strncpy(orig, path);
  2567. X    if (((cp = index(orig, '/')) != NULL) && (cp != orig)) {
  2568. X        *cp = 0;
  2569. X        rest = cp + 1;
  2570. X        if (orig[0] == '~') {
  2571. X            if (orig[1] == 0) {
  2572. X                firstent = uinfo.homedir;
  2573. X            } else {
  2574. X                pw = getpwnam(orig + 1);
  2575. X                if (pw != NULL)
  2576. X                    firstent = pw->pw_dir;
  2577. X            }
  2578. X        } else if (orig[0] == '$') {
  2579. X            cp = orig + 1;
  2580. X            dp = orig + strlen(orig) - 1;
  2581. X            if ((*cp == '(' && *dp == ')') || (*cp == '{' && *dp == '}')) {
  2582. X                cp++;
  2583. X                *dp = 0;
  2584. X            }
  2585. X            firstent = getenv(cp);
  2586. X        }
  2587. X        if (firstent != NULL)
  2588. X            (void) sprintf(path, "%s/%s", firstent, rest);
  2589. X    }
  2590. X    return (path);
  2591. X}    /* LocalPath */
  2592. X
  2593. X
  2594. X
  2595. X/*
  2596. X * A special case, where invisible dot-files that would normally appear in
  2597. X * your home directory will appear instead as visible files in your $DOTDIR
  2598. X * directory if you have one.
  2599. X */
  2600. X
  2601. X#define LCMP(b) (strncmp(path, (b), (o = sizeof(b) - 1)) == 0)
  2602. X
  2603. Xchar *LocalDotPath(char *path)
  2604. X{
  2605. X    size_t o;
  2606. X    longstring s, s2;
  2607. X    char *cp = getenv("DOTDIR");
  2608. X
  2609. X    if (cp == NULL) {
  2610. X        goto aa;
  2611. X    } else {
  2612. X        if (*cp != '/' && *cp != '~') {
  2613. X            /* then maybe they mean relative to $HOME. */
  2614. X            (void) sprintf(s2, "%s/%s", uinfo.homedir, cp);
  2615. X            cp = s2;
  2616. X        }
  2617. X        if (LCMP("~/.") ||
  2618. X            LCMP("$HOME/.") ||
  2619. X            LCMP("$home/.") ||
  2620. X            LCMP("$(HOME)/.") ||
  2621. X            LCMP("${HOME}/.")
  2622. X        ) {
  2623. X            (void) Strncpy(s, path);
  2624. X            (void) sprintf(path, "%s/%s", cp, s + o);
  2625. X            cp = path;
  2626. X        } else {
  2627. Xaa:            cp = LocalPath(path);
  2628. X        }
  2629. X    }
  2630. X    return cp;
  2631. X}    /* LocalDotPath */
  2632. X
  2633. X#ifdef NO_STRSTR
  2634. X
  2635. X/*
  2636. X *  The Elm Mail System  -  $Revision: 5.1 $   $State: Exp $
  2637. X *
  2638. X *            Copyright (c) 1988-1992 USENET Community Trust
  2639. X *            Copyright (c) 1986,1987 Dave Taylor
  2640. X */
  2641. X
  2642. Xchar *strstr(s1, s2)
  2643. Xchar *s1, *s2;
  2644. X{
  2645. X    int len;
  2646. X    char *ptr;
  2647. X    char *tmpptr;
  2648. X
  2649. X    ptr = NULL;
  2650. X    len = strlen(s2);
  2651. X
  2652. X    if ( len <= strlen(s1)) {
  2653. X        tmpptr = s1;
  2654. X        while ((ptr = index(tmpptr, (int)*s2)) != NULL) {
  2655. X            if (strncmp(ptr, s2, len) == 0) {
  2656. X                break;
  2657. X            }
  2658. X            tmpptr = ptr+1;
  2659. X        }
  2660. X    }
  2661. X    return (ptr);
  2662. X}
  2663. X
  2664. X#endif
  2665. X
  2666. X
  2667. X#ifdef NO_RENAME
  2668. Xint rename(oldname, newname)
  2669. Xconst char *oldname, *newname;
  2670. X{
  2671. X    return (link(oldname, newname) == 0 ? unlink(oldname) : -1);
  2672. X}
  2673. X#endif /*NO_RENAME*/
  2674. X
  2675. X
  2676. X/* eof Util.c */
  2677. END_OF_FILE
  2678.   if test 16681 -ne `wc -c <'util.c'`; then
  2679.     echo shar: \"'util.c'\" unpacked with wrong size!
  2680.   fi
  2681.   # end of 'util.c'
  2682. fi
  2683. echo shar: End of archive 2 \(of 6\).
  2684. cp /dev/null ark2isdone
  2685. MISSING=""
  2686. for I in 1 2 3 4 5 6 ; do
  2687.     if test ! -f ark${I}isdone ; then
  2688.     MISSING="${MISSING} ${I}"
  2689.     fi
  2690. done
  2691. if test "${MISSING}" = "" ; then
  2692.     echo You have unpacked all 6 archives.
  2693.     rm -f ark[1-9]isdone
  2694. else
  2695.     echo You still must unpack the following archives:
  2696.     echo "        " ${MISSING}
  2697. fi
  2698. exit 0
  2699. exit 0 # Just in case...
  2700.