home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckcftp.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  568KB  |  17,655 lines

  1. #define FTP_TIMEOUT
  2.  
  3. /*  C K C F T P  --  FTP Client for C-Kermit  */
  4.  
  5. char *ckftpv = "FTP Client, 9.0.260, 14 Jul 2011";
  6.  
  7. /*
  8.   Authors:
  9.     Jeffrey E Altman <jaltman@secure-endpoints.com>
  10.       Secure Endpoints Inc., New York City
  11.     Frank da Cruz <fdc@columbia.edu>,
  12.       The Kermit Project, Columbia University.
  13.  
  14.   Copyright (C) 2000, 2011,
  15.     Trustees of Columbia University in the City of New York.
  16.     All rights reserved.  See the C-Kermit COPYING.TXT file or the
  17.     copyright text in the ckcmai.c module for disclaimer and permissions.
  18.  
  19.   Portions of conditionally included code Copyright Regents of the
  20.     University of California and The Stanford SRP Authentication Project;
  21.     see notices below.
  22. */
  23.  
  24. /*
  25.   Pending...
  26.  
  27.   . Implement recursive NLST downloads by trying to CD to each filename.
  28.     If it works, it's a directory; if not, it's a file -- GET it.  But
  29.     that won't work with servers like wu-ftpd that don't send directory 
  30.     names.  Recursion with MLSD is done.
  31.  
  32.   . Make syslog entries for session?  Files?
  33.  
  34.   . Messages are printed to stdout and stderr in random fashion.  We should
  35.     either print everything to stdout, or else be systematic about when
  36.     to use stderr.
  37.  
  38.   . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
  39.  
  40.   . Adapt to VMS.  Big job because of its record-oriented file system.
  41.     RMS programmer required.  There are probably also some VMS TCP/IP
  42.     product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS
  43.     transfers using special options for Multinet or other FTP servers
  44.     (find out about STRU VMS).
  45. */
  46.  
  47. /*
  48.   Quick FTP command reference:
  49.  
  50.   RFC765 (1980) and earlier:
  51.     MODE  S(tream), B(lock), C(ompressed)
  52.     STRU  F(ILE), R(ECORD), P(AGE)
  53.     TYPE  A(SCII) <format>,  E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
  54.     PORT  - Port
  55.     PASV  - Passive mode
  56.     USER  - User
  57.     PASS  - Password
  58.     ACCT  - Account
  59.     CWD   - Change Working Directory
  60.     REIN  - Logout but not disconnect
  61.     QUIT  - Bye
  62.     RETR  - Retreive
  63.     STOR  - Store
  64.     APPE  - Append
  65.     ALLO  - Allocate
  66.     REST  - Restart
  67.     RNFR  - Rename from
  68.     RNTO  - Rename to
  69.     ABOR  - Cancel
  70.     DELE  - Delete
  71.     LIST  - Directory
  72.     NLST  - Name List
  73.     SITE  - Site parameters or commands
  74.     STAT  - Status
  75.     HELP  - Help
  76.     NOOP  - Noop
  77.  
  78.   RFC959 (1985):
  79.     CDUP  - Change to Parent Directory
  80.     SMNT  - Structure Mount
  81.     STOU  - Store Unique
  82.     RMD   - Remove Directory
  83.     MKD   - Make Directory
  84.     PWD   - Print Directory
  85.     SYST  - System
  86.  
  87.   RFC2389 (1998):
  88.     FEAT  - List Features (done)
  89.     OPTS  - Send options (done)
  90.  
  91.   RFC2640 (1999):
  92.     LANG  - Specify language for messages (not done)
  93.  
  94.   Pending (Internet Drafts):
  95.     SIZE  - File size (done)
  96.     MDTM  - File modification date-time (done)
  97.     MLST  - File name and attribute list (single file) (not done)
  98.     MLSD  - File list with attributes (multiple files) (done)
  99.     MAIL, MLFL, MSOM - mail delivery (not done)
  100.  
  101.   Alphabetical syntax list:
  102.     ABOR <CRLF>
  103.     ACCT <SP> <account-information> <CRLF>
  104.     ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
  105.     APPE <SP> <pathname> <CRLF>
  106.     CDUP <CRLF>
  107.     CWD  <SP> <pathname> <CRLF>
  108.     DELE <SP> <pathname> <CRLF>
  109.     FEAT <CRLF>
  110.     HELP [<SP> <string>] <CRLF>
  111.     LANG [<SP> <language-tag> ] <CRLF>
  112.     LIST [<SP> <pathname>] <CRLF>
  113.     MKD  <SP> <pathname> <CRLF>
  114.     MLSD [<SP> <pathname>] <CRLF>
  115.     MLST [<SP> <pathname>] <CRLF>
  116.     MODE <SP> <mode-code> <CRLF>
  117.     NLST [<SP> <pathname-or-wildcard>] <CRLF>
  118.     NOOP <CRLF>
  119.     OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
  120.     PASS <SP> <password> <CRLF>
  121.     PASV <CRLF>
  122.     PORT <SP> <host-port> <CRLF>
  123.     PWD  <CRLF>
  124.     QUIT <CRLF>
  125.     REIN <CRLF>
  126.     REST <SP> <marker> <CRLF>
  127.     RETR <SP> <pathname> <CRLF>
  128.     RMD  <SP> <pathname> <CRLF>
  129.     RNFR <SP> <pathname> <CRLF>
  130.     RNTO <SP> <pathname> <CRLF>
  131.     SITE <SP> <string> <CRLF>
  132.     SIZE <SP> <pathname> <CRLF>
  133.     SMNT <SP> <pathname> <CRLF>
  134.     STAT [<SP> <pathname>] <CRLF>
  135.     STOR <SP> <pathname> <CRLF>
  136.     STOU <CRLF>
  137.     STRU <SP> <structure-code> <CRLF>
  138.     SYST <CRLF>
  139.     TYPE <SP> <type-code> <CRLF>
  140.     USER <SP> <username> <CRLF>
  141. */
  142. #include "ckcsym.h"                     /* Standard includes */
  143. #include "ckcdeb.h"
  144.  
  145. #ifndef NOFTP                           /* NOFTP  = no FTP */
  146. #ifndef SYSFTP                          /* SYSFTP = use external ftp client */
  147. #ifdef TCPSOCKET                        /* Build only if TCP/IP included */
  148. #define CKCFTP_C
  149.  
  150. /* Note: much of the following duplicates what was done in ckcdeb.h */
  151. /* but let's not mess with it unless it causes trouble. */
  152.  
  153. #ifdef CK_ANSIC
  154. #include <stdarg.h>
  155. #else /* CK_ANSIC */
  156. #include <varargs.h>
  157. #endif /* CK_ANSIC */
  158. #include <signal.h>
  159. #ifdef OS2
  160. #ifdef OS2ONLY
  161. #include <os2.h>
  162. #endif /* OS2ONLY */
  163. #include "ckowin.h"
  164. #include "ckocon.h"
  165. #endif /* OS2 */
  166. #ifndef ZILOG
  167. #ifdef NT
  168. #include <setjmpex.h>
  169. #ifdef NTSIG
  170. extern int TlsIndex;
  171. #endif /* NTSIG */
  172. #else /* NT */
  173. #include <setjmp.h>
  174. #endif /* NT */
  175. #else
  176. #include <setret.h>
  177. #endif /* ZILOG */
  178. #include "ckcsig.h"
  179. #ifdef VMS
  180. /* 2010-03-09 SMS.  VAX C needs help to find "sys".  It's easier not to try. */
  181. #include <stat.h>
  182. #else /* def VMS */
  183. #include <sys/stat.h>
  184. #endif /* def VMS [else] */
  185. #include <ctype.h>
  186.  
  187. #ifndef HPUXPRE65
  188. #include <errno.h>            /* Error number symbols */
  189. #else
  190. #ifndef ERRNO_INCLUDED
  191. #include <errno.h>            /* Error number symbols */
  192. #endif    /* ERRNO_INCLUDED */
  193. #endif    /* HPUXPRE65 */
  194.  
  195. #ifndef NOTIMEH
  196. #include <time.h>
  197. #endif /* NOTIMEH */
  198. #ifndef EPIPE
  199. #define EPIPE 32                        /* Broken pipe error */
  200. #endif /* EPIPE */
  201.  
  202. /* Kermit includes */
  203.  
  204. #include "ckcasc.h"
  205. #include "ckcker.h"
  206. #include "ckucmd.h"
  207. #include "ckuusr.h"
  208. #include "ckcnet.h"                     /* Includes ckctel.h */
  209. #include "ckctel.h"                     /* (then why include it again?) */
  210. #include "ckcxla.h"
  211.  
  212. #ifdef CK_SSL
  213. #include "ckuath.h"            /* SMS 2007/02/15 */
  214. #endif /* def CK_SSL */
  215.  
  216. /*
  217.   How to get the struct timeval definition so we can call select().  The
  218.   xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
  219.   targets.  The problem is: maybe we have already included some header file
  220.   that defined struct timeval, and maybe we didn't.  If we did, we don't want
  221.   to include another header file that defines it again or the compilation will
  222.   fail.  If we didn't, we have to include the header file where it's defined.
  223.   But in some cases even that won't work because of strict POSIX constraints
  224.   or somesuch, or because this introduces other conflicts (e.g. struct tm
  225.   multiply defined), in which case we have to define it ourselves, but this
  226.   can work only if we didn't already encounter a definition.
  227. */
  228. #ifndef DCLTIMEVAL
  229. #ifdef SV68R3V6
  230. #define DCLTIMEVAL
  231. #else
  232. #ifdef SCO234
  233. #define DCLTIMEVAL
  234. #endif /* SCO234 */
  235. #endif /* SV68R3V6 */
  236. #endif /* DCLTIMEVAL */
  237.  
  238. #ifdef DCLTIMEVAL
  239. /* Also maybe in some places the elements must be unsigned... */
  240. struct timeval {
  241.     long tv_sec;
  242.     long tv_usec;
  243. };
  244. #ifdef COMMENT
  245. /* Currently we don't use this... */
  246. struct timezone {
  247.     int tz_minuteswest;
  248.     int tz_dsttime;
  249. };
  250. #endif /* COMMENT */
  251. #else  /* !DCLTIMEVAL */
  252. #ifndef NOSYSTIMEH
  253. #ifdef SYSTIMEH
  254. #include <sys/time.h>
  255. #endif /* SYSTIMEH */
  256. #endif /* NOSYSTIMEH */
  257. #ifndef NOSYSTIMEBH
  258. #ifdef SYSTIMEBH
  259. #include <sys/timeb.h>
  260. #endif /* SYSTIMEBH */
  261. #endif /* NOSYSTIMEBH */
  262. #endif /* DCLTIMEVAL */
  263.  
  264. /* 2010-03-09 SMS.  VAX C needs help to find "sys".  It's easier not to try. */
  265. #ifdef VMS
  266. #include <types.h>
  267. #else /* def VMS */
  268. #include <sys/types.h>
  269. #endif /* def VMS [else] */
  270. #include <stdio.h>
  271. #include <string.h>
  272. #ifdef HAVE_STDLIB_H
  273. #include <stdlib.h>
  274. #endif /* HAVE_STDLIB_H */
  275.  
  276. #ifndef NOSETTIME
  277. #ifdef COMMENT
  278. /* This section moved to ckcdeb.h */
  279. #ifdef POSIX
  280. #define UTIMEH
  281. #else
  282. #ifdef HPUX9
  283. #define UTIMEH
  284. #else
  285. #ifdef OS2
  286. #define SYSUTIMEH
  287. #endif /* OS2 */
  288. #endif /* HPUX9 */
  289. #endif /* POSIX */
  290. #endif /* COMMENT */
  291.  
  292. #ifdef VMS                /* SMS 2007/02/15 */
  293. #include "ckvrtl.h"            /* for utime() */
  294. #else  /* def VMS */
  295. #ifdef SYSUTIMEH
  296. #include <sys/utime.h>
  297. #else
  298. #ifdef UTIMEH
  299. #include <utime.h>
  300. #define SYSUTIMEH
  301. #endif /* UTIMEH */
  302. #endif /* SYSUTIMEH */
  303. #endif /* def VMS */
  304. #endif /* NOSETTIME */
  305.  
  306. #ifndef SCO_OSR504
  307. #ifdef SELECT_H
  308. #include <sys/select.h>
  309. #endif /* SELECT_H */
  310. #endif /* SCO_OSR504 */
  311.  
  312. #ifndef INADDR_NONE            /* 2010-03-29 */
  313. #define INADDR_NONE -1
  314. #endif    /* INADDR_NONE */
  315.  
  316. /* select() dialects... */
  317.  
  318. #ifdef UNIX
  319. #define BSDSELECT                       /* BSD select() syntax/semantics */
  320. #ifndef FD_SETSIZE
  321. #define FD_SETSIZE 128
  322. #endif    /* FD_SETSIZE */
  323. #ifdef HPUX6                /* For HP-UX 6.5 circa 1989 */
  324. typedef long fd_mask;
  325. #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
  326. #ifndef howmany
  327. #define howmany(x, y)   (((x)+((y)-1))/(y))
  328. #endif    /* howmany */
  329. #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  330. #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  331. #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  332. #define FD_COPY(f, t)   bcopy(f, t, sizeof(*(f)))
  333. #define FD_ZERO(p)      bzero(p, sizeof(*(p)))
  334. #endif    /* HPUX6 */
  335.  
  336. #else
  337. #ifdef OS2                              /* OS/2 or Win32 */
  338. #ifdef NT
  339. #define BSDSELECT
  340. #else /* NT */
  341. #define IBMSELECT
  342. #endif /* NT */
  343. #endif /* OS2 */
  344. #endif /* UNIX */
  345.  
  346. #ifdef VMS
  347. #define BSDSELECT            /* SMS 2007/02/15 */
  348. #endif /* def VMS */
  349.  
  350. /* Other select() peculiarities */
  351.  
  352. #ifdef HPUX
  353. #ifndef HPUX10                          /* HP-UX 9.xx and earlier */
  354. #ifndef HPUX1100
  355. /* The three interior args to select() are (int *) rather than (fd_set *) */
  356. #ifndef INTSELECT
  357. #define INTSELECT
  358. #endif /* INTSELECT */
  359. #endif /* HPUX1100 */
  360. #endif /* HPUX10 */
  361. #endif /* HPUX */
  362.  
  363. #ifdef CK_SOCKS                         /* SOCKS Internet relay package */
  364. #ifdef CK_SOCKS5                        /* SOCKS 5 */
  365. #define accept  SOCKSaccept
  366. #define bind    SOCKSbind
  367. #define connect SOCKSconnect
  368. #define getsockname SOCKSgetsockname
  369. #define listen SOCKSlisten
  370. #else  /* Not SOCKS 5 */
  371. #define accept  Raccept
  372. #define bind    Rbind
  373. #define connect Rconnect
  374. #define getsockname Rgetsockname
  375. #define listen Rlisten
  376. #endif /* CK_SOCKS5 */
  377. #endif /* CK_SOCKS */
  378.  
  379. #ifndef NOHTTP
  380. extern char * tcp_http_proxy;           /* Name[:port] of http proxy server */
  381. extern int    tcp_http_proxy_errno;
  382. extern char * tcp_http_proxy_user;
  383. extern char * tcp_http_proxy_pwd;
  384. extern char * tcp_http_proxy_agent;
  385. #define HTTPCPYL 1024
  386. static char proxyhost[HTTPCPYL];
  387. #endif /* NOHTTP */
  388. int ssl_ftp_proxy = 0;                  /* FTP over SSL/TLS Proxy Server */
  389.  
  390. /* Feature selection */
  391.  
  392. #ifndef USE_SHUTDOWN
  393. /*
  394.   We don't use shutdown() because (a) we always call it just before close()
  395.   so it's redundant and unnecessary, and (b) it introduces a long pause on
  396.   some platforms like SV/68 R3.
  397. */
  398. /* #define USE_SHUTDOWN */
  399. #endif /* USE_SHUTDOWN */
  400.  
  401. #ifndef NORESEND
  402. #ifndef NORESTART                       /* Restart / recover */
  403. #ifndef FTP_RESTART
  404. #define FTP_RESTART
  405. #endif /* FTP_RESTART */
  406. #endif /* NORESTART */
  407. #endif /* NORESEND */
  408.  
  409. #ifndef NOUPDATE                        /* Update mode */
  410. #ifndef DOUPDATE
  411. #define DOUPDATE
  412. #endif /* DOUPDATE */
  413. #endif /* NOUPDATE */
  414.  
  415. #ifndef UNICODE                         /* Unicode required */
  416. #ifndef NOCSETS                         /* for charset translation */
  417. #define NOCSETS
  418. #endif /* NOCSETS */
  419. #endif /* UNICODE */
  420.  
  421. #ifndef OS2
  422. #ifndef HAVE_MSECS                      /* Millisecond timer */
  423. #ifdef UNIX
  424. #ifdef GFTIMER
  425. #define HAVE_MSECS
  426. #endif /* GFTIMER */
  427. #endif /* UNIX */
  428. #endif /* HAVE_MSECS */
  429. #endif /* OS2 */
  430.  
  431. #ifdef PIPESEND                         /* PUT from pipe */
  432. #ifndef PUTPIPE
  433. #define PUTPIPE
  434. #endif /* PUTPIPE */
  435. #endif /* PIPESEND */
  436.  
  437. #ifndef NOSPL                           /* PUT from array */
  438. #ifndef PUTARRAY
  439. #define PUTARRAY
  440. #endif /* PUTARRAY */
  441. #endif /* NOSPL */
  442.  
  443. /* Security... */
  444.  
  445. #ifdef CK_SRP
  446. #define FTP_SRP
  447. #endif /* CK_SRP */
  448.  
  449. #ifdef CK_KERBEROS
  450. #ifdef KRB4
  451. /*
  452.   There is a conflict between the Key Schedule formats used internally
  453.   within the standalone MIT KRB4 library and that used by Eric Young
  454.   in OpenSSL and his standalone DES library.  Therefore, KRB4 FTP AUTH
  455.   cannot be supported when either of those two packages are used.
  456. */
  457. #ifdef KRB524
  458. #define FTP_KRB4
  459. #else /* KRB524 */
  460. #ifndef CK_SSL
  461. #ifndef LIBDES
  462. #define FTP_KRB4
  463. #endif /* LIBDES */
  464. #endif /* CK_SSL */
  465. #endif /* KRB524 */
  466. #endif /* KRB4 */
  467. #ifdef KRB5
  468. #ifndef HEIMDAL
  469. #ifndef NOFTP_GSSAPI            /* 299 */
  470. #define FTP_GSSAPI
  471. #endif    /* NOFTP_GSSAPI */
  472. #endif /* HEIMDAL */
  473. #endif /* KRB5 */
  474. #endif /* CK_KERBEROS */
  475.  
  476. /* FTP_SECURITY is defined if any of the above is selected */
  477. #ifndef FTP_SECURITY
  478. #ifdef FTP_GSSAPI
  479. #define FTP_SECURITY
  480. #else
  481. #ifdef FTP_KRB4
  482. #define FTP_SECURITY
  483. #else
  484. #ifdef FTP_SRP
  485. #define FTP_SECURITY
  486. #else
  487. #ifdef CK_SSL
  488. #define FTP_SECURITY
  489. #endif /* CK_SSL */
  490. #endif /* FTP_SRP */
  491. #endif /* FTP_KRB4 */
  492. #endif /* FTP_GSSAPI */
  493. #endif /* FTP_SECURITY */
  494.  
  495. #ifdef CK_DES
  496. #ifdef CK_SSL
  497. #ifndef LIBDES
  498. #define LIBDES
  499. #endif /* LIBDES */
  500. #endif /* CK_SSL */
  501. #endif /* CK_DES */
  502.  
  503. #ifdef CRYPT_DLL
  504. #ifndef LIBDES
  505. #define LIBDES
  506. #endif /* LIBDES */
  507. #endif /* CRYPT_DLL */
  508.  
  509. #ifdef FTP_KRB4
  510. #define des_cblock Block
  511. #define des_key_schedule Schedule
  512. #ifdef KRB524
  513. #ifdef NT
  514. #define _WINDOWS
  515. #endif /* NT */
  516. #include "kerberosIV/krb.h"
  517. #else /* KRB524 */
  518. #ifdef SOLARIS
  519. #ifndef sun
  520. /* For some reason lost in history the Makefile Solaris targets have -Usun */
  521. #define sun
  522. #endif /* sun */
  523. #endif /* SOLARIS */
  524. #include "krb.h"
  525. #define krb_get_err_text_entry krb_get_err_text
  526. #endif /* KRB524 */
  527. #endif /* FTP_KRB4 */
  528.  
  529. #ifdef CK_SSL
  530. #ifdef FTP_KRB4
  531. #ifndef HEADER_DES_H
  532. #define HEADER_DES_H
  533. #endif /* HEADER_DES_H */
  534. #endif /* FTP_KRB4 */
  535. #include "ck_ssl.h"
  536. #endif /* CK_SSL */
  537.  
  538. #ifdef FTP_SRP
  539. #ifdef HAVE_PWD_H
  540. #include "pwd.h"
  541. #endif /* HAVE_PWD_H */
  542. #include "t_pwd.h"
  543. #include "t_client.h"
  544. #include "krypto.h"
  545. #endif /* FTP_SRP */
  546.  
  547. #ifdef FTP_GSSAPI
  548. #include <gssapi/gssapi.h>
  549. /*
  550.   Need to include the krb5 file, because we're doing manual fallback
  551.   from the v2 mech to the v1 mech.  Once there's real negotiation,
  552.   we can be generic again.
  553. */
  554. #include <gssapi/gssapi_generic.h>
  555. #include <gssapi/gssapi_krb5.h>
  556. static gss_ctx_id_t gcontext;
  557.  
  558. #ifdef MACOSX
  559. /** exported constants defined in gssapi_krb5{,_nx}.h **/
  560.  
  561. /* these are bogus, but will compile */
  562.  
  563. /*
  564.  * The OID of the draft krb5 mechanism, assigned by IETF, is:
  565.  *      iso(1) org(3) dod(5) internet(1) security(5)
  566.  *      kerberosv5(2) = 1.3.5.1.5.2
  567.  * The OID of the krb5_name type is:
  568.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  569.  *      krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
  570.  * The OID of the krb5_principal type is:
  571.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  572.  *      krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
  573.  * The OID of the proposed standard krb5 mechanism is:
  574.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  575.  *      krb5(2) = 1.2.840.113554.1.2.2
  576.  * The OID of the proposed standard krb5 v2 mechanism is:
  577.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  578.  *      krb5v2(3) = 1.2.840.113554.1.2.3
  579.  *
  580.  */
  581.  
  582. /*
  583.  * Encoding rules: The first two values are encoded in one byte as 40
  584.  * * value1 + value2.  Subsequent values are encoded base 128, most
  585.  * significant digit first, with the high bit (\200) set on all octets
  586.  * except the last in each value's encoding.
  587.  */
  588.  
  589. static CONST gss_OID_desc
  590. ck_krb5_gss_oid_array[] = {
  591.    /* this is the official, rfc-specified OID */
  592.    {9, "\052\206\110\206\367\022\001\002\002"},
  593.    /* this is the unofficial, wrong OID */
  594.    {5, "\053\005\001\005\002"},
  595.    /* this is the v2 assigned OID */
  596.    {9, "\052\206\110\206\367\022\001\002\003"},
  597.    /* these two are name type OID's */
  598.    {10, "\052\206\110\206\367\022\001\002\002\001"},
  599.    {10, "\052\206\110\206\367\022\001\002\002\002"},
  600.    { 0, 0 }
  601. };
  602.  
  603. static
  604. CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
  605.  
  606. #ifdef MACOSX103
  607. static
  608. CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
  609. #endif /* MACOSX103 */
  610.  
  611. #ifndef MACOSX
  612. static
  613. CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
  614. static
  615. CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
  616. static
  617. CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
  618. static
  619. CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
  620. #endif    /* MACOSX */
  621.  
  622. /*
  623.  * See krb5/gssapi_krb5.c for a description of the algorithm for
  624.  * encoding an object identifier.
  625.  */
  626.  
  627. /*
  628.  * The OID of user_name is:
  629.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  630.  *      generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
  631.  * machine_uid_name:
  632.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  633.  *      generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
  634.  * string_uid_name:
  635.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  636.  *      generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
  637.  * service_name:
  638.  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
  639.  *      generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
  640.  * exported_name:
  641.  *      1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes),
  642.  *          4(gss-api-exported-name)
  643.  * host_based_service_name (v2):
  644.  *      iso (1) org (3), dod (6), internet (1), security (5), nametypes(6),
  645.  *      gss-host-based-services(2)
  646.  */
  647.  
  648. static gss_OID_desc ck_oids[] = {
  649.    {10, "\052\206\110\206\367\022\001\002\001\001"},
  650.    {10, "\052\206\110\206\367\022\001\002\001\002"},
  651.    {10, "\052\206\110\206\367\022\001\002\001\003"},
  652.    {10, "\052\206\110\206\367\022\001\002\001\004"},
  653.    { 6, "\053\006\001\005\006\004"},
  654.    { 6, "\053\006\001\005\006\002"},
  655. };
  656.  
  657. static gss_OID ck_gss_nt_user_name = ck_oids+0;
  658. static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1;
  659. static gss_OID ck_gss_nt_string_uid_name = ck_oids+2;
  660. static gss_OID ck_gss_nt_service_name = ck_oids+3;
  661. static gss_OID ck_gss_nt_exported_name = ck_oids+4;
  662. static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5;
  663. #endif /* MACOSX */
  664. #endif /* FTP_GSSAPI */
  665.  
  666. #ifdef OS2
  667. #ifdef FTP_SRP
  668. #define MAP_KRYPTO
  669. #ifdef SRPDLL
  670. #define MAP_SRP
  671. #endif /* SRPDLL */
  672. #endif /* FTP_SRP */
  673. #ifdef FTP_KRB4
  674. #define MAP_KRB4
  675. #ifdef CK_ENCRYPTION
  676. #define MAP_DES
  677. #endif /* CK_ENCRYPTION */
  678. #endif /* FTP_KRB4 */
  679. #ifdef FTP_GSSAPI
  680. #define MAP_GSSAPI
  681. #define GSS_OIDS
  682. #endif /* FTP_GSSAPI */
  683. #include "ckoath.h"
  684.  
  685. extern int k95stdout, wherex[], wherey[];
  686. extern unsigned char colorcmd;
  687. #endif /* OS2 */
  688.  
  689. #ifdef FTP_KRB4
  690. static char ftp_realm[REALM_SZ + 1];
  691. static KTEXT_ST ftp_tkt;
  692. #ifdef OS2
  693. static LEASH_CREDENTIALS ftp_cred;
  694. #else /* OS2 */
  695. static CREDENTIALS ftp_cred;
  696. #endif /* OS2 */
  697. static MSG_DAT ftp_msg_data;
  698. static des_key_schedule ftp_sched;
  699. static int foo[4] = {99,99,99,99};
  700. #endif /* FTP_KRB4 */
  701.  
  702. /* getreply() function codes */
  703.  
  704. #define GRF_AUTH 1            /* Reply to AUTH command */
  705. #define GRF_FEAT 2            /* Reply to FEAT command */
  706.  
  707. /* Operational definitions */
  708.  
  709. #define DEF_VBM 0                       /* Default verbose mode */
  710. /* #define SETVBM */                    /* (see getreply) */
  711.  
  712. #define URL_ONEFILE                     /* GET, not MGET, for FTP URL */
  713.  
  714. #define FTP_BUFSIZ 10240                /* Max size for FTP cmds & replies */
  715. #define SRVNAMLEN 32                    /* Max length for server type name */
  716. #define PWDSIZ 256
  717. #define PASSBUFSIZ 256
  718. #define PROMPTSIZ 256
  719.  
  720. #ifndef MGETMAX                         /* Max operands for MGET command */
  721. #define MGETMAX 1000
  722. #endif /* MGETMAX */
  723.  
  724. #ifdef FTP_SRP
  725. #define FUDGE_FACTOR 100
  726. #endif /* FTP_SRP */
  727.  
  728. /*
  729.   Amount of growth from cleartext to ciphertext.  krb_mk_priv adds this
  730.   number bytes.  Must be defined for each auth type.
  731.   GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
  732.   3DES requires 56 bytes.  Lets use 96 just to be sure.
  733. */
  734. #ifdef FTP_GSSAPI
  735. #ifndef FUDGE_FACTOR
  736. #define FUDGE_FACTOR 96
  737. #endif /* FUDGE_FACTOR */
  738. #endif /* FTP_GSSAPI */
  739.  
  740. #ifdef FTP_KRB4
  741. #ifndef FUDGE_FACTOR
  742. #define FUDGE_FACTOR 32
  743. #endif /* FUDGE_FACTOR */
  744. #endif /* FTP_KRB4 */
  745.  
  746. #ifndef FUDGE_FACTOR                    /* In case no auth types define it */
  747. #define FUDGE_FACTOR 0
  748. #endif /* FUDGE_FACTOR */
  749.  
  750. #ifndef MAXHOSTNAMELEN
  751. #define MAXHOSTNAMELEN 64
  752. #endif /* MAXHOSTNAMELEN */
  753. #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
  754.  
  755. /* Fascist compiler toadying */
  756.  
  757. #ifndef SENDARG2TYPE
  758. #ifdef COMMENT                          /* Might be needed here and there */
  759. #define SENDARG2TYPE const char *
  760. #else
  761. #define SENDARG2TYPE char *
  762. #endif /* COMMENT */
  763. #endif /* SENDARG2TYPE */
  764.  
  765. /* Common text messages */
  766.  
  767. static char *nocx = "?No FTP control connection\n";
  768.  
  769. static char *fncnam[] = {
  770.   "rename", "overwrite", "backup", "append", "discard", "ask", "update",
  771.   "dates-differ", ""
  772. };
  773.  
  774. /* Macro definitions */
  775.  
  776. /* Used to speed up text-mode PUTs */
  777. #define zzout(fd,c) \
  778. ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
  779.  
  780. #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
  781.  
  782. /* Externals */
  783.  
  784. #ifdef CK_URL
  785. extern struct urldata g_url;
  786. #endif /* CK_URL */
  787.  
  788. #ifdef DYNAMIC
  789. extern char *zinbuffer, *zoutbuffer;    /* Regular Kermit file i/o */
  790. #else
  791. extern char zinbuffer[], zoutbuffer[];
  792. #endif /* DYNAMIC */
  793. extern char *zinptr, *zoutptr;
  794. extern int zincnt, zoutcnt, zobufsize, fncact;
  795.  
  796. #ifdef CK_TMPDIR
  797. extern int f_tmpdir;                    /* Directory changed temporarily */
  798. extern char savdir[];                   /* For saving current directory */
  799. extern char * dldir;
  800. #endif /* CK_TMPDIR */
  801.  
  802. extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
  803.  
  804. extern xx_strp xxstring;
  805. extern struct keytab onoff[], txtbin[], rpathtab[];
  806. extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
  807. extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
  808. extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
  809. extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
  810. extern int nolinks, msgflg, keep;
  811. extern CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len;
  812. extern long filcnt, xfsecs, tfcps, cps, oldcps;
  813.  
  814. #ifdef FTP_TIMEOUT
  815. int ftp_timed_out = 0;
  816. long ftp_timeout = 0;
  817. #endif    /* FTP_TIMEOUT */
  818.  
  819. #ifdef GFTIMER
  820. extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
  821. #else
  822. extern long xfsecs;
  823. #endif /* GFTIMER */
  824.  
  825. extern char filnam[], * filefile, myhost[];
  826. extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
  827. extern int g_skipbup, skipbup, sendmode;
  828. extern int g_displa, fdispla, displa;
  829.  
  830. #ifdef LOCUS
  831. extern int locus, autolocus;
  832. #endif /* LOCUS */
  833.  
  834. #ifndef NOCSETS
  835. extern int nfilc, dcset7, dcset8, fileorder;
  836. extern struct csinfo fcsinfo[];
  837. extern struct keytab fcstab[];
  838. extern int fcharset;
  839. #endif /* NOCSETS */
  840.  
  841. extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
  842. extern char sndnbefore[], sndnafter[], *rcvexcept[];
  843. extern CHAR feol;
  844.  
  845. extern char * remdest;
  846. extern int remfile, remappd, rempipe;
  847.  
  848. #ifndef NOSPL
  849. extern int cmd_quoting;
  850. #ifdef PUTARRAY
  851. extern int sndxlo, sndxhi, sndxin;
  852. extern char sndxnam[];
  853. extern char **a_ptr[];                  /* Array pointers */
  854. extern int a_dim[];                     /* Array dimensions */
  855. #endif /* PUTARRAY */
  856. #endif /* NOSPL */
  857.  
  858. #ifndef NOMSEND                         /* MPUT and ADD SEND-LIST lists */
  859. extern char *msfiles[];
  860. extern int filesinlist;
  861. extern struct filelist * filehead;
  862. extern struct filelist * filetail;
  863. extern struct filelist * filenext;
  864. extern int addlist;
  865. extern char fspec[];                    /* Most recent filespec */
  866. extern int fspeclen;                    /* Length of fspec[] buffer */
  867. #endif /* NOMSEND */
  868.  
  869. extern int pipesend;
  870. #ifdef PIPESEND
  871. extern char * sndfilter, * rcvfilter;
  872. #endif /* PIPESEND */
  873.  
  874. #ifdef CKROOT
  875. extern int ckrooterr;
  876. #endif /* CKROOT */
  877.  
  878. #ifdef KRB4
  879. extern int krb4_autoget;
  880. _PROTOTYP(char * ck_krb4_realmofhost,(char *));
  881. #endif /* KRB4 */
  882.  
  883. #ifdef KRB5
  884. extern int krb5_autoget;
  885. extern int krb5_d_no_addresses;
  886. _PROTOTYP(char * ck_krb5_realmofhost,(char *));
  887. #endif /* KRB5 */
  888.  
  889. #ifdef DCMDBUF
  890. extern char *atmbuf;                    /* Atom buffer (malloc'd) */
  891. extern char *cmdbuf;                    /* Command buffer (malloc'd) */
  892. extern char *line;                      /* Big string buffer #1 */
  893. extern char *tmpbuf;                    /* Big string buffer #2 */
  894. #else
  895. extern char atmbuf[];                   /* The same, but static */
  896. extern char cmdbuf[];
  897. extern char line[];
  898. extern char tmpbuf[];
  899. #endif /* DCMDBUF */
  900.  
  901. extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
  902.  
  903. /* Public variables declared here */
  904.  
  905. #ifdef NOXFER
  906. int ftpget  =  1;                       /* GET/PUT/REMOTE orientation FTP */
  907. #else
  908. int ftpget  =  2;                       /* GET/PUT/REMOTE orientation AUTO */
  909. #endif /* NOXFER */
  910. int ftpcode = -1;                       /* Last FTP response code */
  911. int ftp_cmdlin = 0;                     /* FTP invoked from command line */
  912. int ftp_fai = 0;                        /* FTP failure count */
  913. int ftp_deb = 0;                        /* FTP debugging */
  914. int ftp_dis = -1;            /* FTP display style */
  915. int ftp_log = 1;                        /* FTP Auto-login */
  916. int sav_log = -1;
  917. int ftp_action = 0;                     /* FTP action from command line */
  918. int ftp_dates = 1;                      /* Set file dates from server */
  919. int ftp_xfermode = XMODE_A;        /* FTP-specific transfer mode */
  920.  
  921. char ftp_reply_str[FTP_BUFSIZ] = "";    /* Last line of previous reply */
  922. char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
  923. char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
  924. char * ftp_host = NULL;                 /* FTP hostname */
  925. char * ftp_logname = NULL;              /* FTP username */
  926. char * ftp_rdir = NULL;                 /* Remote directory from cmdline */
  927. char * ftp_apw = NULL;            /* Anonymous password */
  928.  
  929. /* Definitions and typedefs needed for prototypes */
  930.  
  931. #define sig_t my_sig_t
  932. #define sigtype SIGTYP
  933. typedef sigtype (*sig_t)();
  934.  
  935. /* Static global variables */
  936.  
  937. static char ftpsndbuf[FTP_BUFSIZ+64];
  938.  
  939. static char * fts_sto = NULL;
  940.  
  941. static int ftpsndret = 0;
  942. static struct _ftpsnd {
  943.     sig_t oldintr, oldintp;
  944.     int            reply;
  945.     int            incs,
  946.                    outcs;
  947.     char *         cmd, * local, * remote;
  948.     int            bytes;
  949.     int            restart;
  950.     int            xlate;
  951.     char *         lmode;
  952. } ftpsnd;
  953.  
  954. /*
  955.   This is just a first stab -- these strings should match how the
  956.   corresponding FTP servers identify themselves.
  957. */
  958. #ifdef UNIX
  959. static char * myostype = "UNIX";
  960. #else
  961. #ifdef VMS
  962. /* not yet... */
  963. static char * myostype = "VMS";
  964. #else
  965. #ifdef OS2
  966. #ifdef NT
  967. static char * myostype = "WIN32";
  968. #else
  969. static char * myostype = "OS/2";
  970. #endif /* NT */
  971. #else
  972. static char * myostype = "UNSUPPORTED";
  973. #endif /* OS2  */
  974. #endif /* VMS */
  975. #endif /* UNIX */
  976.  
  977. static int noinit = 0;                  /* Don't send REST, STRU, MODE */
  978. static int alike = 0;                   /* Client/server like platforms */
  979. static int local = 1;                   /* Shadows Kermit global 'local' */
  980. static int dout = -1;                   /* Data connection file descriptor */
  981. static int dpyactive = 0;               /* Data transfer is active */
  982. static int globaldin = -1;              /* Data connection f.d. */
  983. static int out2screen = 0;              /* GET output is to screen */
  984. static int forcetype = 0;               /* Force text or binary mode */
  985. static int cancelfile = 0;              /* File canceled */
  986. static int cancelgroup = 0;             /* Group canceled */
  987. static int anonymous = 0;               /* Logging in as anonymous */
  988. static int loggedin = 0;                /* Logged in (or not) */
  989. static int puterror = 0;                /* What to do on PUT error */
  990. static int geterror = 0;                /* What to do on GET error */
  991. static int rfrc = 0;                    /* remote_files() return code */
  992. static int okrestart = 0;               /* Server understands REST */
  993. static int printlines = 0;              /* getreply()should print data lines */
  994. static int haveurl = 0;                 /* Invoked by command-line FTP URL */
  995. static int mdtmok = 1;            /* Server supports MDTM */
  996. static int sizeok = 1;
  997. static int featok = 1;
  998. static int mlstok = 1;
  999. static int stouarg = 1;
  1000. static int typesent = 0;
  1001. static int havesigint = 0;
  1002. static long havetype =  0;
  1003. static CK_OFF_T havesize = (CK_OFF_T)-1;
  1004. static char * havemdtm = NULL;
  1005. static int mgetmethod = 0;        /* NLST or MLSD */
  1006. static int mgetforced = 0;
  1007.  
  1008. static int i, /* j, k, */ x, y, z;      /* Volatile temporaries */
  1009. static int c0, c1;                      /* Temp variables for characters */
  1010.  
  1011. static char putpath[CKMAXPATH+1] = { NUL, NUL };
  1012. static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
  1013.  
  1014. #define RFNBUFSIZ 4096            /* Remote filename buffer size */
  1015.  
  1016. static unsigned int maxbuf = 0, actualbuf = 0;
  1017. static CHAR *ucbuf = NULL;
  1018. static int ucbufsiz = 0;
  1019. static unsigned int nout = 0;           /* Number of chars in ucbuf */
  1020.  
  1021. static jmp_buf recvcancel;
  1022. static jmp_buf sendcancel;
  1023. static jmp_buf ptcancel;
  1024. static jmp_buf jcancel;
  1025. static int ptabflg = 0;
  1026.  
  1027. /* Protection level symbols */
  1028.  
  1029. #define FPL_CLR 1                       /* Clear */
  1030. #define FPL_SAF 2                       /* Safe */
  1031. #define FPL_PRV 3                       /* Private */
  1032. #define FPL_CON 4                       /* Confidential */
  1033.  
  1034. /* Symbols for file types returned by MLST/MLSD */
  1035.  
  1036. #define FTYP_FILE 1            /* Regular file */
  1037. #define FTYP_DIR  2            /* Directory */
  1038. #define FTYP_CDIR 3            /* Current directory */
  1039. #define FTYP_PDIR 4            /* Parent directory */
  1040.  
  1041. /* File type symbols keyed to the file-type symbols from ckcker.h */
  1042.  
  1043. #define FTT_ASC XYFT_T                  /* ASCII (text) */
  1044. #define FTT_BIN XYFT_B                  /* Binary (image) */
  1045. #define FTT_TEN XYFT_X                  /* TENEX (TOPS-20) */
  1046.  
  1047. /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
  1048.  
  1049. static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  1050.  
  1051. #define SFT_AUTH  1            /* FTP server feature codes */
  1052. #define SFT_LANG  2
  1053. #define SFT_MDTM  3
  1054. #define SFT_MLST  4
  1055. #define SFT_PBSZ  5
  1056. #define SFT_PROT  6
  1057. #define SFT_REST  7
  1058. #define SFT_SIZE  8
  1059. #define SFT_TVFS  9
  1060. #define SFT_UTF8 10
  1061.  
  1062. #define CNV_AUTO  2            /* FTP filename conversion */
  1063. #define CNV_CNV   1
  1064. #define CNV_LIT   0
  1065.  
  1066. /* SET FTP values */
  1067.  
  1068. static int                              /* SET FTP values... */
  1069.   ftp_aut = 1,                          /* Auto-authentication */
  1070. #ifdef FTP_SECURITY
  1071.   ftp_cry = 1,                          /* Auto-encryption */
  1072.   ftp_cfw = 0,                          /* Credential forwarding */
  1073. #endif /* FTP_SECURITY */
  1074.   ftp_cpl = FPL_CLR,                    /* Command protection level */
  1075.   ftp_dpl = FPL_CLR,                    /* Data protection level */
  1076. #ifdef FTP_PROXY
  1077.   ftp_prx = 0,                          /* Use proxy */
  1078. #endif /* FTP_PROXY */
  1079.   sav_psv = -1,                         /* For saving passive mode */
  1080.   ftp_psv = 1,                          /* Passive mode */
  1081.   ftp_spc = 1,                          /* Send port commands */
  1082.   ftp_typ = FTT_ASC,                    /* Type */
  1083.   get_auto = 1,                         /* Automatic type switching for GET */
  1084.   tenex = 0,                            /* Type is Tenex */
  1085.   ftp_usn = 0,                          /* Unique server names */
  1086.   ftp_prm = 0,                          /* Permissions */
  1087.   ftp_cnv = CNV_AUTO,            /* Filename conversion (2 = auto) */
  1088.   ftp_vbm = DEF_VBM,                    /* Verbose mode */
  1089.   ftp_vbx = DEF_VBM,                    /* Sticky version of same */
  1090.   ftp_err = 0,                          /* Error action */
  1091.   ftp_fnc = -1;                         /* Filename collision action */
  1092.  
  1093. #ifdef CK_SSL
  1094. static int ftp_bug_use_ssl_v2 = 0;      /* use SSLv2 for AUTH SSL */
  1095. #endif /* CK_SSL */
  1096.  
  1097. static int
  1098. #ifdef NOCSETS
  1099.   ftp_csr = -1,                         /* Remote (server) character set */
  1100. #else
  1101.   ftp_csr = FC_UTF8,
  1102. #endif /* NOCSETS */
  1103.   ftp_xla = 0;                          /* Character-set translation on/off */
  1104. int
  1105.   ftp_csx = -1,                         /* Remote charset currently in use */
  1106.   ftp_csl = -1;                         /* Local charset currently in use */
  1107.  
  1108. static int g_ftp_typ = FTT_ASC;         /* For saving and restoring ftp_typ */
  1109.  
  1110. char * ftp_nml = NULL;                  /* /NAMELIST */
  1111. char * ftp_tmp = NULL;                  /* Temporary string */
  1112. static char * ftp_acc = NULL;           /* Account string */
  1113. static char * auth_type = NULL;         /* Authentication type */
  1114. static char * srv_renam = NULL;         /* Server-rename string */
  1115. FILE * fp_nml = NULL;                   /* Namelist file pointer */
  1116.  
  1117. static int csocket = -1;                /* Control socket */
  1118. static int connected = 0;               /* Connected to FTP server */
  1119. /* static unsigned short ftp_port = 0; */ /* FTP port */ 
  1120. /* static int ftp_port = 0; */        /* SMS 2007/02/15 */
  1121. static int ftp_port = 0;        /* fdc 2007/08/30 */
  1122. #ifdef FTPHOST
  1123. static int hostcmd = 0;                 /* Has HOST command been sent */
  1124. #endif /* FTPHOST */
  1125. static int form, mode, stru, bytesize, curtype = FTT_ASC;
  1126. static char bytename[8];
  1127.  
  1128. /* For parsing replies to FTP server command */
  1129. static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
  1130.  
  1131. #ifdef FTP_PROXY
  1132. static int proxy, unix_proxy
  1133. #endif /* FTP_PROXY */
  1134.  
  1135. static char pasv[64];                   /* Passive-mode port */
  1136. static int passivemode = 0;
  1137. static int sendport = 0;
  1138. static int servertype = 0;              /* FTP server's OS type */
  1139.  
  1140. static int testing = 0;
  1141. static char ftpcmdbuf[FTP_BUFSIZ];
  1142.  
  1143. /* Macro definitions */
  1144.  
  1145. #define UC(b) ckitoa(((int)b)&0xff)
  1146. #define nz(x) ((x) == 0 ? 1 : (x))
  1147.  
  1148. /* Command tables and definitions */
  1149.  
  1150. #define FTP_ACC  1                      /* FTP command keyword codes */
  1151. #define FTP_APP  2
  1152. #define FTP_CWD  3
  1153. #define FTP_CHM  4
  1154. #define FTP_CLS  5
  1155. #define FTP_DEL  6
  1156. #define FTP_DIR  7
  1157. #define FTP_GET  8
  1158. #define FTP_IDL  9
  1159. #define FTP_MDE 10
  1160. #define FTP_MDI 11
  1161. #define FTP_MGE 12
  1162. #define FTP_MKD 13
  1163. #define FTP_MOD 14
  1164. #define FTP_MPU 15
  1165. #define FTP_OPN 16
  1166. #define FTP_PUT 17
  1167. #define FTP_PWD 18
  1168. #define FTP_RGE 19
  1169. #define FTP_REN 20
  1170. #define FTP_RES 21
  1171. #define FTP_HLP 22
  1172. #define FTP_RMD 23
  1173. #define FTP_STA 24
  1174. #define FTP_SIT 25
  1175. #define FTP_SIZ 26
  1176. #define FTP_SYS 27
  1177. #define FTP_UMA 28
  1178. #define FTP_GUP 29
  1179. #define FTP_USR 30
  1180. #define FTP_QUO 31
  1181. #define FTP_TYP 32
  1182. #define FTP_FEA 33
  1183. #define FTP_OPT 34
  1184. #define FTP_CHK 35
  1185. #define FTP_VDI 36
  1186. #define FTP_ENA 37
  1187. #define FTP_DIS 38
  1188. #define FTP_REP 39
  1189.  
  1190. struct keytab gprtab[] = {              /* GET-PUT-REMOTE keywords */
  1191.     { "auto",    2, 0 },
  1192.     { "ftp",     1, 0 },
  1193.     { "kermit",  0, 0  }
  1194. };
  1195.  
  1196. static struct keytab qorp[] = {         /* QUIT or PROCEED keywords */
  1197.     { "proceed", 0, 0 },                /* 0 = proceed */
  1198.     { "quit",    1, 0 }                 /* 1 = quit */
  1199. };
  1200.  
  1201. static struct keytab ftpcmdtab[] = {    /* FTP command table */
  1202.     { "account",   FTP_ACC, 0 },
  1203.     { "append",    FTP_APP, 0 },
  1204.     { "bye",       FTP_CLS, 0 },
  1205.     { "cd",        FTP_CWD, 0 },
  1206.     { "cdup",      FTP_GUP, 0 },
  1207.     { "check",     FTP_CHK, 0 },
  1208.     { "chmod",     FTP_CHM, 0 },
  1209.     { "close",     FTP_CLS, 0 },
  1210.     { "cwd",       FTP_CWD, CM_INV },
  1211.     { "delete",    FTP_MDE, 0 },
  1212.     { "directory", FTP_DIR, 0 },
  1213.     { "disable",   FTP_DIS, 0 },
  1214.     { "enable",    FTP_ENA, 0 },
  1215.     { "features",  FTP_FEA, 0 },
  1216.     { "get",       FTP_GET, 0 },
  1217.     { "help",      FTP_HLP, 0 },
  1218.     { "idle",      FTP_IDL, 0 },
  1219.     { "login",     FTP_USR, CM_INV },
  1220.     { "mdelete",   FTP_MDE, CM_INV },
  1221.     { "mget",      FTP_MGE, 0 },
  1222.     { "mkdir",     FTP_MKD, 0 },
  1223.     { "modtime",   FTP_MOD, 0 },
  1224.     { "mput",      FTP_MPU, 0 },
  1225.     { "open",      FTP_OPN, 0 },
  1226.     { "opt",       FTP_OPT, CM_INV|CM_ABR },
  1227.     { "opts",      FTP_OPT, CM_INV },
  1228.     { "options",   FTP_OPT, 0 },
  1229.     { "put",       FTP_PUT, 0 },
  1230.     { "pwd",       FTP_PWD, 0 },
  1231.     { "quit",      FTP_CLS, CM_INV },
  1232.     { "quote",     FTP_QUO, 0 },
  1233.     { "reget",     FTP_RGE, 0 },
  1234.     { "rename",    FTP_REN, 0 },
  1235.     { "reput",     FTP_REP, 0 },
  1236.     { "resend",    FTP_REP, CM_INV },
  1237.     { "reset",     FTP_RES, 0 },
  1238.     { "rmdir",     FTP_RMD, 0 },
  1239.     { "send",      FTP_PUT, CM_INV },
  1240.     { "site",      FTP_SIT, 0 },
  1241.     { "size",      FTP_SIZ, 0 },
  1242.     { "status",    FTP_STA, 0 },
  1243.     { "system",    FTP_SYS, 0 },
  1244.     { "type",      FTP_TYP, 0 },
  1245.     { "umask",     FTP_UMA, 0 },
  1246.     { "up",        FTP_GUP, CM_INV },
  1247.     { "user",      FTP_USR, 0 },
  1248.     { "vdirectory",FTP_VDI, 0 },
  1249.     { "", 0, 0 }
  1250. };
  1251. static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
  1252.  
  1253. #define OPN_ANO 1            /* FTP OPEN switch codes */
  1254. #define OPN_PSW 2
  1255. #define OPN_USR 3
  1256. #define OPN_ACC 4
  1257. #define OPN_ACT 5
  1258. #define OPN_PSV 6
  1259. #define OPN_TLS 7
  1260. #define OPN_NIN 8
  1261. #define OPN_NOL 9
  1262.  
  1263. #ifdef FTP_SECURITY
  1264. #ifdef CK_SSL
  1265. #define USETLSTAB
  1266. static struct keytab tlstab[] = {       /* FTP SSL/TLS switches */
  1267.     { "/ssl",       OPN_TLS, 0    },
  1268.     { "/tls",       OPN_TLS, 0    },
  1269.     { "", 0, 0 }
  1270. };
  1271. static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
  1272. #endif /* CK_SSL */
  1273. #endif /* FTP_SECURITY */
  1274.  
  1275. static struct keytab ftpswitab[] = {    /* FTP command switches */
  1276.     { "/account",   OPN_ACC, CM_ARG },
  1277.     { "/active",    OPN_ACT, 0      },
  1278.     { "/anonymous", OPN_ANO, 0      },
  1279.     { "/noinit",    OPN_NIN, 0      },
  1280.     { "/nologin",   OPN_NOL, 0      },
  1281.     { "/passive",   OPN_PSV, 0      },
  1282.     { "/password",  OPN_PSW, CM_ARG },
  1283.     { "/user",      OPN_USR, CM_ARG },
  1284.     { "", 0, 0 }
  1285. };
  1286. static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
  1287.  
  1288. /* FTP { ENABLE, DISABLE } items */
  1289.  
  1290. #define ENA_FEAT 1
  1291. #define ENA_MDTM 2
  1292. #define ENA_MLST 3
  1293. #define ENA_SIZE 4
  1294. #define ENA_AUTH 5
  1295.  
  1296. static struct keytab ftpenatab[] = {
  1297.     { "AUTH",  ENA_AUTH, 0 },
  1298.     { "FEAT",  ENA_FEAT, 0 },
  1299.     { "MDTM",  ENA_MDTM, 0 },
  1300.     { "ML",    ENA_MLST, CM_INV|CM_ABR },
  1301.     { "MLS",   ENA_MLST, CM_INV|CM_ABR },
  1302.     { "MLSD",  ENA_MLST, CM_INV },
  1303.     { "MLST",  ENA_MLST, 0 },
  1304.     { "SIZE",  ENA_SIZE, 0 },
  1305.     { "", 0, 0 }
  1306. };
  1307. static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
  1308.  
  1309. /* SET FTP command keyword indices */
  1310.  
  1311. #define FTS_AUT  1                      /* Autoauthentication */
  1312. #define FTS_CRY  2                      /* Encryption */
  1313. #define FTS_LOG  3                      /* Autologin */
  1314. #define FTS_CPL  4                      /* Command protection level */
  1315. #define FTS_CFW  5                      /* Credentials forwarding */
  1316. #define FTS_DPL  6                      /* Data protection level */
  1317. #define FTS_DBG  7                      /* Debugging */
  1318. #define FTS_PSV  8                      /* Passive mode */
  1319. #define FTS_SPC  9                      /* Send port commands */
  1320. #define FTS_TYP 10                      /* (file) Type */
  1321. #define FTS_USN 11                      /* Unique server names (for files) */
  1322. #define FTS_VBM 12                      /* Verbose mode */
  1323. #define FTS_ATP 13                      /* Authentication type */
  1324. #define FTS_CNV 14                      /* Filename conversion */
  1325. #define FTS_TST 15                      /* Test (progress) messages */
  1326. #define FTS_PRM 16                      /* (file) Permissions */
  1327. #define FTS_XLA 17                      /* Charset translation */
  1328. #define FTS_CSR 18                      /* Server charset */
  1329. #define FTS_ERR 19                      /* Error action */
  1330. #define FTS_FNC 20                      /* Collision */
  1331. #define FTS_SRP 21                      /* SRP options */
  1332. #define FTS_GFT 22                      /* GET automatic file-type switching */
  1333. #define FTS_DAT 23                      /* Set file dates */
  1334. #define FTS_STO 24            /* Server time offset */
  1335. #define FTS_APW 25            /* Anonymous password */
  1336. #define FTS_DIS 26            /* File-transfer display style */
  1337. #define FTS_BUG 27                      /* Bug(s) */
  1338. #define FTS_TMO 28            /* Timeout */
  1339.  
  1340. /* FTP BUGS */
  1341.  
  1342. #define FTB_SV2  1                      /* use SSLv2 */
  1343.  
  1344. static struct keytab ftpbugtab[] = {
  1345.     { "use-ssl-v2",     FTB_SV2,        0 }
  1346. };
  1347. static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
  1348.  
  1349. /* FTP PUT options (mutually exclusive, not a bitmask) */
  1350.  
  1351. #define PUT_UPD 1                       /* Update */
  1352. #define PUT_RES 2                       /* Restart */
  1353. #define PUT_SIM 4                       /* Simulation */
  1354. #define PUT_DIF 8            /* Dates Differ */
  1355.  
  1356. static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
  1357. #ifndef MAC
  1358.     { "append",    XYFX_A, 0 },         /* append to old file */
  1359. #endif /* MAC */
  1360. #ifdef COMMENT
  1361.     { "ask",       XYFX_Q, 0 },         /* ask what to do (not implemented) */
  1362. #endif
  1363.     { "backup",    XYFX_B, 0 },         /* rename old file */
  1364. #ifndef MAC
  1365.     { "dates-differ", XYFX_M, 0 },    /* accept if dates differ */
  1366.     { "discard",   XYFX_D, 0 },         /* don't accept new file */
  1367.     { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
  1368. #endif /* MAC */
  1369.     { "overwrite", XYFX_X, 0 },         /* overwrite the old file */
  1370.     { "rename",    XYFX_R, 0 },         /* rename the incoming file */
  1371. #ifndef MAC                             /* This crashes Mac Kermit. */
  1372.     { "update",    XYFX_U, 0 },         /* replace if newer */
  1373. #endif /* MAC */
  1374.     { "", 0, 0 }
  1375. };
  1376. static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
  1377.  
  1378.  
  1379. #ifdef FTP_SECURITY
  1380. /* FTP authentication options */
  1381.  
  1382. #define FTA_AUTO 0                      /* Auto */
  1383. #define FTA_SRP  1                      /* SRP */
  1384. #define FTA_GK5  2                      /* Kerberos 5 */
  1385. #define FTA_K4   3                      /* Kerberos 4 */
  1386. #define FTA_SSL  4                      /* SSL */
  1387. #define FTA_TLS  5                      /* TLS */
  1388.  
  1389. /* FTP authentication types */
  1390.  
  1391. #define FTPATYPS 8
  1392. static int ftp_auth_type[FTPATYPS] = {
  1393. #ifdef FTP_GSSAPI
  1394.     FTA_GK5,                            /* GSSAPI Kerberos 5 */
  1395. #endif /* FTP_GK5 */
  1396. #ifdef FTP_SRP
  1397.     FTA_SRP,                            /* SRP */
  1398. #endif /* FTP_SRP */
  1399. #ifdef FTP_KRB4
  1400.     FTA_K4,                             /* Kerberos 4 */
  1401. #endif /* FTP_KRB4 */
  1402. #ifdef CK_SSL
  1403.     FTA_TLS,                            /* TLS */
  1404.     FTA_SSL,                            /* SSL */
  1405. #endif /* CK_SSL */
  1406.     0
  1407. };
  1408.  
  1409. static struct keytab ftpauth[] = {      /* SET FTP AUTHTYPE cmd table */
  1410.     { "automatic", FTA_AUTO,  CM_INV },
  1411. #ifdef FTP_GSSAPI
  1412.     { "gssapi-krb5", FTA_GK5, 0 },
  1413. #endif /* FTP_GSSAPI */
  1414. #ifdef FTP_KRB4
  1415.     { "k4",       FTA_K4,     CM_INV },
  1416. #endif /* FTP_KRB4 */
  1417. #ifdef FTP_GSSAPI
  1418.     { "k5",        FTA_GK5,   CM_INV },
  1419. #endif /* FTP_GSSAPI */
  1420. #ifdef FTP_KRB4
  1421.     { "kerberos4", FTA_K4,    0 },
  1422. #endif /* FTP_KRB4 */
  1423. #ifdef FTP_GSSAPI
  1424.     { "kerberos5", FTA_GK5,   CM_INV },
  1425. #endif /* FTP_GSSAPI */
  1426. #ifdef FTP_KRB4
  1427.     { "kerberos_iv",FTA_K4,   CM_INV },
  1428. #endif /* FTP_KRB4 */
  1429. #ifdef FTP_GSSAPI
  1430.     { "kerberos_v", FTA_GK5,  CM_INV },
  1431. #endif /* FTP_GSSAPI */
  1432. #ifdef FTP_KRB4
  1433.     { "krb4",     FTA_K4,     CM_INV },
  1434. #endif /* FTP_KRB4 */
  1435. #ifdef FTP_GSSAPI
  1436.     { "krb5",     FTA_GK5,    CM_INV },
  1437. #endif /* FTP_GSSAPI */
  1438. #ifdef FTP_SRP
  1439.     { "srp",      FTA_SRP,     0 },
  1440. #endif /* FTP_SRP */
  1441. #ifdef CK_SSL
  1442.     { "ssl",      FTA_SSL,     0 },
  1443.     { "tls",      FTA_TLS,     0 },
  1444. #endif /* CK_SSL */
  1445.     { "", 0, 0 }
  1446. };
  1447. static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
  1448.  
  1449. #ifdef FTP_SRP
  1450. #define SRP_CIPHER 1
  1451. #define SRP_HASH   2
  1452. static struct keytab ftpsrp[] = {      /* SET FTP SRP command table */
  1453.     { "cipher",   SRP_CIPHER,     0 },
  1454.     { "hash",     SRP_HASH,       0 },
  1455.     { "", 0, 0 }
  1456. };
  1457. static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
  1458. #endif /* FTP_SRP */
  1459. #endif /* FTP_SECURITY */
  1460.  
  1461. static struct keytab ftpset[] = {       /* SET FTP commmand table */
  1462.     { "anonymous-password",       FTS_APW, 0 },
  1463. #ifdef FTP_SECURITY
  1464.     { "authtype",                 FTS_ATP, 0 },
  1465.     { "autoauthentication",       FTS_AUT, 0 },
  1466.     { "autoencryption",           FTS_CRY, 0 },
  1467. #endif /* FTP_SECURITY */
  1468.     { "autologin",                FTS_LOG, 0 },
  1469.     { "bug",                      FTS_BUG, 0 },
  1470. #ifndef NOCSETS
  1471.     { "character-set-translation",FTS_XLA, 0 },
  1472. #endif /* NOCSETS */
  1473.     { "collision",                FTS_FNC, 0 },
  1474. #ifdef FTP_SECURITY
  1475.     { "command-protection-level", FTS_CPL, 0 },
  1476.     { "cpl",                      FTS_CPL, CM_INV },
  1477.     { "credential-forwarding",    FTS_CFW, 0 },
  1478.     { "da",                       FTS_DAT, CM_INV|CM_ABR },
  1479.     { "data-protection-level",    FTS_DPL, 0 },
  1480. #endif /* FTP_SECURITY */
  1481.     { "dates",                    FTS_DAT, 0 },
  1482.     { "debug",                    FTS_DBG, 0 },
  1483.     { "display",                  FTS_DIS, 0 },
  1484. #ifdef FTP_SECURITY
  1485.     { "dpl",                      FTS_DPL, CM_INV },
  1486. #endif /* FTP_SECURITY */
  1487.     { "error-action",             FTS_ERR, 0 },
  1488.     { "filenames",                FTS_CNV, 0 },
  1489.     { "get-filetype-switching",   FTS_GFT, 0 },
  1490.     { "passive-mode",             FTS_PSV, 0 },
  1491.     { "pasv",                     FTS_PSV, CM_INV },
  1492.     { "permissions",              FTS_PRM, 0 },
  1493.     { "progress-messages",        FTS_TST, 0 },
  1494.     { "send-port-commands",       FTS_SPC, 0 },
  1495. #ifndef NOCSETS
  1496.     { "server-character-set",     FTS_CSR, 0 },
  1497. #endif /* NOCSETS */
  1498.     { "server-time-offset",       FTS_STO, 0 },
  1499. #ifdef FTP_SRP
  1500.     { "srp",                      FTS_SRP, 0 },
  1501. #else
  1502.     { "srp",                      FTS_SRP, CM_INV },
  1503. #endif /* FTP_SRP */
  1504. #ifdef FTP_TIMEOUT
  1505.     { "timeout",                  FTS_TMO, 0 },
  1506. #endif    /* FTP_TIMEOUT */
  1507.     { "type",                     FTS_TYP, 0 },
  1508.     { "unique-server-names",      FTS_USN, 0 },
  1509.     { "verbose-mode",             FTS_VBM, 0 },
  1510.     { "", 0, 0 }
  1511. };
  1512. static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
  1513.  
  1514. /*
  1515.   GET and PUT switches are approximately the same as Kermit GET and SEND,
  1516.   and use the same SND_xxx definitions, but hijack a couple for FTP use.
  1517.   Don't just make up new ones, since the number of SND_xxx options must be
  1518.   known in advance for the switch-parsing arrays.
  1519. */
  1520. #define SND_USN SND_PRO                 /* /UNIQUE instead of /PROTOCOL */
  1521. #define SND_PRM SND_PIP                 /* /PERMISSIONS instead of /PIPES */
  1522. #define SND_TEN SND_CAL                 /* /TENEX instead of /CALIBRATE */
  1523.  
  1524. static struct keytab putswi[] = {       /* FTP PUT switch table */
  1525.     { "/after",                SND_AFT, CM_ARG },
  1526. #ifdef PUTARRAY
  1527.     { "/array",                SND_ARR, CM_ARG },
  1528. #endif /* PUTARRAY */
  1529.     { "/as",                   SND_ASN, CM_ARG|CM_INV|CM_ABR },
  1530.     { "/as-name",              SND_ASN, CM_ARG },
  1531.     { "/ascii",                SND_TXT, CM_INV },
  1532.     { "/b",                    SND_BIN, CM_INV|CM_ABR },
  1533.     { "/before",               SND_BEF, CM_ARG },
  1534.     { "/binary",               SND_BIN, 0 },
  1535. #ifdef PUTPIPE
  1536.     { "/command",              SND_CMD, CM_PSH },
  1537. #endif /* PUTPIPE */
  1538. #ifdef COMMENT
  1539. /* This works but it's dangerous */
  1540. #ifdef DOUPDATE
  1541.     { "/dates-differ",         SND_DIF, CM_INV },
  1542. #endif /* DOUPDATE */
  1543. #endif /* COMMENT */
  1544.     { "/delete",               SND_DEL, 0 },
  1545. #ifdef UNIXOROSK
  1546.     { "/dotfiles",             SND_DOT, 0 },
  1547. #endif /* UNIXOROSK */
  1548.     { "/error-action",         SND_ERR, CM_ARG },
  1549.     { "/except",               SND_EXC, CM_ARG },
  1550.     { "/filenames",            SND_NAM, CM_ARG },
  1551. #ifdef PIPESEND
  1552. #ifndef NOSPL
  1553.     { "/filter",               SND_FLT, CM_ARG|CM_PSH },
  1554. #endif /* NOSPL */
  1555. #endif /* PIPESEND */
  1556. #ifdef CKSYMLINK
  1557.     { "/followlinks",          SND_LNK, 0 },
  1558. #endif /* CKSYMLINK */
  1559. #ifdef VMS
  1560.     { "/image",                SND_IMG, 0 },
  1561. #else
  1562.     { "/image",                SND_BIN, CM_INV },
  1563. #endif /* VMS */
  1564.     { "/larger-than",          SND_LAR, CM_ARG },
  1565.     { "/listfile",             SND_FIL, CM_ARG },
  1566. #ifndef NOCSETS
  1567.     { "/local-character-set",  SND_CSL, CM_ARG },
  1568. #endif /* NOCSETS */
  1569. #ifdef CK_TMPDIR
  1570.     { "/move-to",              SND_MOV, CM_ARG },
  1571. #endif /* CK_TMPDIR */
  1572.     { "/nobackupfiles",        SND_NOB, 0 },
  1573. #ifdef UNIXOROSK
  1574.     { "/nodotfiles",           SND_NOD, 0 },
  1575. #endif /* UNIXOROSK */
  1576. #ifdef CKSYMLINK
  1577.     { "/nofollowlinks",        SND_NLK, 0 },
  1578. #endif /* CKSYMLINK */
  1579.  
  1580.     { "/not-after",            SND_NAF, CM_ARG },
  1581.     { "/not-before",           SND_NBE, CM_ARG },
  1582. #ifdef UNIX
  1583.     { "/permissions",          SND_PRM, CM_ARG },
  1584. #else
  1585.     { "/permissions",          SND_PRM, CM_ARG|CM_INV },
  1586. #endif /* UNIX */
  1587.     { "/quiet",                SND_SHH, 0 },
  1588. #ifdef FTP_RESTART
  1589.     { "/recover",              SND_RES, 0 },
  1590. #endif /* FTP_RESTART */
  1591. #ifdef RECURSIVE
  1592.     { "/recursive",            SND_REC, 0 },
  1593. #endif /* RECURSIVE */
  1594.     { "/rename-to",            SND_REN, CM_ARG },
  1595. #ifdef FTP_RESTART
  1596.     { "/restart",              SND_RES, CM_INV },
  1597. #endif /* FTP_RESTART */
  1598. #ifndef NOCSETS
  1599.     { "/server-character-set", SND_CSR, CM_ARG },
  1600. #endif /* NOCSETS */
  1601.     { "/server-rename-to",     SND_SRN, CM_ARG },
  1602.     { "/simulate",             SND_SIM, 0 },
  1603.     { "/since",                SND_AFT, CM_INV|CM_ARG },
  1604.     { "/smaller-than",         SND_SMA, CM_ARG },
  1605. #ifdef COMMENT
  1606.     { "/starting-at",          SND_STA, CM_ARG },
  1607. #endif /* COMMENT */
  1608. #ifdef RECURSIVE
  1609.     { "/subdirectories",       SND_REC, CM_INV },
  1610. #endif /* RECURSIVE */
  1611.     { "/tenex",                SND_TEN, 0 },
  1612.     { "/text",                 SND_TXT, 0 },
  1613. #ifndef NOCSETS
  1614.     { "/transparent",          SND_XPA, 0 },
  1615. #endif /* NOCSETS */
  1616.     { "/type",                 SND_TYP, CM_ARG },
  1617. #ifdef DOUPDATE
  1618.     { "/update",               SND_UPD, 0 },
  1619. #endif /* DOUPDATE */
  1620.     { "/unique-server-names",  SND_USN, 0 },
  1621.     { "", 0, 0 }
  1622. };
  1623. static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
  1624.  
  1625. static struct keytab getswi[] = {       /* FTP [M]GET switch table */
  1626.     { "/after",                SND_AFT, CM_INV },
  1627.     { "/as",                   SND_ASN, CM_ARG|CM_INV|CM_ABR },
  1628.     { "/as-name",              SND_ASN, CM_ARG },
  1629.     { "/ascii",                SND_TXT, CM_INV },
  1630.     { "/before",               SND_BEF, CM_INV },
  1631.     { "/binary",               SND_BIN, 0 },
  1632.     { "/collision",            SND_COL, CM_ARG },
  1633. #ifdef PUTPIPE
  1634.     { "/command",              SND_CMD, CM_PSH },
  1635. #endif /* PUTPIPE */
  1636.     { "/delete",               SND_DEL, 0 },
  1637.     { "/error-action",         SND_ERR, CM_ARG },
  1638.     { "/except",               SND_EXC, CM_ARG },
  1639.     { "/filenames",            SND_NAM, CM_ARG },
  1640. #ifdef PIPESEND
  1641. #ifndef NOSPL
  1642.     { "/filter",               SND_FLT, CM_ARG|CM_PSH },
  1643. #endif /* NOSPL */
  1644. #endif /* PIPESEND */
  1645. #ifdef VMS
  1646.     { "/image",                SND_IMG, 0 },
  1647. #else
  1648.     { "/image",                SND_BIN, CM_INV },
  1649. #endif /* VMS */
  1650.     { "/larger-than",          SND_LAR, CM_ARG },
  1651.     { "/listfile",             SND_FIL, CM_ARG },
  1652. #ifndef NOCSETS
  1653.     { "/local-character-set",  SND_CSL, CM_ARG },
  1654. #endif /* NOCSETS */
  1655.     { "/match",                SND_PAT, CM_ARG },
  1656.     { "/ml",                   SND_MLS, CM_INV|CM_ABR },
  1657.     { "/mls",                  SND_MLS, CM_INV|CM_ABR },
  1658.     { "/mlsd",                 SND_MLS, 0 },
  1659.     { "/mlst",                 SND_MLS, CM_INV },
  1660. #ifdef CK_TMPDIR
  1661.     { "/move-to",              SND_MOV, CM_ARG },
  1662. #endif /* CK_TMPDIR */
  1663.     { "/namelist",             SND_NML, CM_ARG },
  1664.     { "/nlst",                 SND_NLS, 0 },
  1665.     { "/nobackupfiles",        SND_NOB, 0 },
  1666.     { "/nodotfiles",           SND_NOD, 0 },
  1667. #ifdef DOUPDATE
  1668.     { "/dates-differ",         SND_DIF, CM_INV },
  1669. #endif /* DOUPDATE */
  1670.     { "/not-after",            SND_NAF, CM_INV },
  1671.     { "/not-before",           SND_NBE, CM_INV },
  1672.     { "/permissions",          SND_PRM, CM_INV },
  1673.     { "/quiet",                SND_SHH, 0 },
  1674. #ifdef FTP_RESTART
  1675.     { "/recover",              SND_RES, 0 },
  1676. #endif /* FTP_RESTART */
  1677. #ifdef RECURSIVE
  1678.     { "/recursive",            SND_REC, 0 },
  1679. #endif /* RECURSIVE */
  1680.     { "/rename-to",            SND_REN, CM_ARG },
  1681. #ifdef FTP_RESTART
  1682.     { "/restart",              SND_RES, CM_INV },
  1683. #endif /* FTP_RESTART */
  1684. #ifndef NOCSETS
  1685.     { "/server-character-set", SND_CSR, CM_ARG },
  1686. #endif /* NOCSETS */
  1687.     { "/server-rename-to",     SND_SRN, CM_ARG },
  1688.     { "/smaller-than",         SND_SMA, CM_ARG },
  1689. #ifdef RECURSIVE
  1690.     { "/subdirectories",       SND_REC, CM_INV },
  1691. #endif /* RECURSIVE */
  1692.     { "/text",                 SND_TXT, 0 },
  1693.     { "/tenex",                SND_TEN, 0 },
  1694. #ifndef NOCSETS
  1695.     { "/transparent",          SND_XPA, 0 },
  1696. #endif /* NOCSETS */
  1697.     { "/to-screen",            SND_MAI, 0 },
  1698. #ifdef DOUPDATE
  1699.     { "/update",               SND_UPD, CM_INV },
  1700. #endif /* DOUPDATE */
  1701.     { "", 0, 0 }
  1702. };
  1703. static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
  1704.  
  1705. static struct keytab delswi[] = {       /* FTP [M]DELETE switch table */
  1706.     { "/error-action",         SND_ERR, CM_ARG },
  1707.     { "/except",               SND_EXC, CM_ARG },
  1708.     { "/filenames",            SND_NAM, CM_ARG },
  1709.     { "/larger-than",          SND_LAR, CM_ARG },
  1710.     { "/nobackupfiles",        SND_NOB, 0 },
  1711. #ifdef UNIXOROSK
  1712.     { "/nodotfiles",           SND_NOD, 0 },
  1713. #endif /* UNIXOROSK */
  1714.     { "/quiet",                SND_SHH, 0 },
  1715. #ifdef RECURSIVE
  1716.     { "/recursive",            SND_REC, 0 },
  1717. #endif /* RECURSIVE */
  1718.     { "/smaller-than",         SND_SMA, CM_ARG },
  1719. #ifdef RECURSIVE
  1720.     { "/subdirectories",       SND_REC, CM_INV },
  1721. #endif /* RECURSIVE */
  1722.     { "", 0, 0 }
  1723. };
  1724. static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
  1725.  
  1726. static struct keytab fntab[] = {        /* Filename conversion keyword table */
  1727.     { "automatic",    2, CNV_AUTO },
  1728.     { "converted",    1, CNV_CNV  },
  1729.     { "literal",      0, CNV_LIT  }
  1730. };
  1731. static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
  1732.  
  1733. static struct keytab ftptyp[] = {       /* SET FTP TYPE table */
  1734.     { "ascii",        FTT_ASC, 0 },
  1735.     { "binary",       FTT_BIN, 0 },
  1736.     { "tenex",        FTT_TEN, 0 },
  1737.     { "text",         FTT_ASC, CM_INV },
  1738.     { "", 0, 0 }
  1739. };
  1740. static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
  1741.  
  1742. #ifdef FTP_SECURITY
  1743. static struct keytab ftppro[] = {       /* SET FTP PROTECTION-LEVEL table */
  1744.     { "clear",        FPL_CLR, 0 },
  1745.     { "confidential", FPL_CON, 0 },
  1746.     { "private",      FPL_PRV, 0 },
  1747.     { "safe",         FPL_SAF, 0 },
  1748.     { "", 0, 0 }
  1749. };
  1750. static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
  1751. #endif /* FTP_SECURITY */
  1752.  
  1753. /* Definitions for FTP from RFC765. */
  1754.  
  1755. /* Reply codes */
  1756.  
  1757. #define REPLY_PRELIM    1               /* Positive preliminary */
  1758. #define REPLY_COMPLETE  2               /* Positive completion */
  1759. #define REPLY_CONTINUE  3               /* Positive intermediate */
  1760. #define REPLY_TRANSIENT 4               /* Transient negative completion */
  1761. #define REPLY_ERROR     5               /* Permanent negative completion */
  1762. #define REPLY_SECURE    6               /* Security encoded message */
  1763.  
  1764. /* Form codes and names */
  1765.  
  1766. #define FORM_N 1                        /* Non-print */
  1767. #define FORM_T 2                        /* Telnet format effectors */
  1768. #define FORM_C 3                        /* Carriage control (ASA) */
  1769.  
  1770. /* Structure codes and names */
  1771.  
  1772. #define STRU_F 1                        /* File (no record structure) */
  1773. #define STRU_R 2                        /* Record structure */
  1774. #define STRU_P 3                        /* Page structure */
  1775.  
  1776. /* Mode types and names */
  1777.  
  1778. #define MODE_S 1                        /* Stream */
  1779. #define MODE_B 2                        /* Block */
  1780. #define MODE_C 3                        /* Compressed */
  1781.  
  1782. /* Protection levels and names */
  1783.  
  1784. #define PROT_C 1                        /* Clear */
  1785. #define PROT_S 2                        /* Safe */
  1786. #define PROT_P 3                        /* Private */
  1787. #define PROT_E 4                        /* Confidential */
  1788.  
  1789. #ifdef COMMENT                          /* Not used */
  1790. #ifdef FTP_NAMES
  1791. char *strunames[]  =  {"0", "File",     "Record", "Page" };
  1792. char *formnames[]  =  {"0", "Nonprint", "Telnet", "Carriage-control" };
  1793. char *modenames[]  =  {"0", "Stream",   "Block",  "Compressed" };
  1794. char *levelnames[] =  {"0", "Clear",    "Safe",   "Private",  "Confidential" };
  1795. #endif /* FTP_NAMES */
  1796.  
  1797. /* Record Tokens */
  1798.  
  1799. #define REC_ESC '\377'                  /* Record-mode Escape */
  1800. #define REC_EOR '\001'                  /* Record-mode End-of-Record */
  1801. #define REC_EOF '\002'                  /* Record-mode End-of-File */
  1802.  
  1803. /* Block Header */
  1804.  
  1805. #define BLK_EOR           0x80          /* Block is End-of-Record */
  1806. #define BLK_EOF           0x40          /* Block is End-of-File */
  1807. #define BLK_REPLY_ERRORS  0x20          /* Block might have errors */
  1808. #define BLK_RESTART       0x10          /* Block is Restart Marker */
  1809. #define BLK_BYTECOUNT 2                 /* Bytes in this block */
  1810. #endif /* COMMENT */
  1811.  
  1812. #define RADIX_ENCODE 0                  /* radix_encode() function codes */
  1813. #define RADIX_DECODE 1
  1814.  
  1815. /*
  1816.   The default setpbsz() value in the Unix FTP client is 1<<20 (1MB).  This
  1817.   results in a serious performance degradation due to the increased number
  1818.   of page faults and the inability to overlap encrypt/decrypt, file i/o, and
  1819.   network i/o.  So instead we set the value to 1<<13 (8K), about half the size
  1820.   of the typical TCP window.  Maybe we should add a command to allow the value
  1821.   to be changed.
  1822. */
  1823. #define DEFAULT_PBSZ 1<<13
  1824.  
  1825. /* Prototypes */
  1826.  
  1827. _PROTOTYP(int remtxt, (char **) );
  1828. _PROTOTYP(char * gskreason, (int) );
  1829. _PROTOTYP(static int ftpclose,(void));
  1830. _PROTOTYP(static int zzsend, (int, CHAR));
  1831. _PROTOTYP(static int getreply,(int,int,int,int,int));
  1832. _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
  1833. _PROTOTYP(static int setpbsz,(unsigned int));
  1834. _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
  1835.   int,int,char *,int,int,int));
  1836. _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
  1837. _PROTOTYP(static int fts_cpl,(int));
  1838. _PROTOTYP(static int fts_dpl,(int));
  1839. #ifdef FTP_SECURITY
  1840. _PROTOTYP(static int ftp_auth, (void));
  1841. #endif /* FTP_SECURITY */
  1842. _PROTOTYP(static int ftp_user, (char *, char *, char *));
  1843. _PROTOTYP(static int ftp_login, (char *));
  1844. _PROTOTYP(static int ftp_reset, (void));
  1845. _PROTOTYP(static int ftp_rename, (char *, char *));
  1846. _PROTOTYP(static int ftp_umask, (char *));
  1847. _PROTOTYP(static int secure_flush, (int));
  1848. #ifdef COMMENT
  1849. _PROTOTYP(static int secure_putc, (char, int));
  1850. #endif /* COMMENT */
  1851. _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
  1852. _PROTOTYP(static int scommand, (char *));
  1853. _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
  1854. _PROTOTYP(static int secure_getc, (int, int));
  1855. _PROTOTYP(static int secure_getbyte, (int, int));
  1856. _PROTOTYP(static int secure_read, (int, char *, int));
  1857. _PROTOTYP(static int initconn, (void));
  1858. _PROTOTYP(static int dataconn, (char *));
  1859. _PROTOTYP(static int setprotbuf,(unsigned int));
  1860. _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
  1861.  
  1862. _PROTOTYP(static char * radix_error,(int));
  1863. _PROTOTYP(static char * ftp_hookup,(char *, int, int));
  1864. _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
  1865.  
  1866. _PROTOTYP(static VOID mlsreset, (void));
  1867. _PROTOTYP(static VOID secure_error, (char *fmt, ...));
  1868. _PROTOTYP(static VOID lostpeer, (void));
  1869. _PROTOTYP(static VOID cancel_remote, (int));
  1870. _PROTOTYP(static VOID changetype, (int, int));
  1871.  
  1872. _PROTOTYP(static sigtype cmdcancel, (int));
  1873.  
  1874. #ifdef FTP_SRP
  1875. _PROTOTYP(static int srp_reset, ());
  1876. _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
  1877. _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
  1878. _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
  1879. _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
  1880. _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
  1881. _PROTOTYP(static int srp_selcipher, (char *));
  1882. _PROTOTYP(static int srp_selhash, (char *));
  1883. #endif /* FTP_SRP */
  1884.  
  1885. #ifdef FTP_GSSAPI
  1886. _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
  1887. #endif /* FTP_GSSAPI */
  1888.  
  1889. /*  D O F T P A R G  --  Do an FTP command-line argument.  */
  1890.  
  1891. #ifdef FTP_SECURITY
  1892. #ifndef NOICP
  1893. #define FT_NOGSS   1
  1894. #define FT_NOK4    2
  1895. #define FT_NOSRP   3
  1896. #define FT_NOSSL   4
  1897. #define FT_NOTLS   5
  1898. #define FT_CERTFI  6
  1899. #define FT_OKCERT  7
  1900. #define FT_DEBUG   8
  1901. #define FT_KEY     9
  1902. #define FT_SECURE 10
  1903. #define FT_VERIFY 11
  1904.  
  1905. static struct keytab ftpztab[] = {
  1906.     { "!gss",    FT_NOGSS,  0 },
  1907.     { "!krb4",   FT_NOK4,   0 },
  1908.     { "!srp",    FT_NOSRP,  0 },
  1909.     { "!ssl",    FT_NOSSL,  0 },
  1910.     { "!tls",    FT_NOTLS,  0 },
  1911.     { "cert",    FT_CERTFI, CM_ARG },
  1912.     { "certsok", FT_OKCERT, 0 },
  1913.     { "debug",   FT_DEBUG,  0 },
  1914.     { "key",     FT_KEY,    CM_ARG },
  1915.     { "nogss",   FT_NOGSS,  0 },
  1916.     { "nokrb4",  FT_NOK4,   0 },
  1917.     { "nosrp",   FT_NOSRP,  0 },
  1918.     { "nossl",   FT_NOSSL,  0 },
  1919.     { "notls",   FT_NOTLS,  0 },
  1920. #ifdef COMMENT
  1921.     { "secure",  FT_SECURE, 0 },
  1922. #endif /* COMMENT */
  1923.     { "verify",  FT_VERIFY, CM_ARG },
  1924.     { "", 0, 0 }
  1925. };
  1926. static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
  1927.  
  1928. /*
  1929.   The following cipher and hash tables should be replaced with
  1930.   dynamicly created versions based upon the linked library.
  1931. */
  1932. #define SRP_BLOWFISH_ECB    1
  1933. #define SRP_BLOWFISH_CBC    2
  1934. #define SRP_BLOWFISH_CFB64  3
  1935. #define SRP_BLOWFISH_OFB64  4
  1936. #define SRP_CAST5_ECB       5
  1937. #define SRP_CAST5_CBC       6
  1938. #define SRP_CAST5_CFB64     7
  1939. #define SRP_CAST5_OFB64     8
  1940. #define SRP_DES_ECB         9
  1941. #define SRP_DES_CBC        10
  1942. #define SRP_DES_CFB64      11
  1943. #define SRP_DES_OFB64      12
  1944. #define SRP_DES3_ECB       13
  1945. #define SRP_DES3_CBC       14
  1946. #define SRP_DES3_CFB64     15
  1947. #define SRP_DES3_OFB64     16
  1948.  
  1949. static struct keytab ciphertab[] = {
  1950.     { "blowfish_ecb",   SRP_BLOWFISH_ECB,   0 },
  1951.     { "blowfish_cbc",   SRP_BLOWFISH_CBC,   0 },
  1952.     { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
  1953.     { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
  1954.     { "cast5_ecb",      SRP_CAST5_ECB,      0 },
  1955.     { "cast5_cbc",      SRP_CAST5_CBC,      0 },
  1956.     { "cast5_cfb64",    SRP_CAST5_CFB64,    0 },
  1957.     { "cast5_ofb64",    SRP_CAST5_OFB64,    0 },
  1958.     { "des_ecb",        SRP_DES_ECB,        0 },
  1959.     { "des_cbc",        SRP_DES_CBC,        0 },
  1960.     { "des_cfb64",      SRP_DES_CFB64,      0 },
  1961.     { "des_ofb64",      SRP_DES_OFB64,      0 },
  1962.     { "des3_ecb",       SRP_DES3_ECB,       0 },
  1963.     { "des3_cbc",       SRP_DES3_CBC,       0 },
  1964.     { "des3_cfb64",     SRP_DES3_CFB64,     0 },
  1965.     { "des3_ofb64",     SRP_DES3_OFB64,     0 },
  1966.     { "none",           0, 0 },
  1967.     { "", 0, 0 }
  1968. };
  1969. static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
  1970.  
  1971. #define SRP_MD5  1
  1972. #define SRP_SHA  2
  1973. static struct keytab hashtab[] = {
  1974.     { "md5",              SRP_MD5,        0 },
  1975.     { "none",             0,              0 },
  1976.     { "sha",              SRP_SHA,        0 },
  1977.     { "", 0, 0 }
  1978. };
  1979. static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
  1980. #endif /* NOICP */
  1981. #endif /* FTP_SECURITY */
  1982.  
  1983. static char *
  1984. strval(s1,s2) char * s1, * s2; {
  1985.     if (!s1) s1 = "";
  1986.     if (!s2) s2 = "";
  1987.     return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
  1988. }
  1989.  
  1990. #ifndef NOCSETS
  1991. static char * rfnptr = NULL;
  1992. static int rfnlen = 0;
  1993. static char rfnbuf[RFNBUFSIZ];          /* Remote filename translate buffer */
  1994. static char * xgnbp = NULL;
  1995.  
  1996. static int
  1997. strgetc() {                             /* Helper function for xgnbyte() */
  1998.     int c;
  1999.     if (!xgnbp)
  2000.       return(-1);
  2001.     if (!*xgnbp)
  2002.       return(-1);
  2003.     c = (unsigned) *xgnbp++;
  2004.     return(((unsigned) c) & 0xff);
  2005. }
  2006.  
  2007. static int                              /* Helper function for xpnbyte() */
  2008. #ifdef CK_ANSIC
  2009. strputc(char c)
  2010. #else
  2011. strputc(c) char c;
  2012. #endif /* CK_ANSIC */
  2013. {
  2014.     rfnlen = rfnptr - rfnbuf;
  2015.     if (rfnlen >= (RFNBUFSIZ - 1))
  2016.       return(-1);
  2017.     *rfnptr++ = c;
  2018.     *rfnptr = NUL;
  2019.     return(0);
  2020. }
  2021.  
  2022. static int
  2023. #ifdef CK_ANSIC
  2024. xprintc(char c)
  2025. #else
  2026. xprintc(c) char c;
  2027. #endif /* CK_ANSIC */
  2028. {
  2029.     printf("%c",c);
  2030.     return(0);
  2031. }
  2032.  
  2033. static VOID
  2034. bytswap(c0,c1) int * c0, * c1; {
  2035.     int t;
  2036.     t = *c0;
  2037.     *c0 = *c1;
  2038.     *c1 = t;
  2039. }
  2040. #endif /* NOCSETS */
  2041.  
  2042. #ifdef CKLOGDIAL
  2043. char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
  2044. int ftplogactive = 0;
  2045. long ftplogprev = 0L;
  2046.  
  2047. VOID
  2048. ftplogend() {
  2049.     extern int dialog;
  2050.     extern char diafil[];
  2051.     long d1, d2, t1, t2;
  2052.     char buf[32], * p;
  2053.  
  2054.     debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
  2055.     debug(F110,"ftp cx log buf",ftplogbuf,0);
  2056.  
  2057.     if (!ftplogactive || !ftplogbuf[0]) /* No active record */
  2058.       return;
  2059.  
  2060.     ftplogactive = 0;                   /* Record is not active */
  2061.  
  2062.     d1 = mjd((char *)ftplogbuf);        /* Get start date of this session */
  2063.     ckstrncpy(buf,ckdate(),31);         /* Get current date */
  2064.     d2 = mjd(buf);                      /* Convert them to mjds */
  2065.     p = ftplogbuf;                      /* Get start time */
  2066.     p[11] = NUL;
  2067.     p[14] = NUL;                        /* Convert to seconds */
  2068.     t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
  2069.     p[11] = ':';
  2070.     p[14] = ':';
  2071.     p = buf;                            /* Get end time */
  2072.     p[11] = NUL;
  2073.     p[14] = NUL;
  2074.     t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
  2075.     t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
  2076.     if (t2 > -1L) {
  2077.         ftplogprev = t2;
  2078.         p = hhmmss(t2);
  2079.         ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
  2080.         ckstrncat(ftplogbuf,p,CXLOGBUFL);
  2081.     } else
  2082.       ftplogprev = 0L;
  2083.     debug(F101,"ftp cx log dialog","",dialog);
  2084.     if (dialog) {                       /* If logging */
  2085.         int x;
  2086.         x = diaopn(diafil,1,1);         /* Open log in append mode */
  2087.         if (x > 0) {
  2088.             debug(F101,"ftp cx log open","",x);
  2089.             x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
  2090.             debug(F101,"ftp cx log write","",x);
  2091.             x = zclose(ZDIFIL);         /* Close the log */
  2092.             debug(F101,"ftp cx log close","",x);
  2093.         }
  2094.     }
  2095. }
  2096.  
  2097. VOID
  2098. dologftp() {
  2099.     ftplogend();                        /* Previous session not closed out? */
  2100.     ftplogprev = 0L;
  2101.     ftplogactive = 1;                   /* Record is active */
  2102.  
  2103.     ckmakxmsg(ftplogbuf,CXLOGBUFL,
  2104.               ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
  2105.               " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
  2106.               " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
  2107.     debug(F110,"ftp cx log begin",ftplogbuf,0);
  2108. }
  2109. #endif /* CKLOGDIAL */
  2110.  
  2111. static char * dummy[2] = { NULL, NULL };
  2112.  
  2113. static struct keytab modetab[] = {
  2114.     { "active",  0, 0 },
  2115.     { "passive", 1, 0 }
  2116. };
  2117.  
  2118. #ifndef NOCMDL
  2119. int                                     /* Called from ckuusy.c */
  2120. #ifdef CK_ANSIC
  2121. doftparg(char c)
  2122. #else
  2123. doftparg(c) char c;
  2124. #endif /* CK_ANSIC */
  2125. /* doftparg */ {
  2126.     int x, z;
  2127.     char *xp;
  2128.     extern char **xargv, *xarg0;
  2129.     extern int xargc, stayflg, haveftpuid;
  2130.     extern char uidbuf[];
  2131.  
  2132.     xp = *xargv+1;                      /* Pointer for bundled args */
  2133.     while (c) {
  2134.         if (ckstrchr("MuDPkcHzm",c)) {  /* Options that take arguments */
  2135.             if (*(xp+1)) {
  2136.                 fatal("?Invalid argument bundling");
  2137.             }
  2138.             xargv++, xargc--;
  2139.             if ((xargc < 1) || (**xargv == '-')) {
  2140.                 fatal("?Required argument missing");
  2141.             }
  2142.         }
  2143.         switch (c) {                    /* Big switch on arg */
  2144.           case 'h':                     /* help */
  2145.            printf("C-Kermit's FTP client command-line personality.  Usage:\n");
  2146.             printf("  %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
  2147.             printf("Options:\n");
  2148.             printf("  -h           = help (this message)\n");
  2149.             printf("  -m mode      = \"passive\" (default) or \"active\"\n");
  2150.             printf("  -u name      = username for autologin (or -M)\n");
  2151.             printf("  -P password  = password for autologin (RISKY)\n");
  2152.             printf("  -A           = autologin anonymously\n");
  2153.             printf("  -D directory = cd after autologin\n");
  2154.             printf("  -b           = force binary mode\n");
  2155.             printf("  -a           = force text (\"ascii\") mode (or -T)\n");
  2156.             printf("  -d           = debug (double to add timestamps)\n");
  2157.             printf("  -n           = no autologin\n");
  2158.             printf("  -v           = verbose (default)\n");
  2159.             printf("  -q           = quiet\n");
  2160.             printf("  -S           = Stay (issue command prompt when done)\n");
  2161.             printf("  -Y           = do not execute Kermit init file\n");
  2162.             printf("  -p files     = files to put after autologin (or -s)\n");
  2163.             printf("  -g files     = files to get after autologin\n");
  2164.             printf("  -R           = recursive (for use with -p)\n");
  2165.  
  2166. #ifdef FTP_SECURITY
  2167.             printf("\nSecurity options:\n");
  2168.             printf("  -k realm     = Kerberos 4 realm\n");
  2169.             printf("  -f           = Kerboros 5 credentials forwarding\n");
  2170.             printf("  -x           = autoencryption mode\n");
  2171.             printf("  -c cipher    = SRP cipher type\n");
  2172.             printf("  -H hash      = SRP encryption hash\n");
  2173.             printf("  -z option    = Security options\n");
  2174. #endif /* FTP_SECURITY */
  2175.  
  2176.             printf("\n-p or -g, if given, should be last.  Example:\n");
  2177.             printf("  ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
  2178.  
  2179.             doexit(GOOD_EXIT,-1);
  2180.             break;
  2181.  
  2182.           case 'R':                     /* Recursive */
  2183.             recursive = 1;
  2184.             break;
  2185.  
  2186.           case 'd':                     /* Debug */
  2187. #ifdef DEBUG
  2188.             if (deblog) {
  2189.                 extern int debtim;
  2190.                 debtim = 1;
  2191.             } else {
  2192.                 deblog = debopn("debug.log",0);
  2193.                 debok = 1;
  2194.             }
  2195. #endif /* DEBUG */
  2196.             /* fall thru on purpose */
  2197.  
  2198.           case 't':                     /* Trace */
  2199.             ftp_deb++;
  2200.             break;
  2201.  
  2202.           case 'n':                     /* No autologin */
  2203.             ftp_log = 0;
  2204.             break;
  2205.  
  2206.           case 'i':                     /* No prompt */
  2207.           case 'v':                     /* Verbose */
  2208.             break;                      /* (ignored) */
  2209.  
  2210.           case 'q':                     /* Quiet */
  2211.             quiet = 1;
  2212.             break;
  2213.  
  2214.           case 'S':                     /* Stay */
  2215.             stayflg = 1;
  2216.             break;
  2217.  
  2218.           case 'M':
  2219.           case 'u':                     /* My User Name */
  2220.             if ((int)strlen(*xargv) > 63) {
  2221.                 fatal("username too long");
  2222.             }
  2223.             ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
  2224.             haveftpuid = 1;
  2225.             break;
  2226.  
  2227.           case 'A':
  2228.             ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
  2229.             haveftpuid = 1;
  2230.             break;
  2231.  
  2232.           case 'T':                     /* Text */
  2233.           case 'a':                     /* "ascii" */
  2234.           case 'b':                     /* Binary */
  2235.             binary = (c == 'b') ? FTT_BIN : FTT_ASC;
  2236.             ftp_xfermode = XMODE_M;
  2237.             filepeek = 0;
  2238.             patterns = 0;
  2239.             break;
  2240.  
  2241.           case 'g':                     /* Get */
  2242.           case 'p':                     /* Put */
  2243.           case 's': {                   /* Send (= Put) */
  2244.               int havefiles, rc;
  2245.               if (ftp_action) {
  2246.                   fatal("Only one FTP action at a time please");
  2247.               }
  2248.               if (*(xp+1)) {
  2249.                   fatal("invalid argument bundling after -s");
  2250.               }
  2251.               nfils = 0;                /* Initialize file counter */
  2252.               havefiles = 0;            /* Assume nothing to send  */
  2253.               cmlist = xargv + 1;       /* Remember this pointer */
  2254.  
  2255.               while (++xargv, --xargc > 0) { /* Traverse the list */
  2256.                   if (c == 'g') {
  2257.                       havefiles++;
  2258.                       nfils++;
  2259.                       continue;
  2260.                   }
  2261. #ifdef RECURSIVE
  2262.                   if (!strcmp(*xargv,".")) {
  2263.                       havefiles = 1;
  2264.                       nfils++;
  2265.                       recursive = 1;
  2266.                   } else
  2267. #endif /* RECURSIVE */
  2268.                     if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
  2269.                         if  (rc != -2)
  2270.                           havefiles = 1;
  2271.                         nfils++;
  2272.                     } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
  2273.                         havefiles = 1;
  2274.                         nfils++;
  2275.                     }
  2276.               }
  2277.               xargc++, xargv--;         /* Adjust argv/argc */
  2278.               if (!havefiles) {
  2279.                   if (c == 'g') {
  2280.                       fatal("No files to put");
  2281.                   } else {
  2282.                       fatal("No files to get");
  2283.                   }
  2284.               }
  2285.               ftp_action = c;
  2286.               break;
  2287.           }
  2288.           case 'D':                     /* Directory */
  2289.             makestr(&ftp_rdir,*xargv);
  2290.             break;
  2291.  
  2292.           case 'm':                     /* Mode (Active/Passive */
  2293.             ftp_psv = lookup(modetab,*xargv,2,NULL);
  2294.             if (ftp_psv < 0) fatal("Invalid mode");
  2295.             break;
  2296.  
  2297.           case 'P':
  2298.             makestr(&ftp_tmp,*xargv);   /* You-Know-What */
  2299.             break;
  2300.  
  2301.           case 'Y':                     /* No initialization file */
  2302.             break;                      /* (already done in prescan) */
  2303.  
  2304. #ifdef CK_URL
  2305.           case 'U': {                   /* URL */
  2306.               /* These are set by urlparse() - any not set are NULL */
  2307.               if (g_url.hos) {
  2308. /*
  2309.   Kermit has accepted host:port notation since many years before URLs were
  2310.   invented.  Unfortunately, URLs conflict with this notation.  Thus "ftp
  2311.   host:449" looks like a URL and results in service = host and host = 449.
  2312.   Here we try to catch this situation transparently to the user.
  2313. */
  2314.                   if (ckstrcmp(g_url.svc,"ftp",-1,0)
  2315. #ifdef CK_SSL
  2316.                        && ckstrcmp(g_url.svc,"ftps",-1,0)
  2317. #endif /* CK_SSL */
  2318.                        ) {
  2319.                       if (!g_url.usr &&
  2320.                           !g_url.psw &&
  2321.                           !g_url.por &&
  2322.                           !g_url.pth) {
  2323.                           g_url.por = g_url.hos;
  2324.                           g_url.hos = g_url.svc;
  2325.                           g_url.svc = "ftp";
  2326.                       } else {
  2327.                           ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
  2328.                                    g_url.svc," host=",g_url.hos);
  2329.                           fatal(tmpbuf);
  2330.                       }
  2331.                   }
  2332.                   makestr(&ftp_host,g_url.hos);
  2333.                   if (g_url.usr) {
  2334.                       haveftpuid = 1;
  2335.                       ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
  2336.                       makestr(&ftp_logname,uidbuf);
  2337.                   }
  2338.                   if (g_url.psw) {
  2339.                       makestr(&ftp_tmp,g_url.psw);
  2340.                   }
  2341.                   if (g_url.pth) {
  2342.                       if (!g_url.usr) {
  2343.                           haveftpuid = 1;
  2344.                           ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
  2345.                           makestr(&ftp_logname,uidbuf);
  2346.                       }
  2347.                       if (ftp_action) {
  2348.                           fatal("Only one FTP action at a time please");
  2349.                       }
  2350.                       if (!stayflg)
  2351.                         quiet = 1;
  2352.                       nfils = 1;
  2353.                       dummy[0] = g_url.pth;
  2354.                       cmlist = dummy;
  2355.                       ftp_action = 'g';
  2356.                   }
  2357.                   xp = NULL;
  2358.                   haveurl = 1;
  2359.               }
  2360.               break;
  2361.           }
  2362. #endif /* CK_URL */
  2363.  
  2364. #ifdef FTP_SECURITY
  2365.           case 'k': {                   /* K4 Realm */
  2366. #ifdef FTP_KRB4
  2367.               ckstrncpy(ftp_realm,*xargv, REALM_SZ);
  2368. #endif /* FTP_KRB4 */
  2369.               if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
  2370.               break;
  2371.           }
  2372.           case 'f': {
  2373. #ifdef FTP_GSSAPI
  2374.               ftp_cfw = 1;
  2375.               if (ftp_deb) printf("K5 Credentials Forwarding\n");
  2376. #else /* FTP_GSSAPI */
  2377.               printf("K5 Credentials Forwarding not supported\n");
  2378. #endif /* FTP_GSSAPI */
  2379.               break;
  2380.           }
  2381.           case 'x': {
  2382.               ftp_cry = 1;
  2383.               if (ftp_deb) printf("Autoencryption\n");
  2384.               break;
  2385.           }
  2386.           case 'c': {                   /* Cipher */
  2387. #ifdef FTP_SRP
  2388.               if (!srp_selcipher(*xargv)) {
  2389.                   if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
  2390.               } else
  2391.                 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
  2392. #else /* FTP_SRP */
  2393.               printf("?SRP not supported\n");
  2394. #endif /* FTP_SRP */
  2395.               break;
  2396.           }
  2397.           case 'H': {
  2398. #ifdef FTP_SRP
  2399.               if (!srp_selhash(*xargv)) {
  2400.                   if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
  2401.               } else
  2402.                 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
  2403. #else /* FTP_SRP */
  2404.               printf("?SRP not supported\n");
  2405. #endif /* FTP_SRP */
  2406.               break;
  2407.           }
  2408.           case 'z': {
  2409.               /* *xargv contains a value of the form tag=value */
  2410.               /* we need to lookup the tag and save the value  */
  2411.               char * p = NULL, * q = NULL;
  2412.               makestr(&p,*xargv);
  2413.               y = ckindex("=",p,0,0,1);
  2414.               if (y > 0)
  2415.                 p[y-1] = '\0';
  2416.               x = lookup(ftpztab,p,nftpztab,&z);
  2417.               if (x < 0) {
  2418.                   printf("?Invalid security option: \"%s\"\n",p);
  2419.               } else {
  2420.                   if (ftp_deb)
  2421.             printf("Security option: \"%s",p);
  2422.                   if (ftpztab[z].flgs & CM_ARG) {
  2423.                       if (y <= 0)
  2424.                         fatal("?Missing required value");
  2425.                       q = &p[y];
  2426.                       if (!*q)
  2427.                         fatal("?Missing required value");
  2428.                       if (ftp_deb)
  2429.             printf("=%s\"",q);
  2430.                   }
  2431.                   switch (ftpztab[z].kwval) { /* -z options w/args */
  2432.                     case FT_NOGSS:
  2433. #ifdef FTP_GSSAPI
  2434.                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
  2435.                           if (ftp_auth_type[z] == FTA_GK5) {
  2436.                               for (y = z;
  2437.                                    y < (FTPATYPS-1) && ftp_auth_type[y];
  2438.                                    y++
  2439.                                    )
  2440.                                 ftp_auth_type[y] = ftp_auth_type[y+1];
  2441.                               ftp_auth_type[FTPATYPS-1] = 0;
  2442.                               break;
  2443.                           }
  2444.                       }
  2445. #endif /* FTP_GSSAPI */
  2446.                       break;
  2447.                     case FT_NOK4:
  2448. #ifdef FTP_KRB4
  2449.                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
  2450.                           if (ftp_auth_type[z] == FTA_K4) {
  2451.                               for (y = z;
  2452.                                    y < (FTPATYPS-1) && ftp_auth_type[y];
  2453.                                    y++
  2454.                                    )
  2455.                                 ftp_auth_type[y] = ftp_auth_type[y+1];
  2456.                               ftp_auth_type[FTPATYPS-1] = 0;
  2457.                               break;
  2458.                           }
  2459.                       }
  2460. #endif /* FTP_KRB4 */
  2461.                       break;
  2462.                     case FT_NOSRP:
  2463. #ifdef FTP_SRP
  2464.                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
  2465.                           if (ftp_auth_type[z] == FTA_SRP) {
  2466.                               for (y = z;
  2467.                                    y < (FTPATYPS-1) && ftp_auth_type[y];
  2468.                                    y++
  2469.                                    )
  2470.                                 ftp_auth_type[y] = ftp_auth_type[y+1];
  2471.                               ftp_auth_type[FTPATYPS-1] = 0;
  2472.                               break;
  2473.                           }
  2474.                       }
  2475. #endif /* FTP_SRP */
  2476.                       break;
  2477.                     case FT_NOSSL:
  2478. #ifdef CK_SSL
  2479.                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
  2480.                           if (ftp_auth_type[z] == FTA_SSL) {
  2481.                               for (y = z;
  2482.                                    y < (FTPATYPS-1) && ftp_auth_type[y];
  2483.                                    y++
  2484.                                    )
  2485.                                 ftp_auth_type[y] = ftp_auth_type[y+1];
  2486.                               ftp_auth_type[FTPATYPS-1] = 0;
  2487.                               break;
  2488.                           }
  2489.                       }
  2490. #endif /* CK_SSL */
  2491.                       break;
  2492.                     case FT_NOTLS:
  2493. #ifdef CK_SSL
  2494.                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
  2495.                           if (ftp_auth_type[z] == FTA_TLS) {
  2496.                               for (y = z;
  2497.                                    y < (FTPATYPS-1) && ftp_auth_type[y];
  2498.                                    y++
  2499.                                    )
  2500.                                 ftp_auth_type[y] = ftp_auth_type[y+1];
  2501.                               ftp_auth_type[FTPATYPS-1] = 0;
  2502.                               break;
  2503.                           }
  2504.                       }
  2505. #endif /* CK_SSL */
  2506.                       break;
  2507.                     case FT_CERTFI:
  2508. #ifdef CK_SSL
  2509.                       makestr(&ssl_rsa_cert_file,q);
  2510. #endif /* CK_SSL */
  2511.                       break;
  2512.                     case FT_OKCERT:
  2513. #ifdef CK_SSL
  2514.                       ssl_certsok_flag = 1;
  2515. #endif /* CK_SSL */
  2516.                       break;
  2517.                     case FT_DEBUG:
  2518. #ifdef DEBUG
  2519.                       if (deblog) {
  2520.                           extern int debtim;
  2521.                           debtim = 1;
  2522.                       } else {
  2523.                           deblog = debopn("debug.log",0);
  2524.                       }
  2525. #endif /* DEBUG */
  2526.                       break;
  2527.                     case FT_KEY:
  2528. #ifdef CK_SSL
  2529.                       makestr(&ssl_rsa_key_file,q);
  2530. #endif /* CK_SSL */
  2531.                       break;
  2532.                     case FT_SECURE:
  2533.                       /* no equivalent */
  2534.                       break;
  2535.                     case FT_VERIFY:
  2536. #ifdef CK_SSL
  2537.                       if (!rdigits(q))
  2538.                         printf("?Bad number: %s\n",q);
  2539.                       ssl_verify_flag = atoi(q);
  2540. #endif /* CK_SSL */
  2541.                       break;
  2542.                   }
  2543.               }
  2544.               if (ftp_deb) printf("\"\n");
  2545.               free(p);
  2546.               break;
  2547.           }
  2548. #endif /* FTP_SECURITY */
  2549.  
  2550.           default:
  2551.             fatal2(*xargv,
  2552.                    "unknown command-line option, type \"ftp -h\" for help"
  2553.                    );
  2554.         }
  2555.         if (!xp) break;
  2556.         c = *++xp;                      /* See if options are bundled */
  2557.     }
  2558.     return(0);
  2559. }
  2560. #endif /* NOCMDL */
  2561.  
  2562. int
  2563. ftpisconnected() {
  2564.     return(connected);
  2565. }
  2566.  
  2567. int
  2568. ftpisloggedin() {
  2569.     return(connected ? loggedin : 0);
  2570. }
  2571.  
  2572. int
  2573. ftpissecure() {
  2574.     return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
  2575. }
  2576.  
  2577. static VOID
  2578. ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
  2579.     if (displa && fdispla && !backgrd && !quiet && !out2screen) {
  2580.         if (!dpyactive) {
  2581.             ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
  2582.             dpyactive = 1;
  2583.         }
  2584.         ckscreen(n,c,z,s);
  2585.     }
  2586. }
  2587.  
  2588. #ifndef OS2
  2589. /*  g m s t i m e r  --  Millisecond timer */
  2590.  
  2591. long
  2592. gmstimer() {
  2593. #ifdef HAVE_MSECS
  2594.     /* For those versions of ztime() that also set global ztmsec. */
  2595.     char *p = NULL;
  2596.     long z;
  2597.     ztime(&p);
  2598.     if (!p) return(0L);
  2599.     if (!*p) return(0L);
  2600.     z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
  2601.     return(z * 1000 + ztmsec);
  2602. #else
  2603.     return((long)time(NULL) * 1000L);
  2604. #endif /* HAVE_MSECS */
  2605. }
  2606. #endif /* OS2 */
  2607.  
  2608. /*  d o s e t f t p  --  The SET FTP command  */
  2609.  
  2610. int
  2611. dosetftp() {
  2612.     int cx;
  2613.     if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
  2614.       return(cx);
  2615.     switch (cx) {
  2616.  
  2617.       case FTS_FNC:                     /* Filename collision action */
  2618.         if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
  2619.           return(x);
  2620.         if ((y = cmcfm()) < 0)
  2621.           return(y);
  2622.         ftp_fnc = x;
  2623.         return(1);
  2624.  
  2625.       case FTS_CNV:                     /* Filename conversion */
  2626.         if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
  2627.           return(x);
  2628.         if ((y = cmcfm()) < 0)
  2629.           return(y);
  2630.         ftp_cnv = x;
  2631.         return(1);
  2632.  
  2633.       case FTS_DBG:                     /* Debug messages */
  2634.         return(seton(&ftp_deb));
  2635.  
  2636.       case FTS_LOG:                     /* Auto-login */
  2637.         return(seton(&ftp_log));
  2638.  
  2639.       case FTS_PSV:                     /* Passive mode */
  2640.     return(dosetftppsv());
  2641.  
  2642.       case FTS_SPC:                     /* Send port commands */
  2643.         x = seton(&ftp_spc);
  2644.         if (x > 0) sendport = ftp_spc;
  2645.         return(x);
  2646.  
  2647.       case FTS_TYP:                     /* Type */
  2648.         if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
  2649.           return(x);
  2650.         if ((y = cmcfm()) < 0) return(y);
  2651.     ftp_typ = x;
  2652.     g_ftp_typ = x;
  2653.     tenex = (ftp_typ == FTT_TEN);
  2654.         return(1);
  2655.  
  2656.       case FTS_USN:                     /* Unique server names */
  2657.         return(seton(&ftp_usn));
  2658.  
  2659.       case FTS_VBM:                     /* Verbose mode */
  2660.         if ((x = seton(&ftp_vbm)) < 0)  /* Per-command copy */
  2661.           return(x);
  2662.         ftp_vbx = ftp_vbm;              /* Global sticky copy */
  2663.         return(x);
  2664.  
  2665.       case FTS_TST:                     /* "if (testing)" messages */
  2666.         return(seton(&testing));
  2667.  
  2668.       case FTS_PRM:                     /* Send permissions */
  2669.         return(setonaut(&ftp_prm));
  2670.  
  2671.       case FTS_AUT:                     /* Auto-authentication */
  2672.         return(seton(&ftp_aut));
  2673.  
  2674.       case FTS_ERR:                     /* Error action */
  2675.         if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
  2676.           return(x);
  2677.         if ((y = cmcfm()) < 0)
  2678.           return(y);
  2679.         ftp_err = x;
  2680.         return(success = 1);
  2681.  
  2682. #ifndef NOCSETS
  2683.       case FTS_XLA:                     /* Translation */
  2684.         return(seton(&ftp_xla));
  2685.  
  2686.       case FTS_CSR:                     /* Server charset */
  2687.         if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
  2688.           return(x);
  2689.         if ((y = cmcfm()) < 0)
  2690.           return(y);
  2691.         ftp_csr = x;
  2692.         ftp_xla = 1;                    /* Also enable translation */
  2693.         return(success = 1);
  2694. #endif /* NOCSETS */
  2695.  
  2696.       case FTS_GFT:
  2697.         return(seton(&get_auto));       /* GET-filetype-switching */
  2698.  
  2699.       case FTS_DAT:
  2700.         return(seton(&ftp_dates));      /* Set file dates */
  2701.  
  2702. #ifdef FTP_TIMEOUT
  2703.       case FTS_TMO:            /* Timeout */
  2704.         if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
  2705.           return(x);
  2706.         if ((y = cmcfm()) < 0)
  2707.           return(y);
  2708.     ftp_timeout = z;
  2709.     return(success = 1);
  2710. #endif    /* FTP_TIMEOUT */
  2711.  
  2712.       case FTS_STO: {            /* Server time offset */
  2713.       char * s, * p = NULL;
  2714.       long k;
  2715.       if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
  2716.         return(x);
  2717.       if (!strcmp(s,"+0")) {
  2718.           s = NULL;
  2719.       } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
  2720.           printf("?Invalid time offset\n");
  2721.           return(-9);
  2722.       }
  2723.       makestr(&p,s);        /* Make a safe copy the string */
  2724.       if ((x = cmcfm()) < 0) {    /* Get confirmation */
  2725.           if (p)
  2726.         makestr(&p,NULL);
  2727.           return(x);
  2728.       }
  2729.       fts_sto = p;            /* Confirmed - set the string. */
  2730.       return(success = 1);
  2731.       }
  2732.       case FTS_APW: {
  2733.       char * s;
  2734.       if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
  2735.         return(x);
  2736.       makestr(&ftp_apw, *s ? s : NULL);
  2737.       return(success = 1);
  2738.       }
  2739.  
  2740.       case FTS_BUG: {
  2741.           if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0) 
  2742.         return(x);
  2743.           switch (x) {
  2744. #ifdef CK_SSL
  2745.           case FTB_SV2:
  2746.         return seton(&ftp_bug_use_ssl_v2);
  2747. #endif /* CK_SSL */
  2748.           default:
  2749.         return(-2);
  2750.           }
  2751.       }
  2752.  
  2753. #ifdef FTP_SECURITY
  2754.       case FTS_CRY:                     /* Auto-encryption */
  2755.         return(seton(&ftp_cry));
  2756.  
  2757.       case FTS_CFW:                     /* Credential-forwarding */
  2758.         return(seton(&ftp_cfw));
  2759.  
  2760.       case FTS_CPL:                     /* Command protection level */
  2761.         if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
  2762.         if ((y = cmcfm()) < 0) return(y);
  2763.         success = fts_cpl(x);
  2764.         return(success);
  2765.  
  2766.       case FTS_DPL:                     /* Data protection level */
  2767.         if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
  2768.         if ((y = cmcfm()) < 0) return(y);
  2769.           success = fts_dpl(x);
  2770.           return(success);
  2771.  
  2772.       case FTS_ATP: {                   /* FTP Auth Type */
  2773.           int i, j, atypes[8];
  2774.  
  2775.           for (i = 0; i < 8; i++) {
  2776.               if ((y = cmkey(ftpauth,nftpauth,"",
  2777.                              (i == 0) ? "automatic" : "",
  2778.                              xxstring)) < 0) {
  2779.                   if (y == -3)
  2780.                     break;
  2781.                   return(y);
  2782.               }
  2783.               if (i > 0 && (y == FTA_AUTO)) {
  2784.                   printf("?Choice may only be used in first position.\r\n");
  2785.                   return(-9);
  2786.               }
  2787.               for (j = 0; j < i; j++) {
  2788.                   if (atypes[j] == y) {
  2789.                       printf("\r\n?Choice has already been used.\r\n");
  2790.                       return(-9);
  2791.                   }
  2792.               }
  2793.               atypes[i] = y;
  2794.               if (y == FTA_AUTO) {
  2795.                   i++;
  2796.                   break;
  2797.               }
  2798.           }
  2799.           if (i < 8)
  2800.             atypes[i] = 0;
  2801.           if ((z = cmcfm()) < 0)
  2802.             return(z);
  2803.           if (atypes[0] == FTA_AUTO) {
  2804.               i = 0;
  2805. #ifdef FTP_GSSAPI
  2806.               ftp_auth_type[i++] = FTA_GK5;
  2807. #endif /* FTP_GSSAPI */
  2808. #ifdef FTP_SRP
  2809.               ftp_auth_type[i++] = FTA_SRP;
  2810. #endif /* FTP_SRP */
  2811. #ifdef FTP_KRB4
  2812.               ftp_auth_type[i++] = FTA_K4;
  2813. #endif /* FTP_KRB4 */
  2814. #ifdef CK_SSL
  2815.               ftp_auth_type[i++] = FTA_TLS;
  2816.               ftp_auth_type[i++] = FTA_SSL;
  2817. #endif /* CK_SSL */
  2818.               ftp_auth_type[i] = 0;
  2819.           } else {
  2820.               for (i = 0; i < 8; i++)
  2821.                 ftp_auth_type[i] = atypes[i];
  2822.           }
  2823.           return(success = 1);
  2824.       }
  2825.  
  2826.       case FTS_SRP:
  2827. #ifdef FTP_SRP
  2828.         if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
  2829.           return(x);
  2830.         switch (x) {
  2831.           case SRP_CIPHER:
  2832.             if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
  2833.               return(x);
  2834.             if ((z = cmcfm()) < 0)
  2835.               return(z);
  2836.             success = !srp_selcipher(ciphertab[x].kwd);
  2837.             return(success);
  2838.           case SRP_HASH:
  2839.             if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
  2840.               return(x);
  2841.             if ((z = cmcfm()) < 0)
  2842.               return(z);
  2843.             success = !srp_selhash(hashtab[x].kwd);
  2844.             return(success = 1);
  2845.           default:
  2846.             if ((z = cmcfm()) < 0)
  2847.               return(z);
  2848.             return(-2);
  2849.         }
  2850. #else /* FTP_SRP */
  2851.         if ((z = cmcfm()) < 0)
  2852.           return(z);
  2853.         return(-2);
  2854. #endif /* FTP_SRP */
  2855. #endif /* FTP_SECURITY */
  2856.  
  2857.       case FTS_DIS:
  2858.     doxdis(2);            /* 2 == ftp */
  2859.         return(success = 1);
  2860.  
  2861.       default:
  2862.         return(-2);
  2863.     }
  2864. }
  2865.  
  2866. int
  2867. ftpbye() {
  2868.     int x;
  2869.     if (!connected)
  2870.       return(1);
  2871.     if (testing)
  2872.       printf(" ftp closing %s...\n",ftp_host);
  2873.     x = ftpclose();
  2874.     return((x > -1) ? 1 : 0);
  2875. }
  2876.  
  2877. /*  o p e n f t p  --  Parse FTP hostname & port and open */
  2878.  
  2879. static int
  2880. openftp(s,opn_tls) char * s; int opn_tls; {
  2881.     char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
  2882.     int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
  2883.     int haveuser = 0;
  2884.     struct FDB sw, fl, cm;
  2885.     extern int nnetdir;                 /* Network services directory */
  2886.     extern int nhcount;                 /* Lookup result */
  2887.     extern char *nh_p[];                /* Network directory entry pointers */
  2888.     extern char *nh_p2[];               /* Network directory entry nettype */
  2889.  
  2890.     if (!s) return(-2);
  2891.     if (!*s) return(-2);
  2892.  
  2893.     makestr(&hostname,s);
  2894.     hostsave = hostname;
  2895.     makestr(&ftp_logname,NULL);
  2896.     anonymous = 0;
  2897.     noinit = 0;
  2898.  
  2899.     debug(F110,"ftp open",hostname,0);
  2900.  
  2901.     if (sav_psv > -1) {                 /* Restore prevailing active/passive */
  2902.         ftp_psv = sav_psv;              /* selection in case it was */
  2903.         sav_psv = -1;                   /* temporarily overriden by a switch */
  2904.     }
  2905.     if (sav_log > -1) {                 /* Ditto for autologin */
  2906.         ftp_log = sav_log;
  2907.         sav_log = -1;
  2908.     }
  2909.     cmfdbi(&sw,                         /* Switches */
  2910.            _CMKEY,
  2911.            "Service name or port;\n or switch",
  2912.            "",                          /* default */
  2913.            "",                          /* addtl string data */
  2914.            nftpswi,                     /* addtl numeric data 1: tbl size */
  2915.            4,                           /* addtl numeric data 2: none */
  2916.            xxstring,                    /* Processing function */
  2917.            ftpswitab,                   /* Keyword table */
  2918.            &fl                          /* Pointer to next FDB */
  2919.            );
  2920.     cmfdbi(&fl,                         /* A host name or address */
  2921.            _CMFLD,                      /* fcode */
  2922.            "",                          /* help */
  2923.            "xYzBoo",                    /* default */
  2924.            "",                          /* addtl string data */
  2925.            0,                           /* addtl numeric data 1 */
  2926.            0,                           /* addtl numeric data 2 */
  2927.            xxstring,
  2928.            NULL,
  2929.            &cm
  2930.            );
  2931.     cmfdbi(&cm,                         /* Command confirmation */
  2932.            _CMCFM,
  2933.            "",
  2934.            "",
  2935.            "",
  2936.            0,
  2937.            0,
  2938.            NULL,
  2939.            NULL,
  2940.            NULL
  2941.            );
  2942.  
  2943.     for (n = 0;; n++) {
  2944.         rc = cmfdb(&sw);                /* Parse a service name or a switch */
  2945.         if (rc < 0)
  2946.           goto xopenftp;
  2947.  
  2948.         if (cmresult.fcode == _CMCFM) { /* Done? */
  2949.             break;
  2950.         } else if (cmresult.fcode == _CMFLD) {  /* Port */
  2951.             if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
  2952.               makestr(&service,cmresult.sresult);
  2953.             else
  2954.               makestr(&service,opn_tls?"ftps":"ftp");
  2955.         } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
  2956.             c = cmgbrk();               /* get break character */
  2957.             getval = (c == ':' || c == '=');
  2958.             rc = -9;
  2959.             if (getval && !(cmresult.kflags & CM_ARG)) {
  2960.                 printf("?This switch does not take arguments\n");
  2961.                 goto xopenftp;
  2962.             }
  2963.             if (!getval && (cmresult.kflags & CM_ARG)) {
  2964.                 printf("?This switch requires an argument\n");
  2965.                 goto xopenftp;
  2966.             }
  2967.             switch (cmresult.nresult) { /* Switch */
  2968.               case OPN_ANO:             /* /ANONYMOUS */
  2969.                 anonymous++;
  2970.         nologin = 0;
  2971.                 break;
  2972.               case OPN_NIN:             /* /NOINIT */
  2973.                 noinit++;
  2974.                 break;
  2975.               case OPN_NOL:             /* /NOLOGIN */
  2976.                 nologin++;
  2977.         anonymous = 0;
  2978.         makestr(&ftp_logname,NULL);
  2979.                 break;
  2980.               case OPN_PSW:             /* /PASSWORD */
  2981.                 if (!anonymous)         /* Don't log real passwords */
  2982.                   debok = 0;
  2983.                 rc = cmfld("Password for FTP server","",&p,xxstring);
  2984.                 if (rc == -3) {
  2985.                     makestr(&ftp_tmp,NULL);
  2986.                 } else if (rc < 0) {
  2987.                     goto xopenftp;
  2988.                 } else {
  2989.                     makestr(&ftp_tmp,brstrip(p));
  2990.             nologin = 0;
  2991.                 }
  2992.                 break;
  2993.               case OPN_USR:             /* /USER */
  2994.                 rc = cmfld("Username for FTP server","",&p,xxstring);
  2995.                 if (rc == -3) {
  2996.                     makestr(&ftp_logname,NULL);
  2997.                 } else if (rc < 0) {
  2998.                     goto xopenftp;
  2999.                 } else {
  3000.             nologin = 0;
  3001.                     anonymous = 0;
  3002.             haveuser = 1;
  3003.                     makestr(&ftp_logname,brstrip(p));
  3004.                 }
  3005.                 break;
  3006.               case OPN_ACC:
  3007.                 rc = cmfld("Account for FTP server","",&p,xxstring);
  3008.                 if (rc == -3) {
  3009.                     makestr(&ftp_acc,NULL);
  3010.                 } else if (rc < 0) {
  3011.                     goto xopenftp;
  3012.                 } else {
  3013.                     makestr(&ftp_acc,brstrip(p));
  3014.                 }
  3015.                 break;
  3016.               case OPN_ACT:
  3017.                 opn_psv = 0;
  3018.                 break;
  3019.               case OPN_PSV:
  3020.                 opn_psv = 1;
  3021.                 break;
  3022.               case OPN_TLS:
  3023.                 opn_tls = 1;
  3024.                 break;
  3025.               default:
  3026.                 break;
  3027.             }
  3028.         }
  3029.         if (n == 0) {                   /* After first time through */
  3030.             cmfdbi(&sw,                 /* accept only switches */
  3031.                    _CMKEY,
  3032.                    "\nCarriage return to confirm to command, or switch",
  3033.                    "",
  3034.                    "",
  3035.                    nftpswi,
  3036.                    4,
  3037.                    xxstring,
  3038.                    ftpswitab,
  3039.                    &cm
  3040.                    );
  3041.         }
  3042.     }
  3043. #ifdef COMMENT
  3044.     debug(F100,"ftp openftp while exit","",0);
  3045.     rc = cmcfm();
  3046.     debug(F101,"ftp openftp cmcfm rc","",rc);
  3047.     if (rc < 0)
  3048.       goto xopenftp;
  3049. #endif /* COMMENT */
  3050.  
  3051.     if (opn_psv > -1) {                 /* /PASSIVE or /ACTIVE switch given */
  3052.         sav_psv = ftp_psv;
  3053.         ftp_psv = opn_psv;
  3054.     }
  3055.     if (nologin || haveuser) {        /* /NOLOGIN or /USER switch given */
  3056.     sav_log = ftp_log;
  3057.     ftp_log = haveuser ? 1 : 0;
  3058.     }
  3059.     if (*hostname == '=') {             /* Bypass directory lookup */
  3060.         hostname++;                     /* if hostname starts with '=' */
  3061.         havehost++;
  3062.     } else if (isdigit(*hostname)) {    /* or if it starts with a digit */
  3063.         havehost++;
  3064.     }
  3065.     if (!service)
  3066.       makestr(&service,opn_tls?"ftps":"ftp");
  3067.  
  3068. #ifndef NODIAL
  3069.     if (!havehost && nnetdir > 0) {     /* If there is a networks directory */
  3070.         lunet(hostname);                /* Look up the name */
  3071.         debug(F111,"ftp openftp lunet",hostname,nhcount);
  3072.         if (nhcount == 0) {
  3073.             if (testing)
  3074.               printf(" ftp open trying \"%s %s\"...\n",hostname,service);
  3075.             success = ftpopen(hostname,service,opn_tls);
  3076.             debug(F101,"ftp openftp A ftpopen success","",success);
  3077.             rc = success;
  3078.         } else {
  3079.             int found = 0;
  3080.             for (i = 0; i < nhcount; i++) {
  3081.                 if (nh_p2[i])           /* If network type specified */
  3082.                   if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
  3083.                     continue;
  3084.                 found++;
  3085.                 makestr(&hostname,nh_p[i]);
  3086.                 debug(F111,"ftpopen lunet substitution",hostname,i);
  3087.                 if (testing)
  3088.                   printf(" ftp open trying \"%s %s\"...\n",hostname,service);
  3089.                 success = ftpopen(hostname,service,opn_tls);
  3090.                 debug(F101,"ftp openftp B ftpopen success","",success);
  3091.                 rc = success;
  3092.                 if (success)
  3093.                   break;
  3094.             }
  3095.             if (!found) {               /* E.g. if no network types match */
  3096.                 if (testing)
  3097.                   printf(" ftp open trying \"%s %s\"...\n",hostname,service);
  3098.                 success = ftpopen(hostname,service,opn_tls);
  3099.                 debug(F101,"ftp openftp C ftpopen success","",success);
  3100.                 rc = success;
  3101.             }
  3102.         }
  3103.     } else {
  3104. #endif /* NODIAL */
  3105.         if (testing)
  3106.           printf(" ftp open trying \"%s %s\"...\n",hostname,service);
  3107.         success = ftpopen(hostname,service,opn_tls);
  3108.         debug(F111,"ftp openftp D ftpopen success",hostname,success);
  3109.         debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
  3110.         rc = success;
  3111. #ifndef NODIAL
  3112.     }
  3113. #endif /* NODIAL */
  3114.  
  3115.   xopenftp:
  3116.     debug(F101,"ftp openftp xopenftp rc","",rc);
  3117.     if (hostsave) free(hostsave);
  3118.     if (service) free(service);
  3119.     if (rc < 0 && ftp_logname) {
  3120.         free(ftp_logname);
  3121.         ftp_logname = NULL;
  3122.     }
  3123.     if (ftp_tmp) {
  3124.         free(ftp_tmp);
  3125.         ftp_tmp = NULL;
  3126.     }
  3127.     return(rc);
  3128. }
  3129.  
  3130. VOID                    /* 12 Aug 2007 */
  3131. doftpglobaltype(x) int x; {
  3132.     ftp_xfermode = XMODE_M;        /* Set manual FTP transfer mode */
  3133.     ftp_typ = x;            /* Used by top-level BINARY and */
  3134.     g_ftp_typ = x;            /* ASCII commands. */
  3135.     get_auto = 0;
  3136.     forcetype = 1;
  3137. }
  3138.  
  3139. int
  3140. doftpacct() {
  3141.     int x;
  3142.     char * s;
  3143.     if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
  3144.       return(x);
  3145.     CHECKCONN();
  3146.     makestr(&ftp_acc,brstrip(s));
  3147.     if (testing)
  3148.       printf(" ftp account: \"%s\"\n",ftp_acc);
  3149.     success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
  3150.     return(success);
  3151. }
  3152.  
  3153. int
  3154. doftpusr() {                            /* Log in as USER */
  3155.     extern char uidbuf[];
  3156.     extern char pwbuf[];
  3157.     extern int  pwflg, pwcrypt;
  3158.     int x;
  3159.     char *s, * acct = "";
  3160.  
  3161.     debok = 0;                          /* Don't log */
  3162.  
  3163.     if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
  3164.       return(x);
  3165.     ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
  3166.     if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
  3167.         if (x == -3) { /* no input */
  3168.             if ( pwbuf[0] && pwflg ) {
  3169.                 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
  3170. #ifdef OS2
  3171.                 if ( pwcrypt )
  3172.                     ck_encrypt((char *)tmpbuf);
  3173. #endif /* OS2 */
  3174.             }
  3175.         } else {
  3176.             return(x);
  3177.         }
  3178.     } else {
  3179.         ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
  3180.     }
  3181.     if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
  3182.                    "", &s, xxstring)) < 0)
  3183.       return(x);
  3184.     CHECKCONN();
  3185.     if (*s) {
  3186.         x = strlen(tmpbuf);
  3187.         if (x > 0) {
  3188.             acct = &tmpbuf[x+2];
  3189.             ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
  3190.         }
  3191.     }
  3192.     if (testing)
  3193.       printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
  3194.     success = ftp_user(line,tmpbuf,acct);
  3195. #ifdef CKLOGDIAL
  3196.     dologftp();
  3197. #endif /* CKLOGDIAL */
  3198.     return(success);
  3199. }
  3200.  
  3201. /* DO (various FTP commands)... */
  3202.  
  3203. int
  3204. doftptyp(type) int type; {              /* TYPE */
  3205.     CHECKCONN();
  3206.     ftp_typ = type;
  3207.     changetype(ftp_typ,ftp_vbm);
  3208.     debug(F101,"doftptyp changed type","",type);
  3209.     return(1);
  3210. }
  3211.  
  3212. static int
  3213. doftpxmkd(s,vbm) char * s; int vbm; {   /* MKDIR action */
  3214.     int lcs = -1, rcs = -1;
  3215. #ifndef NOCSETS
  3216.     if (ftp_xla) {
  3217.         lcs = ftp_csl;
  3218.         if (lcs < 0) lcs = fcharset;
  3219.         rcs = ftp_csx;
  3220.         if (rcs < 0) rcs = ftp_csr;
  3221.     }
  3222. #endif /* NOCSETS */
  3223.     debug(F110,"ftp doftpmkd",s,0);
  3224.     if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
  3225.       return(success = 1);
  3226.     if (ftpcode == 500 || ftpcode == 502) {
  3227.         if (!quiet)
  3228.           printf("MKD command not recognized, trying XMKD\n");
  3229.         if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
  3230.           return(success = 1);
  3231.     }
  3232.     return(success = 0);
  3233. }
  3234.  
  3235. static int
  3236. doftpmkd() {                            /* MKDIR parse */
  3237.     int x;
  3238.     char * s;
  3239.     if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
  3240.       return(x);
  3241.     CHECKCONN();
  3242.     ckstrncpy(line,s,LINBUFSIZ);
  3243.     if (testing)
  3244.       printf(" ftp mkdir \"%s\"...\n",line);
  3245.     return(success = doftpxmkd(line,-1));
  3246. }
  3247.  
  3248. static int
  3249. doftprmd() {                            /* RMDIR */
  3250.     int x, lcs = -1, rcs = -1;
  3251.     char * s;
  3252.     if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
  3253.       return(x);
  3254.     CHECKCONN();
  3255.     ckstrncpy(line,s,LINBUFSIZ);
  3256.     if (testing)
  3257.       printf(" ftp rmdir \"%s\"...\n",line);
  3258. #ifndef NOCSETS
  3259.     if (ftp_xla) {
  3260.         lcs = ftp_csl;
  3261.         if (lcs < 0) lcs = fcharset;
  3262.         rcs = ftp_csx;
  3263.         if (rcs < 0) rcs = ftp_csr;
  3264.     }
  3265. #endif /* NOCSETS */
  3266.     if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
  3267.       return(success = 1);
  3268.     if (ftpcode == 500 || ftpcode == 502) {
  3269.         if (!quiet)
  3270.           printf("RMD command not recognized, trying XMKD\n");
  3271.         success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
  3272.     } else
  3273.       success = 0;
  3274.     return(success);
  3275. }
  3276.  
  3277. static int
  3278. doftpren() {                            /* RENAME */
  3279.     int x;
  3280.     char * s;
  3281.     if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
  3282.       return(x);
  3283.     ckstrncpy(line,s,LINBUFSIZ);
  3284.     if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
  3285.       return(x);
  3286.     ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  3287.     if ((x = cmcfm()) < 0)
  3288.       return(x);
  3289.     CHECKCONN();
  3290.     if (testing)
  3291.       printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
  3292.     success = ftp_rename(line,tmpbuf);
  3293.     return(success);
  3294. }
  3295.  
  3296. int
  3297. doftpres() {                            /* RESET (log out without close) */
  3298.     int x;
  3299.     if ((x = cmcfm()) < 0)
  3300.       return(x);
  3301.     CHECKCONN();
  3302.     if (testing)
  3303.       printf(" ftp reset...\n");
  3304.     return(success = ftp_reset());
  3305. }
  3306.  
  3307. static int
  3308. doftpxhlp() {                           /* HELP */
  3309.     int x;
  3310.     char * s;
  3311.     if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
  3312.       return(x);
  3313.     CHECKCONN();
  3314.     ckstrncpy(line,s,LINBUFSIZ);
  3315.     if (testing)
  3316.       printf(" ftp help \"%s\"...\n",line);
  3317.     /* No need to translate -- all FTP commands are ASCII */
  3318.     return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
  3319. }
  3320.  
  3321. static int
  3322. doftpdir(cx) int cx; {                  /* [V]DIRECTORY */
  3323.     int x, lcs = 0, rcs = 0, xlate = 0;
  3324.     char * p, * s, * m = "";
  3325.     if (cx == FTP_VDI) {
  3326.         switch (servertype) {
  3327.           case SYS_VMS:
  3328.           case SYS_DOS:
  3329.           case SYS_TOPS10:
  3330.           case SYS_TOPS20:
  3331.             m = "*.*";
  3332.             break;
  3333.           default:
  3334.             m = "*";
  3335.         }
  3336.     }
  3337.     if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
  3338.       return(x);
  3339.     if ((x = remtxt(&s)) < 0)
  3340.       return(x);
  3341. #ifdef NOCSETS
  3342.     xlate = 0;
  3343. #else
  3344.     xlate = ftp_xla;
  3345. #endif /* NOCSETS */
  3346.     line[0] = NUL;
  3347.     ckstrncpy(line,s,LINBUFSIZ);
  3348.     s = line;
  3349.     CHECKCONN();
  3350.  
  3351. #ifndef NOCSETS
  3352.     if (xlate) {                        /* SET FTP CHARACTER-SET-TRANSLATION */
  3353.         lcs = ftp_csl;                  /* Local charset */
  3354.         if (lcs < 0) lcs = fcharset;
  3355.         if (lcs < 0) xlate = 0;
  3356.     }
  3357.     if (xlate) {                        /* Still ON? */
  3358.         rcs = ftp_csx;                  /* Remote (Server) charset */
  3359.         if (rcs < 0) rcs = ftp_csr;
  3360.         if (rcs < 0) xlate = 0;
  3361.     }
  3362. #endif /* NOCSETS */
  3363.  
  3364.     if (testing) {
  3365.         p = s;
  3366.         if (!p) p = "";
  3367.         if (*p)
  3368.           printf("Directory of files %s at %s:\n", line, ftp_host);
  3369.         else
  3370.           printf("Directory of files at %s:\n", ftp_host);
  3371.     }
  3372.     debug(F111,"doftpdir",s,cx);
  3373.  
  3374.     if (cx == FTP_DIR) {
  3375.         /* Translation of line[] is done inside recvrequest() */
  3376.         /* when it calls ftpcmd(). */
  3377.         return(success =
  3378.           (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
  3379.     }
  3380.     success = 1;                        /* VDIR - one file at a time... */
  3381.     p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
  3382.     cancelgroup = 0;
  3383.     if (!ftp_vbm && !quiet)
  3384.       printlines = 1;
  3385.     while (p && !cancelfile && !cancelgroup) { /* STAT one file */
  3386.         if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
  3387.             success = 0;
  3388.             break;
  3389.         }
  3390.         p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
  3391.         debug(F110,"ftp vdir file",s,0);
  3392.     }
  3393.     return(success);
  3394. }
  3395.  
  3396. static int
  3397. doftppwd() {                            /* PWD */
  3398.     int x, lcs = -1, rcs = -1;
  3399. #ifndef NOCSETS
  3400.     if (ftp_xla) {
  3401.         lcs = ftp_csl;
  3402.         if (lcs < 0) lcs = fcharset;
  3403.         rcs = ftp_csx;
  3404.         if (rcs < 0) rcs = ftp_csr;
  3405.     }
  3406. #endif /* NOCSETS */
  3407.     if ((x = cmcfm()) < 0)
  3408.       return(x);
  3409.     CHECKCONN();
  3410.     if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
  3411.         success = 1;
  3412.     } else if (ftpcode == 500 || ftpcode == 502) {
  3413.         if (ftp_deb)
  3414.           printf("PWD command not recognized, trying XPWD\n");
  3415.         success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
  3416.     }
  3417.     return(success);
  3418. }
  3419.  
  3420. static int
  3421. doftpcwd(s,vbm) char * s; int vbm; {    /* CD (CWD) */
  3422.     int lcs = -1, rcs = -1;
  3423. #ifndef NOCSETS
  3424.     if (ftp_xla) {
  3425.         lcs = ftp_csl;
  3426.         if (lcs < 0) lcs = fcharset;
  3427.         rcs = ftp_csx;
  3428.         if (rcs < 0) rcs = ftp_csr;
  3429.     }
  3430. #endif /* NOCSETS */
  3431.  
  3432.     debug(F110,"ftp doftpcwd",s,0);
  3433.     if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
  3434.       return(success = 1);
  3435.     if (ftpcode == 500 || ftpcode == 502) {
  3436.         if (!quiet)
  3437.           printf("CWD command not recognized, trying XCWD\n");
  3438.         if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
  3439.           return(success = 1);
  3440.     }
  3441.     return(success = 0);
  3442. }
  3443.  
  3444. static int
  3445. doftpcdup() {                           /* CDUP */
  3446.     debug(F100,"ftp doftpcdup","",0);
  3447.     if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
  3448.       return(success = 1);
  3449.     if (ftpcode == 500 || ftpcode == 502) {
  3450.         if (!quiet)
  3451.           printf("CDUP command not recognized, trying XCUP\n");
  3452.         if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
  3453.           return(success = 1);
  3454.     }
  3455.     return(success = 0);
  3456. }
  3457.  
  3458. /* s y n c d i r  --  Synchronizes client & server directories */
  3459.  
  3460. /*
  3461.   Call with:
  3462.     local = pointer to pathname of local file to be sent.
  3463.     sim   = 1 for simulation, 0 for real uploading.
  3464.   Returns 0 on failure, 1 on success.
  3465.  
  3466.   The 'local' argument is relative to the initial directory of the MPUT,
  3467.   i.e. the root of the tree being uploaded.  If the directory of the
  3468.   argument file is different from the directory of the previous file
  3469.   (which is stored in global putpath[]), this routine does the appropriate
  3470.   CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
  3471. */
  3472. static int cdlevel = 0, cdsimlvl = 0;    /* Tree-level trackers */
  3473.  
  3474. static int
  3475. syncdir(local,sim) char * local; int sim; {
  3476.     char buf[CKMAXPATH+1];
  3477.     char tmp[CKMAXPATH+1];
  3478.     char msgbuf[CKMAXPATH+64];
  3479.     char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
  3480.     int i, k = 0, done = 0, itsadir = 0, saveq;
  3481.  
  3482.     debug(F110,"ftp syncdir local (new)",local,0);
  3483.     debug(F110,"ftp syncdir putpath (old)",putpath,0);
  3484.  
  3485.     itsadir = isdir(local);        /* Is the local file a directory? */
  3486.     saveq = quiet;
  3487.  
  3488.     while ((*s = *p)) {                 /* Copy the argument filename */
  3489.         if (++k == CKMAXPATH)           /* so we can poke it. */
  3490.           return(-1);
  3491.         if (*s == '/')                  /* Pointer to rightmost dirsep */
  3492.           q = s;
  3493.         s++;
  3494.         p++;
  3495.     }
  3496.     if (!itsadir)            /* If it's a regular file */
  3497.       *q = NUL;                         /* keep just the path part */
  3498.  
  3499.     debug(F110,"ftp syncdir buf",buf,0);
  3500.     if (!strcmp(buf,putpath)) {         /* Same path as previous file? */
  3501.         if (itsadir) {                  /* This file is a directory? */
  3502.             if (doftpcwd(local,0)) {    /* Try to CD to it */
  3503.                 doftpcdup();            /* Worked - CD back up */
  3504.             } else if (sim) {           /* Simulating... */
  3505.                 if (fdispla == XYFD_B) {
  3506.                     printf("WOULD CREATE DIRECTORY %s\n",local);
  3507.                 } else if (fdispla) {
  3508.                     ckmakmsg(msgbuf,CKMAXPATH,
  3509.                              "WOULD CREATE DIRECTORY",local,NULL,NULL);
  3510.                     ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
  3511.                 }
  3512.                 /* See note above */
  3513.                 return(0);
  3514.             } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
  3515.                 return(0);
  3516.             } else {            /* Remote directory created OK */
  3517.                 if (fdispla == XYFD_B) {
  3518.                     printf("CREATED DIRECTORY %s\n",local);
  3519.                 } else if (fdispla) {
  3520.                     ckmakmsg(msgbuf,CKMAXPATH+64,
  3521.                              "CREATED DIRECTORY ",local,NULL,NULL);
  3522.                     ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
  3523.                 }
  3524.             }
  3525.         }
  3526.         debug(F110,"ftp syncdir no change",buf,0);
  3527.         return(1);                      /* Yes, done. */
  3528.     }
  3529.     ckstrncpy(tmp,buf,CKMAXPATH+1);     /* Make a safe (pre-poked) copy */
  3530.     debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
  3531.  
  3532.     p = buf;                            /* New */
  3533.     s = putpath;                        /* Old */
  3534.  
  3535.     debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
  3536.     debug(F110,"ftp syncdir A (new) p",p,0); /* New */
  3537.  
  3538.     psep = buf;
  3539.     ssep = putpath;
  3540.     while (*p != NUL && *s != NUL && *p == *s) {
  3541.     if (*p == '/') { psep = p+1; ssep = s+1; }
  3542.     p++,s++;
  3543.     }
  3544.     /*
  3545.       psep and ssep point to the first path segment that differs.
  3546.       We have to do as many CDUPs as there are path segments in ssep.
  3547.       then we have to do as many MKDs and CWDs as there are segments in psep.
  3548.     */
  3549.     s = ssep;
  3550.     p = psep;
  3551.  
  3552.     debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
  3553.     debug(F110,"ftp syncdir B (new) p",p,0); /* New */
  3554.  
  3555.     /* p and s now point to the leftmost spot where the paths differ */
  3556.  
  3557.     if (*s) {                           /* We have to back up */
  3558.         k = 1;                          /* How many levels counting this one */
  3559.         while ((c = *s++)) {            /* Count dirseps remaining in prev */
  3560.             if (c == '/' && *s)
  3561.               k++;
  3562.         }
  3563.     debug(F101,"ftp syncdir levels up","",k);
  3564.  
  3565.         for (i = 1; i <= k; i++) {       /* Do that many CDUPs */
  3566.             debug(F111,"ftp syncdir CDUP A",p,i);
  3567.         if (fdispla == XYFD_B)
  3568.           printf(" CDUP\n");
  3569.             if (sim && cdsimlvl) {
  3570.                 cdsimlvl--;
  3571.             } else {
  3572.                 if (!doftpcdup()) {
  3573.                     quiet = saveq;
  3574.                     return(0);
  3575.                 }
  3576.             }
  3577.             cdlevel--;
  3578.         }
  3579.         if (!*p)                        /* If we don't have to go down */
  3580.           goto xcwd;                    /* we're done. */
  3581.     }
  3582. #ifdef COMMENT
  3583.     while (p > buf && *p && *p != '/')  /* If in middle of segment */
  3584.       p--;                              /* back up to beginning */
  3585.     if (*p == '/')                      /* and terminate there */
  3586.       p++;
  3587. #endif    /* COMMENT */
  3588.  
  3589.     debug(F110,"ftp syncdir NEW PATH",p,0);
  3590.  
  3591.     s = p;                              /* Point to start of new down path. */
  3592.     while (1) {                         /* Loop through characters. */
  3593.         if (*s == '/' || !*s) {         /* Have a segment. */
  3594.             if (!*s)                    /* If end of string, */
  3595.               done++;                   /* after this segment we're done. */
  3596.             else
  3597.               *s = NUL;                 /* NUL out the separator. */
  3598.             if (*p) {                   /* If segment is not empty */
  3599.                 debug(F110,"ftp syncdir down segment",p,0);
  3600.                 if (!doftpcwd(p,0)) {   /* Try to CD to it */
  3601.                     if (sim) {
  3602.                         if (fdispla == XYFD_B) {
  3603.                             printf(" WOULD CREATE DIRECTORY %s\n",local);
  3604.                         } else if (fdispla) {
  3605.                             ckmakmsg(msgbuf,CKMAXPATH,
  3606.                      "WOULD CREATE DIRECTORY",
  3607.                                      local,NULL,NULL);
  3608.                             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
  3609.                         }
  3610.                         cdsimlvl++;
  3611.                     } else {
  3612.                         if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
  3613.                 debug(F110,"ftp syncdir mkdir failed",p,0); 
  3614. /*
  3615.   Suppose we are executing SEND /RECURSIVE.  Locally we have a directory
  3616.   FOO but the remote has a regular file with the same name.  We can't CD
  3617.   to it, can't MKDIR it either.  There's no way out but to fail and let
  3618.   the user handle the problem.
  3619. */
  3620.                             quiet = saveq;
  3621.                             return(0);
  3622.                         }
  3623.             debug(F110,"ftp syncdir mkdir OK",p,0); 
  3624.                         if (fdispla == XYFD_B) {
  3625.                             printf(" CREATED DIRECTORY %s\n",p);
  3626.                         } else if (fdispla) {
  3627.                             ckmakmsg(msgbuf,CKMAXPATH,
  3628.                                      "CREATED DIRECTORY ",p,NULL,NULL);
  3629.                             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
  3630.                         }
  3631.                         if (!doftpcwd(p,0)) { /* Try again to CD */
  3632.                 debug(F110,"ftp syncdir CD failed",p,0); 
  3633.                             quiet = saveq;
  3634.                             return(0);
  3635.                         }
  3636.                         if (fdispla == XYFD_B) printf(" CWD %s\n",p);
  3637.             debug(F110,"ftp syncdir CD OK",p,0); 
  3638.                     }
  3639.                 }
  3640.                 cdlevel++;
  3641.             }
  3642.             if (done)                   /* Quit if no next segment */
  3643.               break;
  3644.             p = s+1;                    /* Point to next segment */
  3645.         }
  3646.         s++;                            /* Point to next source char */
  3647.     }
  3648.  
  3649.   xcwd:
  3650.     ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
  3651.     quiet = saveq;
  3652.     return(1);
  3653. }
  3654.  
  3655. #ifdef DOUPDATE
  3656. #ifdef DEBUG
  3657. static VOID
  3658. dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
  3659.     if (deblog) {
  3660.         debug(F111,"ftp year ",s,xx->tm_year);
  3661.         debug(F111,"ftp month",s,xx->tm_mon);
  3662.         debug(F111,"ftp day  ",s,xx->tm_mday);
  3663.         debug(F111,"ftp hour ",s,xx->tm_hour);
  3664.         debug(F111,"ftp min  ",s,xx->tm_min);
  3665.         debug(F111,"ftp sec  ",s,xx->tm_sec);
  3666.     }
  3667. }
  3668. #endif /* DEBUG */
  3669.  
  3670. /*  t m c o m p a r e  --  Compare two struct tm's */
  3671.  
  3672. /*  Like strcmp() but for struct tm's  */
  3673. /*  Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
  3674.  
  3675. static int
  3676. tmcompare(xx,yy) struct tm * xx, * yy; {
  3677.  
  3678.     if (xx->tm_year < yy->tm_year)      /* First year less than second */
  3679.       return(-1);
  3680.     if (xx->tm_year > yy->tm_year)      /* First year greater than second */
  3681.       return(1);
  3682.  
  3683.     /* Years are equal so compare months */
  3684.  
  3685.     if (xx->tm_mon  < yy->tm_mon)       /* And so on... */
  3686.       return(-1);
  3687.     if (xx->tm_mon  > yy->tm_mon)
  3688.       return(1);
  3689.  
  3690.     if (xx->tm_mday < yy->tm_mday)
  3691.       return(-1);
  3692.     if (xx->tm_mday > yy->tm_mday)
  3693.       return(1);
  3694.  
  3695.     if (xx->tm_hour < yy->tm_hour)
  3696.       return(-1);
  3697.     if (xx->tm_hour > yy->tm_hour)
  3698.       return(1);
  3699.  
  3700.     if (xx->tm_min  < yy->tm_min)
  3701.       return(-1);
  3702.     if (xx->tm_min  > yy->tm_min)
  3703.       return(1);
  3704.  
  3705.     if (xx->tm_sec  < yy->tm_sec)
  3706.       return(-1);
  3707.     if (xx->tm_sec  > yy->tm_sec)
  3708.       return(1);
  3709.  
  3710.     return(0);
  3711. }
  3712. #endif /* DOUPDATE */
  3713.  
  3714. #ifndef HAVE_TIMEGM             /* For platforms that do not have timegm() */
  3715. static CONST int MONTHDAYS[] = { /* Number of days in each month. */
  3716.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  3717. };
  3718.  
  3719. /* Macro for whether a given year is a leap year. */
  3720. #define ISLEAP(year) \
  3721. (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
  3722. #endif /* HAVE_TIMEGM */
  3723.  
  3724. /*  m k u t i m e  --  Like mktime() but argument is already UTC */
  3725.  
  3726. static time_t
  3727. #ifdef CK_ANSIC
  3728. mkutime(struct tm * tm)
  3729. #else
  3730. mkutime(tm) struct tm * tm;
  3731. #endif /* CK_ANSIC */
  3732. /* mkutime */ {
  3733. #ifdef HAVE_TIMEGM
  3734.     return(timegm(tm));                 /* Have system service, use it. */
  3735. #else
  3736. /*
  3737.   Contributed by Russ Allbery (rra@stanford.edu), used by permission.
  3738.   Given a struct tm representing a calendar time in UTC, convert it to
  3739.   seconds since epoch.  Returns (time_t) -1 if the time is not
  3740.   convertable.  Note that this function does not canonicalize the provided
  3741.   struct tm, nor does it allow out-of-range values or years before 1970.
  3742.   Result should be identical with timegm().
  3743. */
  3744.     time_t result = 0;
  3745.     int i;
  3746.     /*
  3747.       We do allow some ill-formed dates, but we don't do anything special
  3748.       with them and our callers really shouldn't pass them to us.  Do
  3749.       explicitly disallow the ones that would cause invalid array accesses
  3750.       or other algorithm problems.
  3751.     */
  3752. #ifdef DEBUG
  3753.     if (deblog) {
  3754.         debug(F101,"mkutime tm_mon","",tm->tm_mon);
  3755.         debug(F101,"mkutime tm_year","",tm->tm_year);
  3756.     }
  3757. #endif /* DEBUG */
  3758.     if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
  3759.       return((time_t) -1);
  3760.  
  3761.     /* Convert to time_t. */
  3762.     for (i = 1970; i < tm->tm_year + 1900; i++)
  3763.       result += 365 + ISLEAP(i);
  3764.     for (i = 0; i < tm->tm_mon; i++)
  3765.       result += MONTHDAYS[i];
  3766.     if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
  3767.       result++;
  3768.     result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
  3769.     result = 60 * result + tm->tm_min;
  3770.     result = 60 * result + tm->tm_sec;
  3771.     debug(F101,"mkutime result","",result);
  3772.     return(result);
  3773. #endif /* HAVE_TIMEGM */
  3774. }
  3775.  
  3776.  
  3777. /*
  3778.   s e t m o d t i m e  --  Set file modification time.
  3779.  
  3780.   f = char * filename;
  3781.   t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
  3782.  
  3783.   UNIX-specific; isolates mainline code from hideous #ifdefs.
  3784.   Returns:
  3785.     0 on success,
  3786.    -1 on error.
  3787.  
  3788. */
  3789. static int
  3790. #ifdef CK_ANSIC
  3791. setmodtime(char * f, time_t t)
  3792. #else
  3793. setmodtime(f,t) char * f; time_t t;
  3794. #endif /* CK_ANSIC */
  3795. /* setmodtime */ {
  3796. #ifdef NT
  3797.     struct _stat sb;
  3798. #else /* NT */
  3799.     struct stat sb;
  3800. #endif /* NT */
  3801.     int x, rc = 0;
  3802. #ifdef BSD44
  3803.     struct timeval tp[2];
  3804. #else  /* def BSD44 */
  3805. #ifdef V7
  3806.     struct utimbuf {
  3807.         time_t timep[2];
  3808.     } tp;
  3809. #else  /* def V7 */
  3810. #ifdef SYSUTIMEH
  3811. #ifdef NT
  3812.     struct _utimbuf tp;
  3813. #else /* NT */
  3814.     struct utimbuf tp;
  3815. #endif /* NT */
  3816. #else /* def SYSUTIMEH */
  3817. #ifdef VMS
  3818.     struct utimbuf tp;
  3819. #define SYSUTIMEH               /* Our utimbuf matches this one. */
  3820. #else /* def VMS */
  3821.     struct utimbuf {
  3822.         time_t atime;
  3823.         time_t mtime;
  3824.     } tp;
  3825. #endif /* def VMS [else] */
  3826. #endif /* def SYSUTIMEH [else] */
  3827. #endif /* def V7 [else] */
  3828. #endif /* def BSD44 [else] */
  3829.  
  3830.     if (stat(f,&sb) < 0) {
  3831.         debug(F111,"setmodtime stat failure",f,errno);
  3832.         return(-1);
  3833.     }
  3834. #ifdef BSD44
  3835.     tp[0].tv_sec = sb.st_atime;         /* Access time first */
  3836.     tp[1].tv_sec = t;                   /* Update time second */
  3837.     debug(F111,"setmodtime BSD44",f,t);
  3838. #else
  3839. #ifdef V7
  3840.     tp.timep[0] = t;                    /* Set modif. time to creation date */
  3841.     tp.timep[1] = sb.st_atime;          /* Don't change the access time */
  3842.     debug(F111,"setmodtime V7",f,t);
  3843. #else
  3844. #ifdef SYSUTIMEH
  3845.     tp.modtime = t;                     /* Set modif. time to creation date */
  3846.     tp.actime = sb.st_atime;            /* Don't change the access time */
  3847.     debug(F111,"setmodtime SYSUTIMEH",f,t);
  3848. #else
  3849.     tp.mtime = t;                       /* Set modif. time to creation date */
  3850.     tp.atime = sb.st_atime;             /* Don't change the access time */
  3851.     debug(F111,"setmodtime (other)",f,t);
  3852. #endif /* SYSUTIMEH */
  3853. #endif /* V7 */
  3854. #endif /* BSD44 */
  3855.  
  3856.     /* Try to set the file date */
  3857.  
  3858. #ifdef BSD44
  3859.     x = utimes(f,tp);
  3860.     debug(F111,"setmodtime utimes()","BSD44",x);
  3861. #else
  3862. #ifdef IRIX65
  3863.     {
  3864.       /*
  3865.         The following produces the nonsensical warning:
  3866.         Argument  of type "const struct utimbuf *" is incompatible with
  3867.         parameter of type "const struct utimbuf *".  If you can make it
  3868.         go away, be my guest.
  3869.       */
  3870.         const struct utimbuf * t2 = &tp;
  3871.         x = utime(f,t2);
  3872.     }
  3873. #else
  3874.     x = utime(f,&tp);
  3875.     debug(F111,"setmodtime utime()","other",x);
  3876. #endif /* IRIX65 */
  3877. #endif /* BSD44 */
  3878.     if (x)
  3879.       rc = -1;
  3880.  
  3881.     debug(F101,"setmodtime result","",rc);
  3882.     return(rc);
  3883. }
  3884.  
  3885.  
  3886. /*
  3887.   c h k m o d t i m e  --  Check/Set file modification time.
  3888.  
  3889.   fc = function code:
  3890.     0 = Check; returns:
  3891.       -1 on error,
  3892.        0 if local older than remote,
  3893.        1 if modtimes are equal,
  3894.        2 if local newer than remote.
  3895.     1 = Set (local file's modtime from remote's); returns:
  3896.       -1 on error,
  3897.        0 on success.
  3898. */
  3899. static int
  3900. chkmodtime(local,remote,fc) char * local, * remote; int fc; {
  3901. #ifdef NT
  3902.     struct _stat statbuf;
  3903. #else /* NT */
  3904.     struct stat statbuf;
  3905. #endif /* NT */
  3906.     struct tm * tmlocal = NULL;
  3907.     struct tm tmremote;
  3908.     int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
  3909.     char * s, timebuf[64];
  3910.  
  3911.     debug(F111,"chkmodtime",local,mdtmok);
  3912.     if (!mdtmok)            /* Server supports MDTM? */
  3913.       return(-1);            /* No don't bother. */
  3914.  
  3915. #ifndef NOCSETS
  3916.     if (ftp_xla) {
  3917.         lcs = ftp_csl;
  3918.         if (lcs < 0) lcs = fcharset;
  3919.         rcs = ftp_csx;
  3920.         if (rcs < 0) rcs = ftp_csr;
  3921.     }
  3922. #endif /* NOCSETS */
  3923.  
  3924.     if (fc == 0) {
  3925.         rc = stat(local,&statbuf);
  3926.         if (rc == 0) {                  /* Get local file's mod time */
  3927.         /* Convert to struct tm */
  3928.             tmlocal = gmtime((time_t *)&statbuf.st_mtime);
  3929. #ifdef DEBUG
  3930.             if (tmlocal) {
  3931.                 dbtime(local,tmlocal);
  3932.             }
  3933. #endif /* DEBUG */
  3934.         }
  3935.     }
  3936.     /* Get remote file's mod time as yyyymmddhhmmss */
  3937.  
  3938.     if (havemdtm) {            /* Already got it from MLSD? */
  3939.     s = havemdtm;
  3940.     flag++;
  3941.     } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
  3942.         char c;
  3943.         bzero((char *)&tmremote, sizeof(struct tm));
  3944.         s = ftp_reply_str;
  3945.         while ((c = *s++)) {            /* Skip past response code */
  3946.             if (c == SP) {
  3947.                 flag++;
  3948.                 break;
  3949.             }
  3950.         }
  3951.     }
  3952.     if (flag) {
  3953.     debug(F111,"ftp chkmodtime string",s,flag);
  3954.     if (fts_sto) {            /* User gave server time offset? */
  3955.         char * p;
  3956.         debug(F110,"ftp chkmodtime offset",fts_sto,0);
  3957.         ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
  3958.         if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
  3959.         ckstrncpy(timebuf,p,64);      /* Convert to MDTM format */
  3960.         timebuf[8]  = timebuf[9];  /* h */
  3961.         timebuf[9]  = timebuf[10]; /* h */
  3962.         timebuf[10] = timebuf[12]; /* m */
  3963.         timebuf[11] = timebuf[13]; /* m */
  3964.         timebuf[12] = timebuf[12]; /* s */
  3965.         timebuf[13] = timebuf[13]; /* s */
  3966.         timebuf[14] = NUL;
  3967.         s = timebuf;
  3968.         debug(F110,"ftp chkmodtime adjust",s,0);
  3969.         }
  3970.     }
  3971.         if (flag) {                     /* Convert to struct tm */
  3972.             char * pat;
  3973.             int y2kbug = 0;             /* Seen in Kerberos 4 FTP servers */
  3974.             if (!ckstrcmp(s,"191",3,0)) {
  3975.                 pat = "%05d%02d%02d%02d%02d%02d";
  3976.                 y2kbug++;
  3977.                 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
  3978.             } else {
  3979.                 pat = "%04d%02d%02d%02d%02d%02d";
  3980.             }
  3981.             if (sscanf(s,               /* Parse into struct tm */
  3982.                        pat,
  3983.                        &(tmremote.tm_year),
  3984.                        &(tmremote.tm_mon),
  3985.                        &(tmremote.tm_mday),
  3986.                        &(tmremote.tm_hour),
  3987.                        &(tmremote.tm_min),
  3988.                        &(tmremote.tm_sec)
  3989.                        ) == 6) {
  3990.                 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
  3991.                 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
  3992.                 tmremote.tm_mon--;
  3993.  
  3994. #ifdef DEBUG
  3995.         debug(F100,"SERVER TIME FOLLOWS:","",0);
  3996.                 dbtime(remote,&tmremote);
  3997. #endif /* DEBUG */
  3998.  
  3999.                 if (havedate > -1)
  4000.           havedate = 1;
  4001.             }
  4002.         }
  4003.     } else {                /* Failed */
  4004.     debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
  4005.     if (ftpcode == 500 ||        /* Command unrecognized */
  4006.         ftpcode == 502 ||        /* Command not implemented */
  4007.         ftpcode == 202)        /* Command superfluous */
  4008.       mdtmok = 0;            /* Don't ask this server again */
  4009.     return(-1);
  4010.     }
  4011.     if (fc == 0) {                      /* Compare */
  4012.         if (havedate == 1) {        /* Only if we have both file dates */
  4013.             /*
  4014.               Compare with local file's time.  We don't use
  4015.               clock time (time_t) here in case of signed/unsigned
  4016.               confusion, etc.
  4017.             */
  4018.         int xx;
  4019. #ifdef COMMENT
  4020. #ifdef DEBUG        
  4021.         if (deblog) {
  4022.         dbtime("LOCAL",tmlocal);
  4023.         dbtime("REMOT",&tmremote);
  4024.         }
  4025. #endif /* DEBUG */
  4026. #endif /* COMMENT */
  4027.         xx = tmcompare(tmlocal,&tmremote);
  4028.         debug(F101,"chkmodtime tmcompare","",xx);
  4029.             return(xx + 1);
  4030.         }
  4031.     } else if (ftp_dates) {             /* Set */
  4032.         /*
  4033.           Here we must convert struct tm to time_t
  4034.           without applying timezone conversion, for which
  4035.           there is no portable API.  The method is hidden
  4036.           in mkutime(), defined above.
  4037.         */
  4038.         time_t utc;
  4039.         utc = mkutime(&tmremote);
  4040.         debug(F111,"ftp chkmodtime mkutime",remote,utc);
  4041.         if (utc != (time_t)-1)
  4042.           return(setmodtime(local,utc));
  4043.     }
  4044.     return(-1);
  4045. }
  4046.  
  4047. /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
  4048.  
  4049. static int
  4050. getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
  4051.     char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
  4052. /* getfile */ {
  4053.     int rc = -1;
  4054.     ULONG t0, t1;
  4055.  
  4056. #ifdef GFTIMER
  4057.     CKFLOAT sec;
  4058. #else
  4059.     int sec = 0;
  4060. #endif /* GFTIMER */
  4061.     char fullname[CKMAXPATH+1];
  4062.  
  4063.     debug(F110,"ftp getfile remote A",remote,0);
  4064.     debug(F110,"ftp getfile local A",local,0);
  4065.     debug(F110,"ftp getfile pipename",pipename,0);
  4066.     if (!remote) remote = "";
  4067.  
  4068. #ifdef PATTERNS
  4069.     /* Automatic type switching? */
  4070.     if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
  4071.         int x;
  4072.         x = matchname(remote,0,servertype);
  4073.         debug(F111,"ftp getfile matchname",remote,x);
  4074.         switch (x) {
  4075.           case 0: ftp_typ = FTT_ASC; break;
  4076.           case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
  4077.           default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
  4078.         }
  4079.         changetype(ftp_typ,ftp_vbm);
  4080.         binary = ftp_typ;               /* For file-transfer display */
  4081.     }
  4082. #endif /* PATTERNS */
  4083.  
  4084. #ifndef NOCSETS
  4085.     ftp_csx = -1;                       /* For file-transfer display */
  4086.     ftp_csl = -1;                       /* ... */
  4087.  
  4088.     if (rcs > -1)                       /* -1 means no translation */
  4089.       if (ftp_typ == FTT_ASC)           /* File type is "ascii"? */
  4090.         if (fcs < 0)                    /* File charset not forced? */
  4091.           fcs = fcharset;               /* use prevailing FILE CHARACTER-SET */
  4092.     if (fcs > -1 && rcs > -1) {         /* Set up translation functions */
  4093.         debug(F110,"ftp getfile","initxlate",0);
  4094.         initxlate(rcs,fcs);             /* NB: opposite order of PUT */
  4095.         ftp_csx = rcs;
  4096.         ftp_csl = fcs;
  4097.     } else
  4098.       xlate = 0;
  4099. #endif /* NOCSETS */
  4100.  
  4101.     if (!local) local = "";
  4102.     if (!pipename && !*local)
  4103.       local = remote;
  4104.  
  4105.     out2screen = !strcmp(local,"-");
  4106.  
  4107.     fullname[0] = NUL;
  4108.     if (pipename) {
  4109.         ckstrncpy(fullname,pipename,CKMAXPATH+1);
  4110.     } else {
  4111.         zfnqfp(local,CKMAXPATH,fullname);
  4112.         if (!fullname[0])
  4113.           ckstrncpy(fullname,local,CKMAXPATH+1);
  4114.     }
  4115.     if (!out2screen && displa && fdispla) { /* Screen */
  4116.         ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
  4117.         ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
  4118.         ftscreen(SCR_FS,0,fsize,"");
  4119.     }
  4120.     tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
  4121.     tlog(F110," as",fullname,0);
  4122.     debug(F111,"ftp getfile size",remote,fsize);
  4123.     debug(F111,"ftp getfile local",local,out2screen);
  4124.  
  4125.     ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
  4126.  
  4127.     t0 = gmstimer();                    /* Start time */
  4128.     debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
  4129.     rc = recvrequest("RETR",
  4130.                      local,
  4131.                      remote,
  4132.                      append ? "ab" : "wb",
  4133.                      0,
  4134.                      recover,
  4135.                      pipename,
  4136.                      xlate,
  4137.                      fcs,
  4138.                      rcs
  4139.                      );
  4140.     t1 = gmstimer();                    /* End time */
  4141.     debug(F111,"ftp getfile t1",remote,t1);
  4142.     debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
  4143. #ifdef GFTIMER
  4144.     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  4145.     fpxfsecs = sec;                     /* (for doxlog()) */
  4146. #else
  4147.     sec = (t1 - t0) / 1000;
  4148.     xfsecs = (int)sec;
  4149. #endif /* GFTIMER */
  4150.  
  4151. #ifdef FTP_TIMEOUT
  4152.     if (ftp_timed_out)
  4153.       rc = -4;
  4154. #endif    /* FTP_TIMEOUT */
  4155.  
  4156.     debug(F111,"ftp recvrequest rc",remote,rc);
  4157.     if (cancelfile || cancelgroup) {
  4158.         debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
  4159.         ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
  4160.     } else if (rc > 0) {
  4161.         debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
  4162.         ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
  4163.     } else if (rc < 0) {
  4164.         switch (ftpcode) {
  4165.           case -4:                      /* Network error */
  4166.           case -2:                      /* File error */
  4167.             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
  4168.             break;
  4169.           case -3:
  4170.             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
  4171.              "Failure to make data connection");
  4172.             break;
  4173.           case -1:            /* (should be covered above) */
  4174.             ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
  4175.             break;
  4176.           default:
  4177.             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
  4178.         }
  4179.     } else {                            /* Tudo bem */
  4180.         ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
  4181.         if (rc == 0) {
  4182.             ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
  4183.             makestr(&rrfspec,remote);     /* For WHERE command */
  4184.             makestr(&rfspec,fullname);
  4185.         }
  4186.     }
  4187.     if (rc > -1) {
  4188.     if (ftp_dates)            /* If FTP DATES ON... */
  4189.       if (!pipename && !out2screen)    /* and it's a real file */
  4190.         if (rc < 1 && rc != -3)    /* and it wasn't skipped */
  4191.           if (connected)        /* and we still have a connection */
  4192.         if (zchki(local) > -1) { /* and the file wasn't discarded */
  4193.             chkmodtime(local,remote,1); /* set local file date */
  4194.             debug(F110,"ftp get set date",local,0);
  4195.         }
  4196.     filcnt++;            /* Used by \v(filenum) */
  4197.     }
  4198. #ifdef TLOG
  4199.     if (tralog) {
  4200.         if (rc > 0) {
  4201.             tlog(F100," recovery skipped","",0);
  4202.         } else if (rc == 0) {
  4203.             tlog(F101," complete, size", "", fsize);
  4204.         } else if (cancelfile) {
  4205.             tlog(F100," canceled by user","",0);
  4206. #ifdef FTP_TIMEOUT
  4207.         } else if (ftp_timed_out) {
  4208.             tlog(F100," timed out","",0);
  4209. #endif    /* FTP_TIMEOUT */
  4210.         } else {
  4211.             tlog(F110," failed:",ftp_reply_str,0);
  4212.         }
  4213.         if (!tlogfmt)
  4214.           doxlog(what,local,fsize,ftp_typ,rc,"");
  4215.     }
  4216. #endif /* TLOG */
  4217.     return(rc);
  4218. }
  4219.  
  4220. /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
  4221. /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
  4222.  
  4223. static int
  4224. putfile(cx,
  4225.     local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
  4226.     char * local, * remote, * mvto, *rnto, *srvrn;
  4227.     int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
  4228.  
  4229. /* putfile */ {
  4230.  
  4231.     char asname[CKMAXPATH+1];
  4232.     char fullname[CKMAXPATH+1];
  4233.     int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
  4234.     int xlate = 0, restart = 0, mt = -1;
  4235.     char * s = NULL, * cmd = NULL;
  4236.     ULONG t0 = 0, t1 = 0;        /* Times for stats */
  4237.     int ofcs = 0, orcs = 0;
  4238.  
  4239. #ifdef GFTIMER
  4240.     CKFLOAT sec = 0.0;
  4241. #else
  4242.     int sec = 0;
  4243. #endif /* GFTIMER */
  4244.     debug(F111,"ftp putfile flg",local,flg);
  4245.     debug(F110,"ftp putfile srv_renam",srvrn,0);
  4246.     debug(F101,"ftp putfile fcs","",fcs);
  4247.     debug(F101,"ftp putfile rcs","",rcs);
  4248.  
  4249.     ofcs = fcs;                         /* Save charset args */
  4250.     orcs = rcs;
  4251.  
  4252.     sendstart = (CK_OFF_T)0;
  4253.     restart = flg & PUT_RES;
  4254.     if (!remote)
  4255.       remote = "";
  4256.  
  4257.     /* FTP protocol command to send to server */
  4258.     cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
  4259.  
  4260.     if (x_cnv == SET_AUTO) {            /* Name conversion is auto */
  4261.         if (alike) {                    /* If server & client are alike */
  4262.             nc = 0;                     /* no conversion */
  4263.         } else {                        /* If they are different */
  4264.             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
  4265.               nc = -1;                  /* only minimal conversions needed */
  4266.             else                        /* otherwise */
  4267.               nc = 1;                   /* full conversion */
  4268.         }
  4269.     } else                              /* Not auto - do what user said */
  4270.       nc = x_cnv;
  4271.  
  4272.     /* If Transfer Mode is Automatic, determine file type */
  4273.     if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
  4274.         if (isdir(local)) {             /* If it's a directory */
  4275.             k = FT_BIN;                 /* skip the file scan */
  4276.         } else {
  4277.             debug(F110,"FTP PUT calling scanfile",local,0);
  4278.             k = scanfile(local,&o,nscanfile); /* Scan the file */
  4279.         }
  4280.         debug(F111,"FTP PUT scanfile",local,k);
  4281.         if (k > -1 && !forcetype) {
  4282.             ftp_typ = (k == FT_BIN) ? 1 : 0;
  4283.             if (xft > -1 && ftp_typ != xft) {
  4284.                 if (flg & PUT_SIM)
  4285.                   tlog(F110,"ftp put SKIP (Type):", local, 0);
  4286.                 return(SKP_TYP);
  4287.             }
  4288.             if (ftp_typ == 1 && tenex)  /* User said TENEX? */
  4289.               ftp_typ = FTT_TEN;
  4290.         }
  4291.     }
  4292. #ifndef NOCSETS
  4293.     ftp_csx = -1;                       /* For file-transfer display */
  4294.     ftp_csl = -1;                       /* ... */
  4295.  
  4296.     if (rcs > -1) {                     /* -1 means no translation */
  4297.         if (ftp_typ == 0) {             /* File type is "ascii"? */
  4298.             if (fcs < 0) {              /* File charset not forced? */
  4299.                 if (k < 0) {            /* If we didn't scan */
  4300.                     fcs = fcharset;     /* use prevailing FILE CHARACTER-SET */
  4301.                 } else {                /* If we did scan, use scan result */
  4302.                     switch (k) {
  4303.                       case FT_TEXT:     /* Unknown text */
  4304.                         fcs = fcharset;
  4305.                         break;
  4306.                       case FT_7BIT:     /* 7-bit text */
  4307.                         fcs = dcset7;
  4308.                         break;
  4309.                       case FT_8BIT:     /* 8-bit text */
  4310.                         fcs = dcset8;
  4311.                         break;
  4312.                       case FT_UTF8:     /* UTF-8 */
  4313.                         fcs = FC_UTF8;
  4314.                         break;
  4315.                       case FT_UCS2:     /* UCS-2 */
  4316.                         fcs = FC_UCS2;
  4317.                         if (o > -1)     /* Input file byte order */
  4318.                           fileorder = o;
  4319.                         break;
  4320.                       default:
  4321.                         rcs = -1;
  4322.                     }
  4323.                 }
  4324.             }
  4325.         }
  4326.     }
  4327.     if (fcs > -1 && rcs > -1) {         /* Set up translation functions */
  4328.         debug(F110,"ftp putfile","initxlate",0);
  4329.         initxlate(fcs,rcs);
  4330.         debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
  4331.         xlate = 1;
  4332.         ftp_csx = rcs;
  4333.         ftp_csl = fcs;
  4334.     }
  4335. #endif /* NOCSETS */
  4336.  
  4337.     binary = ftp_typ;                   /* For file-transfer display */
  4338.     asname[0] = NUL;
  4339.  
  4340.     if (recursive) {                    /* If sending recursively, */
  4341.         if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
  4342.           return(-1);                   /* Don't PUT if it fails. */
  4343.         else if (isdir(local))          /* It's a directory */
  4344.           return(0);                    /* Don't send it! */
  4345.     }
  4346.     if (*remote) {                      /* If an as-name template was given */
  4347. #ifndef NOSPL
  4348.         if (cmd_quoting) {              /* and COMMAND QUOTING is ON */
  4349.             y = CKMAXPATH;              /* evaluate it for this file */
  4350.             s = asname;
  4351.             zzstring(remote,&s,&y);
  4352.         } else
  4353. #endif /* NOSPL */
  4354.           ckstrncpy(asname,remote,CKMAXPATH);   /* (or take it literally) */
  4355.     } else {                                    /* No as-name */
  4356.         nzltor(local,asname,nc,0,CKMAXPATH);    /* use local name strip path */
  4357.         debug(F110,"FTP PUT nzltor",asname,0);
  4358.     }
  4359.     /* Preliminary messages and log entries */
  4360.  
  4361.     fullname[0] = NUL;
  4362.     zfnqfp(local,CKMAXPATH,fullname);
  4363.     if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
  4364.     fullname[CKMAXPATH] = NUL;
  4365.  
  4366.     if (displa && fdispla) {            /* Screen */
  4367.         ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
  4368.         ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
  4369.         ftscreen(SCR_FS,0,fsize,"");
  4370.     }
  4371. #ifdef DOUPDATE
  4372.     if (flg & (PUT_UPD|PUT_DIF)) {    /* Date-checking modes... */
  4373.         mt = chkmodtime(fullname,asname,0);
  4374.         debug(F111,"ftp putfile chkmodtime",asname,mt);
  4375.         if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
  4376.             tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
  4377.         /* Skip this one */
  4378.             ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
  4379.             filcnt++;
  4380.             return(SKP_DAT);
  4381.         } else if (mt == 1) {           /* Times are equal */
  4382.             tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
  4383.             ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
  4384.             filcnt++;
  4385.             return(SKP_DAT);
  4386.         }
  4387.     /* Local file is newer */
  4388.         tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
  4389.              "ftp put /update TEXT:", fullname, 0);
  4390.     } else if (flg & PUT_RES) {
  4391.         tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
  4392.              "ftp put /recover TEXT:", fullname, 0);
  4393.     } else {
  4394.         tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
  4395.     }
  4396. #else
  4397.     tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
  4398. #endif /* DOUPDATE */
  4399.     tlog(F110," as",asname,0);
  4400.  
  4401. #ifndef NOCSETS
  4402.     if (xlate) {
  4403.         debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
  4404.         tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
  4405.         tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
  4406.     } else if (!ftp_typ) {
  4407.         tlog(F110," character sets:","no conversion",0);
  4408.         fcs = ofcs;                     /* Binary file but we still must */
  4409.         rcs = orcs;                     /* translate its name */
  4410.     }
  4411. #endif /* NOCSETS */
  4412.  
  4413.     /* PUT THE FILE */
  4414.  
  4415.     t0 = gmstimer();                    /* Start time */
  4416.     if (flg & PUT_SIM) {                /* rc > 0 is a skip reason code */
  4417.         if (flg & (PUT_UPD|PUT_DIF)) {    /* (see SKP_xxx in ckcker.h) */
  4418.             rc = (mt < 0) ?             /* Update mode... */
  4419.               SKP_XNX :                 /* Remote file doesn't exist */
  4420.                 SKP_XUP;                /* Remote file is older */
  4421.         } else {
  4422.             rc = SKP_SIM;               /* "Would be sent", period. */
  4423.         }
  4424.     } else {
  4425.         rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
  4426.     }
  4427.     t1 = gmstimer();                    /* End time */
  4428.     filcnt++;                           /* File number */
  4429.  
  4430. #ifdef GFTIMER
  4431.     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  4432.     fpxfsecs = sec;                     /* (for doxlog()) */
  4433. #else
  4434.     sec = (t1 - t0) / 1000;
  4435.     xfsecs = (int)sec;
  4436. #endif /* GFTIMER */
  4437.  
  4438.     debug(F111,"ftp sendrequest rc",local,rc);
  4439.  
  4440.     if (cancelfile || cancelgroup) {
  4441.         debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
  4442.         ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
  4443.     } else if (rc > 0) {
  4444.         debug(F101,"ftp put skipped",local,rc);
  4445.         ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
  4446.     } else if (rc < 0) {
  4447.         debug(F111,"ftp put error",local,ftpcode);
  4448.         ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
  4449.     } else {
  4450.         debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
  4451.         ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
  4452.         debug(F111,"ftp put ST_OK",local,rc);
  4453.         ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
  4454.         debug(F110,"ftp put old sfspec",sfspec,0);
  4455.         makestr(&sfspec,fullname);      /* For WHERE command */
  4456.         debug(F110,"ftp put new sfspec",sfspec,0);
  4457.         debug(F110,"ftp put old srfspec",srfspec,0);
  4458.         makestr(&srfspec,asname);
  4459.         debug(F110,"ftp put new srfspec",srfspec,0);
  4460.     }
  4461.  
  4462.     /* Final log entries */
  4463.  
  4464. #ifdef TLOG
  4465.     if (tralog) {
  4466.         if (rc > 0) {
  4467.             if (rc == SKP_XNX)
  4468.               tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
  4469.             else if (rc == SKP_XUP)
  4470.               tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
  4471.             else if (rc == SKP_SIM)
  4472.               tlog(F100," /simulate: WOULD BE SENT","",0);
  4473.             else
  4474.               tlog(F110," skipped:",gskreason(rc),0);
  4475.         } else if (rc == 0) {
  4476.             tlog(F101," complete, size", "", fsize);
  4477.         } else if (cancelfile) {
  4478.             tlog(F100," canceled by user","",0);
  4479.         } else {
  4480.             tlog(F110," failed:",ftp_reply_str,0);
  4481.         }
  4482.         if (!tlogfmt)
  4483.           doxlog(what,local,fsize,ftp_typ,rc,"");
  4484.     }
  4485. #endif /* TLOG */
  4486.  
  4487.     if (rc < 0)                         /* PUT did not succeed */
  4488.       return(-1);                       /* so done. */
  4489.  
  4490.     if (flg & PUT_SIM)                  /* Simulating, skip the rest. */
  4491.       return(SKP_SIM);
  4492.  
  4493. #ifdef UNIX
  4494.     /* Set permissions too? */
  4495.  
  4496.     if (prm) {                          /* Change permissions? */
  4497.         s = zgperm(local);              /* Get perms of local file */
  4498.         if (!s) s = "";
  4499.         x = strlen(s);
  4500.         if (x > 3) s += (x - 3);
  4501.         if (rdigits(s)) {
  4502.             ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
  4503.             x =
  4504.               ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
  4505.             tlog(F110, x ? " chmod" : " chmod failed",
  4506.                  s,
  4507.                  0
  4508.                  );
  4509.             if (!x)
  4510.               return(-1);
  4511.         }
  4512.     }
  4513. #endif /* UNIX */
  4514.  
  4515.     /* Disposition of source file */
  4516.  
  4517.     if (moving) {
  4518.         x = zdelet(local);
  4519.         tlog(F110, (x > -1) ?
  4520.              " deleted" : " failed to delete",
  4521.              local,
  4522.              0
  4523.              );
  4524.         if (x < 0)
  4525.           return(-1);
  4526.     } else if (mvto) {
  4527.         x = zrename(local,mvto);
  4528.         tlog(F110, (x > -1) ?
  4529.              " moved source to" : " failed to move source to",
  4530.              mvto,
  4531.              0
  4532.              );
  4533.         if (x < 0)
  4534.           return(-1);
  4535.         /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
  4536.  
  4537.     } else if (rnto) {
  4538.         char * s = rnto;
  4539. #ifndef NOSPL
  4540.         int y;                          /* Pass it thru the evaluator */
  4541.         extern int cmd_quoting;         /* for \v(filename) */
  4542.         if (cmd_quoting) {              /* But only if cmd_quoting is on */
  4543.             y = CKMAXPATH;
  4544.             s = (char *)asname;
  4545.             zzstring(rnto,&s,&y);
  4546.             s = (char *)asname;
  4547.         }
  4548. #endif /* NOSPL */
  4549.         if (s) if (*s) {
  4550.             int x;
  4551.             x = zrename(local,s);
  4552.             tlog(F110, (x > -1) ?
  4553.                  " renamed source file to" :
  4554.                  " failed to rename source file to",
  4555.                  s,
  4556.                  0
  4557.                  );
  4558.             if (x < 0)
  4559.               return(-1);
  4560.             /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
  4561.         }
  4562.     }
  4563.  
  4564.     /* Disposition of destination file */
  4565.  
  4566.     if (srvrn) {                        /* /SERVER-RENAME: */
  4567.         char * s = srvrn;
  4568. #ifndef NOSPL
  4569.         int y;                          /* Pass it thru the evaluator */
  4570.         extern int cmd_quoting; /* for \v(filename) */
  4571.         debug(F111,"ftp putfile srvrn",s,1);
  4572.  
  4573.         if (cmd_quoting) {              /* But only if cmd_quoting is on */
  4574.             y = CKMAXPATH;
  4575.             s = (char *)fullname;       /* We can recycle this buffer now */
  4576.             zzstring(srvrn,&s,&y);
  4577.             s = (char *)fullname;
  4578.         }
  4579. #endif /* NOSPL */
  4580.         debug(F111,"ftp putfile srvrn",s,2);
  4581.         if (s) if (*s) {
  4582.             int x;
  4583.             x = ftp_rename(asname,s);
  4584.             debug(F111,"ftp putfile ftp_rename",asname,x);
  4585.             tlog(F110, (x > 0) ?
  4586.                  " renamed destination file to" :
  4587.                  " failed to rename destination file to",
  4588.                  s,
  4589.                  0
  4590.                  );
  4591.             if (x < 1)
  4592.               return(-1);
  4593.         }
  4594.     }
  4595.     return(0);
  4596. }
  4597.  
  4598. /* xxout must only be used for ASCII transfers */
  4599. static int
  4600. #ifdef CK_ANSIC
  4601. xxout(char c)
  4602. #else
  4603. xxout(c) char c;
  4604. #endif /* CK_ANSIC */
  4605. {
  4606. #ifndef OS2
  4607. #ifndef VMS
  4608. #ifndef MAC
  4609. #ifndef OSK
  4610.     /* For Unix, DG, Stratus, Amiga, Gemdos, other */
  4611.     if (c == '\012') {
  4612.     if (zzout(dout,(CHAR)'\015') < 0)
  4613.       return(-1);
  4614.     ftpsnd.bytes++;
  4615.     }
  4616. #else /* OSK */
  4617.     if (c == '\015') {
  4618.     c = '\012';
  4619.     if (zzout(dout,(CHAR)'\015') < 0)
  4620.       return(-1);
  4621.     ftpsnd.bytes++;
  4622.     }
  4623. #endif /* OSK */
  4624. #else /* MAC */
  4625.     if (c == '\015') {
  4626.     c = '\012';
  4627.     if (zzout(dout,(CHAR)'\015') < 0)
  4628.       return(-1);
  4629.     ftpsnd.bytes++;
  4630.     }
  4631. #endif /* MAC */
  4632. #endif /* VMS */
  4633. #endif /* OS2 */
  4634.     if (zzout(dout,(CHAR)c) < 0)
  4635.       return(-1);
  4636.     ftpsnd.bytes++;
  4637.     return(0);
  4638. }
  4639.  
  4640. static int
  4641. #ifdef CK_ANSIC
  4642. scrnout(char c)
  4643. #else
  4644. scrnout(c) char c;
  4645. #endif /* CK_ANSIC */
  4646. {
  4647.     return(putchar(c));
  4648. }
  4649.  
  4650. static int
  4651. #ifdef CK_ANSIC
  4652. pipeout(char c)
  4653. #else
  4654. pipeout(c) char c;
  4655. #endif /* CK_ANSIC */
  4656. {
  4657.     return(zmchout(c));
  4658. }
  4659.  
  4660. static int
  4661. ispathsep(c) int c; {
  4662.     switch (servertype) {
  4663.       case SYS_VMS:
  4664.       case SYS_TOPS10:
  4665.       case SYS_TOPS20:
  4666.         return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
  4667.       case SYS_OS2:
  4668.       case SYS_WIN32:
  4669.       case SYS_DOS:
  4670.         return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
  4671.       case SYS_VOS:
  4672.         return((c == '>') ? 1 : 0);
  4673.       default:
  4674.         return((c == '/') ? 1 : 0);
  4675.     }
  4676. }
  4677.  
  4678. static int
  4679. iscanceled() {
  4680. #ifdef CK_CURSES
  4681.     extern int ck_repaint();
  4682. #endif /* CK_CURSES */
  4683.     int x, rc = 0;
  4684.     char c = 0;
  4685.     if (cancelfile)
  4686.       return(1);
  4687.     x = conchk();                       /* Any chars waiting at console? */
  4688.     if (x-- > 0) {                      /* Yes...  */
  4689.         c = coninc(5);                  /* Get one */
  4690.         switch (c) {
  4691.           case 032:                     /* Ctrl-X or X */
  4692.           case 'z':
  4693.           case 'Z': cancelgroup++;      /* fall thru on purpose */
  4694.           case 030:                     /* Ctrl-Z or Z */
  4695.           case 'x':
  4696.           case 'X': cancelfile++; rc++; break;
  4697. #ifdef CK_CURSES
  4698.           case 'L':
  4699.           case 'l':
  4700.           case 014:                     /* Ctrl-L or L or Ctrl-W */
  4701.           case 027:
  4702.             ck_repaint();               /* Refresh screen */
  4703. #endif /* CK_CURSES */
  4704.         }
  4705.     }
  4706.     while (x-- > 0)                     /* Soak up any rest */
  4707.       c = coninc(1);
  4708.     return(rc);
  4709. }
  4710.  
  4711. #ifdef FTP_TIMEOUT
  4712. /* fc = 0 for read; 1 for write */
  4713. static int
  4714. check_data_connection(fd,fc) int fd, fc; {
  4715.     int x;
  4716.     struct timeval tv;
  4717.     fd_set in, out, err;
  4718.  
  4719.     if (ftp_timeout < 1L)
  4720.       return(0);
  4721.  
  4722.     FD_ZERO(&in);
  4723.     FD_ZERO(&out);
  4724.     FD_ZERO(&err);
  4725.     FD_SET(fd,fc ? &out : &in);
  4726.     tv.tv_sec = ftp_timeout;        /* Time limit */
  4727.     tv.tv_usec = 0L;
  4728.  
  4729. #ifdef INTSELECT
  4730.     x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
  4731. #else
  4732.     x = select(FD_SETSIZE,&in,&out,&err,&tv);
  4733. #endif /* INTSELECT */
  4734.  
  4735.     if (x == 0) {
  4736. #ifdef EWOULDBLOCK
  4737.     errno = EWOULDBLOCK;
  4738. #else
  4739. #ifdef EAGAIN
  4740.     errno = EAGAIN;
  4741. #else
  4742.     errno = 11;
  4743. #endif    /* EAGAIN */
  4744. #endif    /* EWOULDBLOCK */
  4745.     debug(F100,"ftp check_data_connection TIMOUT","",0);
  4746.     return(-3);
  4747.     }
  4748.     return(0);
  4749. }
  4750. #endif    /* FTP_TIMEOUT */
  4751.  
  4752. /* zzsend - used by buffered output macros. */
  4753.  
  4754. static int
  4755. #ifdef CK_ANSIC
  4756. zzsend(int fd, CHAR c)
  4757. #else
  4758. zzsend(fd,c) int fd; CHAR c;
  4759. #endif /* CK_ANSIC */
  4760. {
  4761.     int rc;
  4762.  
  4763.     debug(F101,"zzsend ucbufsiz","",ucbufsiz);
  4764.     debug(F101,"zzsend nout","",nout);
  4765.     debug(F111,"zzsend","secure?",ftpissecure());
  4766.  
  4767.     if (iscanceled())                   /* Check for cancellation */
  4768.       return(-9);
  4769.  
  4770. #ifdef FTP_TIMEOUT    
  4771.     ftp_timed_out = 0;
  4772.     if (check_data_connection(fd,1) < 0) {
  4773.     ftp_timed_out = 1;
  4774.     return(-3);
  4775.     }
  4776. #endif    /* FTP_TIMEOUT */
  4777.  
  4778.     rc = (!ftpissecure()) ?
  4779.       send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
  4780.         secure_putbuf(fd, ucbuf, nout);
  4781.     ucbuf[nout] = NUL;
  4782.     nout = 0;
  4783.     ucbuf[nout++] = c;
  4784.     spackets++;
  4785.     pktnum++;
  4786.     if (rc > -1 && fdispla != XYFD_B) {
  4787.         spktl = nout;
  4788.         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
  4789.     }
  4790.     return(rc);
  4791. }
  4792.  
  4793. /* c m d l i n p u t  --  Command-line PUT */
  4794.  
  4795. int
  4796. cmdlinput(stay) int stay; {
  4797.     int x, rc = 0, done = 0, good = 0, status = 0;
  4798.     ULONG t0, t1;                       /* Times for stats */
  4799. #ifdef GFTIMER
  4800.     CKFLOAT sec;
  4801. #else
  4802.     int sec = 0;
  4803. #endif /* GFTIMER */
  4804.  
  4805.     if (quiet) {                        /* -q really means quiet */
  4806.         displa = 0;
  4807.         fdispla = 0;
  4808.     } else {
  4809.         displa = 1;
  4810.         fdispla = XYFD_B;
  4811.     }
  4812.     testing = 0;
  4813.     out2screen = 0;
  4814.     dpyactive = 0;
  4815.     what = W_FTP|W_SEND;
  4816.  
  4817. #ifndef NOSPL
  4818.     cmd_quoting = 0;
  4819. #endif /* NOSPL */
  4820.     sndsrc = nfils;
  4821.  
  4822.     t0 = gmstimer();                    /* Record starting time */
  4823.  
  4824.     while (!done && !cancelgroup) {     /* Loop for all files */
  4825.  
  4826.         cancelfile = 0;
  4827.         x = gnfile();                   /* Get next file from list(s) */
  4828.         if (x == 0)                     /* (see gnfile() comments...) */
  4829.           x = gnferror;
  4830.  
  4831.         switch (x) {
  4832.           case 1:                       /* File to send */
  4833.             rc = putfile(FTP_PUT,       /* Function (PUT, APPEND) */
  4834.                          filnam,        /* Local file to send */
  4835.                          filnam,        /* Remote name for file */
  4836.                          forcetype,     /* Text/binary mode forced */
  4837.                          0,             /* Not moving */
  4838.                          NULL,          /* No move-to */
  4839.                          NULL,          /* No rename-to */
  4840.                          NULL,          /* No server-rename */
  4841.                          ftp_cnv,       /* Filename conversion */
  4842.                          0,             /* Unique-server-names */
  4843.                          -1,            /* All file types */
  4844.                          0,             /* No permissions */
  4845.                          -1,            /* No character sets */
  4846.                          -1,            /* No character sets */
  4847.                          0              /* No update or restart */
  4848.                          );
  4849.             if (rc > -1) {
  4850.                 good++;
  4851.                 status = 1;
  4852.             }
  4853.             if (cancelfile) {
  4854.                 continue;               /* Or break? */
  4855.             }
  4856.             if (rc < 0) {
  4857.                 ftp_fai++;
  4858.             }
  4859.             continue;                   /* Or break? */
  4860.  
  4861.           case 0:                       /* No more files, done */
  4862.             done++;
  4863.             continue;
  4864.  
  4865.           case -2:
  4866.           case -1:
  4867.             printf("?%s: file not found - \"%s\"\n",
  4868.                    puterror ? "Fatal" : "Warning",
  4869.                    filnam
  4870.                    );
  4871.             continue;                   /* or break? */
  4872.           case -3:
  4873.             printf("?Warning access denied - \"%s\"\n", filnam);
  4874.             continue;                   /* or break? */
  4875.           case -5:
  4876.             printf("?Too many files match\n");
  4877.             done++;
  4878.             break;
  4879.           case -6:
  4880.             if (good < 1)
  4881.               printf("?No files selected\n");
  4882.             done++;
  4883.             break;
  4884.           default:
  4885.             printf("?getnextfile() - unknown failure\n");
  4886.             done++;
  4887.         }
  4888.     }
  4889.     if (status > 0) {
  4890.         if (cancelgroup)
  4891.           status = 0;
  4892.         else if (cancelfile && good < 1)
  4893.           status = 0;
  4894.     }
  4895.     success = status;
  4896.     x = success;
  4897.     if (x > -1) {
  4898.         lastxfer = W_FTP|W_SEND;
  4899.         xferstat = success;
  4900.     }
  4901.     t1 = gmstimer();                    /* End time */
  4902. #ifdef GFTIMER
  4903.     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  4904.     if (!sec) sec = 0.001;
  4905.     fptsecs = sec;
  4906. #else
  4907.     sec = (t1 - t0) / 1000;
  4908.     if (!sec) sec = 1;
  4909. #endif /* GFTIMER */
  4910.     tfcps = (long) (tfc / sec);
  4911.     tsecs = (int)sec;
  4912.     lastxfer = W_FTP|W_SEND;
  4913.     xferstat = success;
  4914.     if (dpyactive)
  4915.       ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
  4916.     if (!stay)
  4917.       doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
  4918.     return(success);
  4919. }
  4920.  
  4921.  
  4922. /*  d o f t p p u t  --  Parse and execute PUT, MPUT, and APPEND  */
  4923.  
  4924. int
  4925. #ifdef CK_ANSIC
  4926. doftpput(int cx, int who)               /* who == 1 for ftp, 0 for kermit */
  4927. #else
  4928. doftpput(cx,who) int cx, who;
  4929. #endif /* CK_ANSIC */
  4930. {
  4931.     struct FDB sf, fl, sw, cm;
  4932.     int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
  4933.     int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
  4934.     char * s, * s2;
  4935.  
  4936.     int x_csl, x_csr = -1;              /* Local and remote charsets */
  4937.     int x_xla = 0;
  4938.     int x_recurse = 0;
  4939.     char c, * p;                        /* Workers */
  4940. #ifdef PUTARRAY
  4941.     int range[2];                       /* Array range */
  4942.     char ** ap = NULL;                  /* Array pointer */
  4943.     int arrayx = -1;                    /* Array index */
  4944. #endif /* PUTARRAY */
  4945.     ULONG t0 = 0L, t1 = 0L;             /* Times for stats */
  4946. #ifdef GFTIMER
  4947.     CKFLOAT sec;
  4948. #else
  4949.     int sec = 0;
  4950. #endif /* GFTIMER */
  4951.  
  4952.     struct stringint pv[SND_MAX+1];    /* Temporary array for switch values */
  4953.     success = 0;                        /* Assume failure */
  4954.     forcetype = 0;                      /* No /TEXT or /BINARY given yet */
  4955.     out2screen = 0;                     /* Not outputting file to screen */
  4956.     putflags = 0;                       /* PUT options */
  4957.     x_cnv = ftp_cnv;                    /* Filename conversion */
  4958.     x_usn = ftp_usn;                    /* Unique server names */
  4959.     x_prm = ftp_prm;                    /* Permissions */
  4960.     if (x_prm == SET_AUTO)              /* Permissions AUTO */
  4961.       x_prm = alike;
  4962.  
  4963. #ifndef NOCSETS
  4964.     x_csr = ftp_csr;                    /* Inherit global server charset */
  4965.     x_csl = ftp_csl;
  4966.     if (x_csl < 0)
  4967.       x_csl = fcharset;
  4968.     x_xla = ftp_xla;
  4969. #endif /* NOCSETS */
  4970.  
  4971.     makestr(&filefile,NULL);            /* No filename list file yet. */
  4972.     makestr(&srv_renam,NULL);        /* Clear /SERVER-RENAME: */
  4973.     makestr(&snd_rename,NULL);        /*  PUT /RENAME */
  4974.     makestr(&snd_move,NULL);        /*  PUT /MOVE */
  4975.     putpath[0] = NUL;                   /* Initialize for syncdir(). */
  4976.     puterror = ftp_err;                 /* Inherit global error action. */
  4977.     what = W_SEND|W_FTP;                /* What we're doing (sending w/FTP) */
  4978.     asnambuf[0] = NUL;                  /* Clear as-name buffer */
  4979.  
  4980.     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
  4981.         ftp_typ = g_ftp_typ;
  4982.         /* g_ftp_typ = -1; */
  4983.     }
  4984.     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
  4985.         pv[i].sval = NULL;              /* to null pointers */
  4986.         pv[i].ival = -1;                /* and -1 int values */
  4987.         pv[i].wval = (CK_OFF_T)-1;    /* and -1 wide values */
  4988.     }
  4989.     if (who == 0) {                     /* Called with unprefixed command */
  4990.         switch (cx) {
  4991.           case XXRSEN:  pv[SND_RES].ival = 1; break;
  4992.           case XXCSEN:  pv[SND_CMD].ival = 1; break;
  4993.           case XXMOVE:  pv[SND_DEL].ival = 1; break;
  4994.           case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
  4995.           case XXMSE:   mput++; break;
  4996.         }
  4997.     } else {
  4998.     if (cx == FTP_REP)
  4999.       pv[SND_RES].ival = 1;
  5000.         if (cx == FTP_MPU)
  5001.           mput++;
  5002.     }
  5003.     cmfdbi(&sw,                         /* First FDB - command switches */
  5004.            _CMKEY,                      /* fcode */
  5005.            "Filename, or switch",       /* hlpmsg */
  5006.            "",                          /* default */
  5007.            "",                          /* addtl string data */
  5008.            nputswi,                     /* addtl numeric data 1: tbl size */
  5009.            4,                           /* addtl numeric data 2: 4 = cmswi */
  5010.            xxstring,                    /* Processing function */
  5011.            putswi,                      /* Keyword table */
  5012.            &sf                          /* Pointer to next FDB */
  5013.            );
  5014.     cmfdbi(&fl,                         /* 3rd FDB - local filespec */
  5015.            _CMFLD,                      /* fcode */
  5016.            "",                          /* hlpmsg */
  5017.            "",                          /* default */
  5018.            "",                          /* addtl string data */
  5019.            0,                           /* addtl numeric data 1 */
  5020.            0,                           /* addtl numeric data 2 */
  5021.            xxstring,
  5022.            NULL,
  5023.            &cm
  5024.            );
  5025.     cmfdbi(&cm,                         /* 4th FDB - Confirmation */
  5026.            _CMCFM,                      /* fcode */
  5027.            "",                          /* hlpmsg */
  5028.            "",                          /* default */
  5029.            "",                          /* addtl string data */
  5030.            0,                           /* addtl numeric data 1 */
  5031.            0,                           /* addtl numeric data 2 */
  5032.            NULL,
  5033.            NULL,
  5034.            NULL
  5035.            );
  5036.  
  5037.   again:
  5038.     cmfdbi(&sf,                         /* 2nd FDB - file to send */
  5039.            _CMIFI,                      /* fcode */
  5040.            "",                          /* hlpmsg */
  5041.            "",                          /* default */
  5042.            "",                          /* addtl string data */
  5043.            /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
  5044.            nolinks | x_recurse,         /* addtl numeric data 1 */
  5045.            0,                           /* dirflg 0 means "not dirs only" */
  5046.            xxstring,
  5047.            NULL,
  5048. #ifdef COMMENT
  5049.            mput ? &cm : &fl
  5050. #else
  5051.        &fl
  5052. #endif /* COMMENT */
  5053.            );
  5054.  
  5055.     while (1) {                         /* Parse zero or more switches */
  5056.         x = cmfdb(&sw);                 /* Parse something */
  5057.         debug(F101,"ftp put cmfdb A","",x);
  5058.         debug(F101,"ftp put fcode A","",cmresult.fcode);
  5059.         if (x < 0)                      /* Error */
  5060.           goto xputx;                   /* or reparse needed */
  5061.         if (cmresult.fcode != _CMKEY)   /* Break out of loop if not a switch */
  5062.           break;
  5063.         c = cmgbrk();                   /* Get break character */
  5064.         getval = (c == ':' || c == '='); /* to see how they ended the switch */
  5065.         if (getval && !(cmresult.kflags & CM_ARG)) {
  5066.             printf("?This switch does not take arguments\n");
  5067.             x = -9;
  5068.             goto xputx;
  5069.         }
  5070.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  5071.             printf("?This switch requires an argument\n");
  5072.             x = -9;
  5073.             goto xputx;
  5074.         }
  5075.         n = cmresult.nresult;           /* Numeric result = switch value */
  5076.         debug(F101,"ftp put switch","",n);
  5077.  
  5078.         switch (n) {                    /* Process the switch */
  5079.           case SND_AFT:                 /* Send /AFTER:date-time */
  5080.           case SND_BEF:                 /* Send /BEFORE:date-time */
  5081.           case SND_NAF:                 /* Send /NOT-AFTER:date-time */
  5082.           case SND_NBE:                 /* Send /NOT-BEFORE:date-time */
  5083.             if (!getval) break;
  5084.             if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
  5085.                 if (x == -3) {
  5086.                     printf("?Date-time required\n");
  5087.                     x = -9;
  5088.                 }
  5089.                 goto xputx;
  5090.             }
  5091.             pv[n].ival = 1;
  5092.             makestr(&(pv[n].sval),s);
  5093.             break;
  5094.  
  5095.           case SND_ASN:                 /* /AS-NAME: */
  5096.             debug(F101,"ftp put /as-name getval","",getval);
  5097.             if (!getval) break;
  5098.             if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
  5099.                 if (x == -3) {
  5100.                     printf("?name required\n");
  5101.                     x = -9;
  5102.                 }
  5103.                 goto xputx;
  5104.             }
  5105.             makestr(&(pv[n].sval),brstrip(s));
  5106.             debug(F110,"ftp put /as-name 1",pv[n].sval,0);
  5107.             if (pv[n].sval) pv[n].ival = 1;
  5108.             break;
  5109.  
  5110. #ifdef PUTARRAY
  5111.           case SND_ARR:                 /* /ARRAY */
  5112.             if (!getval) break;
  5113.             ap = NULL;
  5114.             if ((x = cmfld("Array name (a single letter will do)",
  5115.                            "",
  5116.                            &s,
  5117.                            NULL
  5118.                            )) < 0) {
  5119.                 if (x == -3)
  5120.           break;
  5121.         else
  5122.           return(x);
  5123.             }
  5124.             if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
  5125.                 printf("?Bad array: %s\n",s);
  5126.                 return(-9);
  5127.             }
  5128.             if (!(ap = a_ptr[x])) {
  5129.                 printf("?No such array: %s\n",s);
  5130.                 return(-9);
  5131.             }
  5132.             pv[n].ival = 1;
  5133.             pv[SND_CMD].ival = 0;       /* Undo any conflicting ones... */
  5134.             pv[SND_RES].ival = 0;
  5135.             pv[SND_FIL].ival = 0;
  5136.             arrayx = x;
  5137.             break;
  5138. #endif /* PUTARRAY */
  5139.  
  5140.           case SND_BIN:                 /* /BINARY */
  5141.           case SND_TXT:                 /* /TEXT or /ASCII */
  5142.           case SND_TEN:                 /* /TENEX */
  5143.             pv[SND_BIN].ival = 0;
  5144.             pv[SND_TXT].ival = 0;
  5145.             pv[SND_TEN].ival = 0;
  5146.             pv[n].ival = 1;
  5147.             break;
  5148.  
  5149. #ifdef PUTPIPE
  5150.           case SND_CMD:                 /* These take no args */
  5151.             if (nopush) {
  5152.                 printf("?Sorry, system command access is disabled\n");
  5153.                 x = -9;
  5154.                 goto xputx;
  5155.             }
  5156. #ifdef PIPESEND
  5157.             else if (sndfilter) {
  5158.                 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
  5159.                 x = -9;
  5160.                 goto xputx;
  5161.             }
  5162. #endif /* PIPESEND */
  5163.             sw.hlpmsg = "Command, or switch"; /* Change help message */
  5164.             pv[n].ival = 1;             /* Just set the flag */
  5165.             pv[SND_ARR].ival = 0;
  5166.             break;
  5167. #endif /* PUTPIPE */
  5168.  
  5169. #ifdef CKSYMLINK
  5170.           case SND_LNK:
  5171.             nolinks = 0;
  5172.             goto again;            /* Because CMIFI params changed... */
  5173.           case SND_NLK:
  5174.             nolinks = 2;
  5175.             goto again;
  5176. #endif /* CKSYMLINK */
  5177.  
  5178. #ifdef FTP_RESTART
  5179.           case SND_RES:                 /* /RECOVER (resend) */
  5180.             pv[SND_ARR].ival = 0;       /* fall thru on purpose... */
  5181. #endif /* FTP_RESTART */
  5182.  
  5183.           case SND_NOB:
  5184.           case SND_DEL:                 /* /DELETE */
  5185.           case SND_SHH:                 /* /QUIET */
  5186.           case SND_UPD:                 /* /UPDATE */
  5187.           case SND_SIM:                 /* /UPDATE */
  5188.           case SND_USN:                 /* /UNIQUE */
  5189.             pv[n].ival = 1;             /* Just set the flag */
  5190.             break;
  5191.  
  5192.           case SND_REC:                 /* /RECURSIVE */
  5193.             recursive = 2;              /* Must be set before cmifi() */
  5194.             x_recurse = 1;
  5195.             goto again;            /* Because CMIFI params changed... */
  5196.             break;
  5197.  
  5198. #ifdef UNIXOROSK
  5199.           case SND_DOT:                 /* /DOTFILES */
  5200.             matchdot = 1;
  5201.             break;
  5202.           case SND_NOD:                 /* /NODOTFILES */
  5203.             matchdot = 0;
  5204.             break;
  5205. #endif /* UNIXOROSK */
  5206.  
  5207.           case SND_ERR:                 /* /ERROR-ACTION */
  5208.             if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
  5209.               goto xputx;
  5210.             pv[n].ival = x;
  5211.             break;
  5212.  
  5213.           case SND_EXC:                 /* Excludes */
  5214.             if (!getval) break;
  5215.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  5216.                 if (x == -3) {
  5217.                     printf("?Pattern required\n");
  5218.                     x = -9;
  5219.                 }
  5220.                 goto xputx;
  5221.             }
  5222.             if (s) if (!*s) s = NULL;
  5223.             makestr(&(pv[n].sval),s);
  5224.             if (pv[n].sval)
  5225.               pv[n].ival = 1;
  5226.             break;
  5227.  
  5228.           case SND_PRM:                 /* /PERMISSIONS */
  5229.             if (!getval)
  5230.               x = 1;
  5231.             else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
  5232.               goto xputx;
  5233.             pv[SND_PRM].ival = x;
  5234.             break;
  5235.  
  5236. #ifdef PIPESEND
  5237.           case SND_FLT:                 /* /FILTER */
  5238.             debug(F101,"ftp put /filter getval","",getval);
  5239.             if (!getval) break;
  5240.             if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
  5241.                 if (x == -3)
  5242.                   s = "";
  5243.                 else
  5244.                   goto xputx;
  5245.             }
  5246.             if (*s) s = brstrip(s);
  5247.             y = strlen(s);
  5248.             for (x = 0; x < y; x++) {   /* Make sure they included "\v(...)" */
  5249.                 if (s[x] != '\\') continue;
  5250.                 if (s[x+1] == 'v') break;
  5251.             }
  5252.             if (x == y) {
  5253.                 printf(
  5254.                 "?Filter must contain a replacement variable for filename.\n"
  5255.                        );
  5256.                 x = -9;
  5257.                 goto xputx;
  5258.             }
  5259.             if (s) if (!*s) s = NULL;
  5260.             makestr(&(pv[n].sval),s);
  5261.             if (pv[n].sval)
  5262.               pv[n].ival = 1;
  5263.             break;
  5264. #endif /* PIPESEND */
  5265.  
  5266.           case SND_NAM:                 /* /FILENAMES */
  5267.             if (!getval) break;
  5268.             if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
  5269.               goto xputx;
  5270.             debug(F101,"ftp put /filenames","",x);
  5271.             pv[n].ival = x;
  5272.             break;
  5273.  
  5274.           case SND_SMA:                 /* Smaller / larger than */
  5275.           case SND_LAR: {
  5276.           CK_OFF_T y;
  5277.           if (!getval) break;
  5278.           if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
  5279.         goto xputx;
  5280.           pv[n].wval = y;
  5281.           break;
  5282.       }
  5283.           case SND_FIL:                 /* Name of file containing filenames */
  5284.             if (!getval) break;
  5285.             if ((x = cmifi("Name of file containing list of filenames",
  5286.                                "",&s,&y,xxstring)) < 0) {
  5287.                 if (x == -3) {
  5288.                     printf("?Filename required\n");
  5289.                     x = -9;
  5290.                 }
  5291.                 goto xputx;
  5292.             } else if (y && iswild(s)) {
  5293.                 printf("?Wildcards not allowed\n");
  5294.                 x = -9;
  5295.                 goto xputx;
  5296.             }
  5297.             if (s) if (!*s) s = NULL;
  5298.             makestr(&(pv[n].sval),s);
  5299.             if (pv[n].sval) {
  5300.                 pv[n].ival = 1;
  5301.                 pv[SND_ARR].ival = 0;
  5302.             } else {
  5303.                 pv[n].ival = 0;
  5304.             }
  5305.             mput = 0;
  5306.             break;
  5307.  
  5308.           case SND_MOV:                 /* MOVE after */
  5309.           case SND_REN:                 /* RENAME after */
  5310.           case SND_SRN: {               /* SERVER-RENAME after */
  5311.               char * m = "";
  5312.               switch (n) {
  5313.                 case SND_MOV:
  5314.                   m = "device and/or directory for source file after sending";
  5315.                   break;
  5316.                 case SND_REN:
  5317.                   m = "new name for source file after sending";
  5318.                   break;
  5319.                 case SND_SRN:
  5320.                   m = "new name for destination file after sending";
  5321.                   break;
  5322.               }
  5323.               if (!getval) break;
  5324.               if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
  5325.                   if (x == -3) {
  5326.                       printf("%s\n", n == SND_MOV ?
  5327.                              "?Destination required" :
  5328.                              "?New name required"
  5329.                              );
  5330.                       x = -9;
  5331.                   }
  5332.                   goto xputx;
  5333.               }
  5334.               if (s) if (!*s) s = NULL;
  5335.               makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
  5336.               pv[n].ival = (pv[n].sval) ? 1 : 0;
  5337.               break;
  5338.           }
  5339.           case SND_STA:                 /* Starting position (= PSEND) */
  5340.             if (!getval) break;
  5341.             if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
  5342.               goto xputx;
  5343.             pv[n].ival = y;
  5344.             break;
  5345.  
  5346.           case SND_TYP:                 /* /TYPE */
  5347.             if (!getval) break;
  5348.             if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
  5349.               goto xputx;
  5350.             pv[n].ival = (x == 2) ? -1 : x;
  5351.             break;
  5352.  
  5353. #ifndef NOCSETS
  5354.           case SND_CSL:                 /* Local character set */
  5355.           case SND_CSR:                 /* Remote (server) charset */
  5356.             if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
  5357.         return((x == -3) ? -2 : x);
  5358.             }
  5359.         if (n == SND_CSL)
  5360.               x_csl = x;
  5361.             else
  5362.               x_csr = x;
  5363.             x_xla = 1;                  /* Overrides global OFF setting */
  5364.             break;
  5365.  
  5366.           case SND_XPA:                 /* Transparent */
  5367.             x_xla = 0;
  5368.             x_csr = -1;
  5369.             x_csl = -1;
  5370.             break;
  5371. #endif /* NOCSETS */
  5372.         }
  5373.     }
  5374. #ifdef PIPESEND
  5375.     if (pv[SND_RES].ival > 0) { /* /RECOVER */
  5376.         if (sndfilter || pv[SND_FLT].ival > 0) {
  5377.             printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
  5378.             x = -9;
  5379.             goto xputx;
  5380.         }
  5381.     if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
  5382.       printf("WARNING: Server says it doesn't support REST.\n");
  5383.     }
  5384. #endif /* PIPESEND */
  5385.  
  5386.     cmarg = "";
  5387.     cmarg2 = asnambuf;
  5388.     line[0] = NUL;
  5389.     s = line;
  5390.     wild = 0;
  5391.  
  5392.     switch (cmresult.fcode) {           /* How did we get out of switch loop */
  5393.       case _CMIFI:                      /* Input filename */
  5394.         if (pv[SND_FIL].ival > 0) {
  5395.             printf("?You may not give a PUT filespec and a /LISTFILE\n");
  5396.             x = -9;
  5397.             goto xputx;
  5398.         }
  5399.         ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
  5400.         if (pv[SND_ARR].ival > 0)
  5401.           ckstrncpy(asnambuf,line,CKMAXPATH);
  5402.         else
  5403.           wild = cmresult.nresult;      /* Wild flag */
  5404.         debug(F111,"ftp put wild",line,wild);
  5405.         if (!wild && !recursive && !mput)
  5406.           nolinks = 0;
  5407.         break;
  5408.       case _CMFLD:                      /* Field */
  5409.         /* Only allowed with /COMMAND and /ARRAY */
  5410.         if (pv[SND_FIL].ival > 0) {
  5411.             printf("?You may not give a PUT filespec and a /LISTFILE\n");
  5412.             x = -9;
  5413.             goto xputx;
  5414.         }
  5415.     /* For MPUT it's OK to have filespecs that don't match any files */
  5416.     if (mput)
  5417.       break;
  5418.         if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
  5419. #ifdef CKROOT
  5420.             if (ckrooterr)
  5421.               printf("?Off limits: %s\n",cmresult.sresult);
  5422.             else
  5423. #endif /* CKROOT */
  5424.               printf("?%s - \"%s\"\n",
  5425.                    iswild(cmresult.sresult) ?
  5426.                    "No files match" : "File not found",
  5427.                    cmresult.sresult
  5428.                    );
  5429.             x = -9;
  5430.             goto xputx;
  5431.         }
  5432.         ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
  5433.         if (pv[SND_ARR].ival > 0)
  5434.           ckstrncpy(asnambuf,line,CKMAXPATH);
  5435.         break;
  5436.       case _CMCFM:                      /* Confirmation */
  5437.         confirmed = 1;
  5438.         break;
  5439.       default:
  5440.         printf("?Unexpected function code: %d\n",cmresult.fcode);
  5441.         x = -9;
  5442.         goto xputx;
  5443.     }
  5444.     debug(F110,"ftp put string",s,0);
  5445.     debug(F101,"ftp put confirmed","",confirmed);
  5446.  
  5447.     /* Save and change protocol and transfer mode */
  5448.     /* Global values are restored in main parse loop */
  5449.  
  5450.     g_displa = fdispla;
  5451.     if (ftp_dis > -1)
  5452.       fdispla = ftp_dis;
  5453.     g_skipbup = skipbup;
  5454.  
  5455.     if (pv[SND_NOB].ival > -1) {        /* /NOBACKUP (skip backup file) */
  5456.         g_skipbup = skipbup;
  5457.         skipbup = 1;
  5458.     }
  5459.     if (pv[SND_TYP].ival > -1) {        /* /TYPE */
  5460.         xfiletype = pv[SND_TYP].ival;
  5461.         if (xfiletype == 2)
  5462.           xfiletype = -1;
  5463.     }
  5464.     if (pv[SND_BIN].ival > 0) {         /* /BINARY really means binary... */
  5465.         forcetype = 1;                  /* So skip file scan */
  5466.         ftp_typ = FTT_BIN;              /* Set binary */
  5467.     } else if (pv[SND_TXT].ival > 0) {  /* Similarly for /TEXT... */
  5468.         forcetype = 1;
  5469.         ftp_typ = FTT_ASC;
  5470.     } else if (pv[SND_TEN].ival > 0) {  /* and /TENEX*/
  5471.         forcetype = 1;
  5472.         ftp_typ = FTT_TEN;
  5473.     } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
  5474.         forcetype = 1;
  5475.         ftp_typ = binary;
  5476.         g_ftp_typ = binary;
  5477.     }
  5478.  
  5479. #ifdef PIPESEND
  5480.     if (pv[SND_CMD].ival > 0) {         /* /COMMAND - strip any braces */
  5481.         debug(F110,"PUT /COMMAND before stripping",s,0);
  5482.         s = brstrip(s);
  5483.         debug(F110,"PUT /COMMAND after stripping",s,0);
  5484.         if (!*s) {
  5485.             printf("?Sorry, a command to send from is required\n");
  5486.             x = -9;
  5487.             goto xputx;
  5488.         }
  5489.         cmarg = s;
  5490.     }
  5491. #endif /* PIPESEND */
  5492.  
  5493. /* Set up /MOVE and /RENAME */
  5494.  
  5495.     if (pv[SND_DEL].ival > 0 &&
  5496.         (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
  5497.         printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
  5498.         x = -9;
  5499.         goto xputx;
  5500.     }
  5501. #ifdef CK_TMPDIR
  5502.     if (pv[SND_MOV].ival > 0) {
  5503.         int len;
  5504.         char * p = pv[SND_MOV].sval;
  5505.         len = strlen(p);
  5506.         if (!isdir(p)) {                /* Check directory */
  5507. #ifdef CK_MKDIR
  5508.             char * s = NULL;
  5509.             s = (char *)malloc(len + 4);
  5510.             if (s) {
  5511.                 strcpy(s,p);            /* safe */
  5512. #ifdef datageneral
  5513.                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
  5514. #else
  5515.                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
  5516. #endif /* datageneral */
  5517.                 s[len++] = 'X';
  5518.                 s[len] = NUL;
  5519. #ifdef NOMKDIR
  5520.                 x = -1;
  5521. #else
  5522.                 x = zmkdir(s);
  5523. #endif /* NOMKDIR */
  5524.                 free(s);
  5525.                 if (x < 0) {
  5526.                     printf("?Can't create \"%s\"\n",p);
  5527.                     x = -9;
  5528.                     goto xputx;
  5529.                 }
  5530.             }
  5531. #else
  5532.             printf("?Directory \"%s\" not found\n",p);
  5533.             x = -9;
  5534.             goto xputx;
  5535. #endif /* CK_MKDIR */
  5536.         }
  5537.         makestr(&snd_move,p);
  5538.     }
  5539. #endif /* CK_TMPDIR */
  5540.  
  5541.     if (pv[SND_REN].ival > 0) {         /* /RENAME */
  5542.         char * p = pv[SND_REN].sval;
  5543.         if (!p) p = "";
  5544.         if (!*p) {
  5545.             printf("?New name required for /RENAME\n");
  5546.             x = -9;
  5547.             goto xputx;
  5548.         }
  5549.         p = brstrip(p);
  5550. #ifndef NOSPL
  5551.     /* If name given is wild, rename string must contain variables */
  5552.         if (wild) {
  5553.             char * s = tmpbuf;
  5554.             x = TMPBUFSIZ;
  5555.             zzstring(p,&s,&x);
  5556.             if (!strcmp(tmpbuf,p)) {
  5557.                 printf(
  5558.     "?/RENAME for file group must contain variables such as \\v(filename)\n"
  5559.                        );
  5560.                 x = -9;
  5561.                 goto xputx;
  5562.             }
  5563.         }
  5564. #endif /* NOSPL */
  5565.         makestr(&snd_rename,p);
  5566.         debug(F110,"FTP snd_rename",snd_rename,0);
  5567.     }
  5568.     if (pv[SND_SRN].ival > 0) {         /* /SERVER-RENAME */
  5569.         char * p = pv[SND_SRN].sval;
  5570.         if (!p) p = "";
  5571.         if (!*p) {
  5572.             printf("?New name required for /SERVER-RENAME\n");
  5573.             x = -9;
  5574.             goto xputx;
  5575.         }
  5576.         p = brstrip(p);
  5577. #ifndef NOSPL
  5578.         if (wild) {
  5579.             char * s = tmpbuf;
  5580.             x = TMPBUFSIZ;
  5581.             zzstring(p,&s,&x);
  5582.             if (!strcmp(tmpbuf,p)) {
  5583.                 printf(
  5584. "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
  5585.                        );
  5586.                 x = -9;
  5587.                 goto xputx;
  5588.             }
  5589.         }
  5590. #endif /* NOSPL */
  5591.         makestr(&srv_renam,p);
  5592.         debug(F110,"ftp put srv_renam",srv_renam,0);
  5593.     }
  5594.     if (!confirmed) {                   /* CR not typed yet, get more fields */
  5595.         char * lp;
  5596.         if (mput) {                     /* MPUT or MMOVE */
  5597.             nfils = 0;                  /* We already have the first one */
  5598. #ifndef NOMSEND
  5599.         if (cmresult.fcode == _CMIFI) {
  5600.         /* First filespec is valid */
  5601.         msfiles[nfils++] = line;    /* Store pointer */
  5602.         lp = line + (int)strlen(line) + 1; /* Point past it */
  5603.         debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
  5604.         } else {
  5605.         /* First filespec matches no files */
  5606.         debug(F110,"ftp put mput skipping first filespec",
  5607.               cmresult.sresult,
  5608.               0
  5609.               );
  5610.         lp = line;
  5611.         }
  5612.         /* Parse a filespec, a "field", or confirmation */
  5613.  
  5614.         cmfdbi(&sf,            /* 1st FDB - file to send */
  5615.            _CMIFI,        /* fcode */
  5616.            "",            /* hlpmsg */
  5617.            "",            /* default */
  5618.            "",            /* addtl string data */
  5619.            nolinks | x_recurse,    /* addtl numeric data 1 */
  5620.            0,            /* dirflg 0 means "not dirs only" */
  5621.            xxstring,
  5622.            NULL,
  5623.            &fl
  5624.            );
  5625.         cmfdbi(&fl,            /* 2nd FDB - local filespec */
  5626.            _CMFLD,        /* fcode */
  5627.            "",            /* hlpmsg */
  5628.            "",            /* default */
  5629.            "",            /* addtl string data */
  5630.            0,            /* addtl numeric data 1 */
  5631.            0,            /* addtl numeric data 2 */
  5632.            xxstring,
  5633.            NULL,
  5634.            &cm
  5635.            );
  5636.         cmfdbi(&cm,            /* 3rd FDB - Confirmation */
  5637.            _CMCFM,        /* fcode */
  5638.            "",
  5639.            "",
  5640.            "",
  5641.            0,
  5642.            0,
  5643.            NULL,
  5644.            NULL,
  5645.            NULL
  5646.            );
  5647.  
  5648.             while (!confirmed) {    /* Get more filenames */
  5649.         x = cmfdb(&sf);        /* Parse something */
  5650.         debug(F101,"ftp put cmfdb B","",x);
  5651.         debug(F101,"ftp put fcode B","",cmresult.fcode);
  5652.         if (x < 0)        /* Error */
  5653.           goto xputx;        /* or reparse needed */
  5654.         switch (cmresult.fcode) {
  5655.           case _CMCFM:        /* End of command */
  5656.             confirmed++;
  5657.             if (nfils < 1) {
  5658.             debug(F100,"ftp put mput no files match","",0);
  5659.             printf("?No files match MPUT list\n");
  5660.             x = -9;
  5661.             goto xputx;
  5662.             }
  5663.             break;
  5664.           case _CMFLD:        /* No match */
  5665.             debug(F110,"ftp put mput skipping",cmresult.sresult,0);
  5666.             continue;
  5667.           case _CMIFI:        /* Good match */
  5668.             s = cmresult.sresult;
  5669.             msfiles[nfils++] = lp; /* Got one, count, point to it, */
  5670.             p = lp;           /* remember pointer, */
  5671.             while ((*lp++ = *s++)) /* and copy it into buffer */
  5672.               if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
  5673.               printf("?MPUT list too long\n");
  5674.               line[0] = NUL;
  5675.               x = -9;
  5676.               goto xputx;
  5677.               }
  5678.             debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
  5679.             if (nfils == 1)    /* Take care of \v(filespec) */
  5680.               fspec[0] = NUL;
  5681. #ifdef ZFNQFP
  5682.             zfnqfp(p,TMPBUFSIZ,tmpbuf);
  5683.             p = tmpbuf;
  5684. #endif /* ZFNQFP */
  5685.             if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
  5686.             strcat(fspec,p);    /* safe */
  5687.             strcat(fspec," ");  /* safe */
  5688.             } else {
  5689. #ifdef COMMENT
  5690.             printf("WARNING - \\v(filespec) buffer overflow\n");
  5691. #else
  5692.             debug(F101,"doxput filespec buffer overflow","",0);
  5693. #endif /* COMMENT */
  5694.             }
  5695.         }
  5696.         }
  5697. #endif /* NOMSEND */
  5698.         } else {                        /* Regular PUT */
  5699.             nfils = -1;
  5700.             if ((x = cmtxt(wild ?
  5701. "\nOptional as-name template containing replacement variables \
  5702. like \\v(filename)" :
  5703.                            "Optional name to send it with",
  5704.                            "",&p,NULL)) < 0)
  5705.               goto xputx;
  5706.  
  5707.             if (p) if (!*p) p = NULL;
  5708.             p = brstrip(p);
  5709.  
  5710.             if (p && *p) {
  5711.                 makestr(&(pv[SND_ASN].sval),p);
  5712.                 if (pv[SND_ASN].sval)
  5713.                   pv[SND_ASN].ival = 1;
  5714.                 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
  5715.             }
  5716.         }
  5717.     }
  5718.     /* Set cmarg2 from as-name, however we got it. */
  5719.  
  5720.     CHECKCONN();
  5721.     if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
  5722.         char * p;
  5723.         p = brstrip(pv[SND_ASN].sval);
  5724.         ckstrncpy(asnambuf,p,CKMAXPATH+1);
  5725.     }
  5726.     debug(F110,"ftp put asnambuf",asnambuf,0);
  5727.  
  5728.     if (pv[SND_FIL].ival > 0) {
  5729.         if (confirmed) {
  5730.             if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
  5731.                 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
  5732.                 printf("?Failure to open %s\n",pv[SND_FIL].sval);
  5733.                 x = -9;
  5734.                 goto xputx;
  5735.             }
  5736.             makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
  5737.             debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
  5738.             wild = 1;
  5739.         }
  5740.     }
  5741.     if (confirmed && !line[0] && !filefile) {
  5742. #ifndef NOMSEND
  5743.         if (filehead) {                 /* OK if we have a SEND-LIST */
  5744.             nfils = filesinlist;
  5745.             sndsrc = nfils;             /* Like MSEND */
  5746.             addlist = 1;                /* But using a different list... */
  5747.             filenext = filehead;
  5748.             goto doput;
  5749.         }
  5750. #endif /* NOMSEND */
  5751.         printf("?Filename required but not given\n");
  5752.         x = -9;
  5753.         goto xputx;
  5754.     }
  5755. #ifndef NOMSEND
  5756.     addlist = 0;                        /* Don't use SEND-LIST. */
  5757. #endif /* NOMSEND */
  5758.  
  5759.     if (mput) {                         /* MPUT (rather than PUT) */
  5760. #ifndef NOMSEND
  5761.         cmlist = msfiles;               /* List of filespecs */
  5762.         sndsrc = nfils;                 /* rather filespec and as-name */
  5763. #endif /* NOMSEND */
  5764.         pipesend = 0;
  5765.     } else if (filefile) {              /* File contains list of filenames */
  5766.         s = "";
  5767.         cmarg = "";
  5768.         line[0] = NUL;
  5769.         nfils = 1;
  5770.         sndsrc = 1;
  5771.  
  5772.     } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
  5773.  
  5774.         /* Not MSEND, MMOVE, /LIST, or /ARRAY */
  5775.         nfils = sndsrc = -1;
  5776.         if (!wild) {
  5777.             if (zchki(s) < 0) {
  5778.                 printf("?Read access denied - \"%s\"\n", s);
  5779.                 x = -9;
  5780.                 goto xputx;
  5781.             }
  5782.         }
  5783.         if (s != line)                  /* We might already have done this. */
  5784.           ckstrncpy(line,s,LINBUFSIZ);  /* Copy of string just parsed. */
  5785. #ifdef DEBUG
  5786.         else
  5787.           debug(F110,"doxput line=s",line,0);
  5788. #endif /* DEBUG */
  5789.         cmarg = line;                   /* File to send */
  5790.     }
  5791. #ifndef NOMSEND
  5792.     zfnqfp(cmarg,fspeclen,fspec);       /* Get full name */
  5793. #endif /* NOMSEND */
  5794.  
  5795.     if (!mput) {                        /* For all but MPUT... */
  5796. #ifdef PIPESEND
  5797.         if (pv[SND_CMD].ival > 0)       /* /COMMAND sets pipesend flag */
  5798.           pipesend = 1;
  5799.         debug(F101,"ftp put /COMMAND pipesend","",pipesend);
  5800.         if (pipesend && filefile) {
  5801.             printf("?Invalid switch combination\n");
  5802.             x = -9;
  5803.             goto xputx;
  5804.         }
  5805. #endif /* PIPESEND */
  5806.  
  5807. #ifndef NOSPL
  5808.     /* If as-name given and filespec is wild, as-name must contain variables */
  5809.         if ((wild || mput) && asnambuf[0]) {
  5810.             char * s = tmpbuf;
  5811.             x = TMPBUFSIZ;
  5812.             zzstring(asnambuf,&s,&x);
  5813.             if (!strcmp(tmpbuf,asnambuf)) {
  5814.                 printf(
  5815.     "?As-name for file group must contain variables such as \\v(filename)\n"
  5816.                        );
  5817.                 x = -9;
  5818.                 goto xputx;
  5819.             }
  5820.         }
  5821. #endif /* NOSPL */
  5822.     }
  5823.  
  5824.   doput:
  5825.  
  5826.     if (pv[SND_SHH].ival > 0) {         /* SEND /QUIET... */
  5827.         fdispla = 0;
  5828.         debug(F101,"ftp put display","",fdispla);
  5829.     } else {
  5830.         displa = 1;
  5831.         if (ftp_deb)
  5832.       fdispla = XYFD_B;
  5833.     }
  5834.  
  5835. #ifdef PUTARRAY                         /* SEND /ARRAY... */
  5836.     if (pv[SND_ARR].ival > 0) {
  5837.         if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
  5838.         if (range[0] == -1)             /* If low end of range not specified */
  5839.           range[0] = 1;                 /* default to 1 */
  5840.         if (range[1] == -1)             /* If high not specified */
  5841.           range[1] = a_dim[arrayx];     /* default to size of array */
  5842.         if ((range[0] < 0) ||           /* Check range */
  5843.             (range[0] > a_dim[arrayx]) ||
  5844.             (range[1] < range[0]) ||
  5845.             (range[1] > a_dim[arrayx])) {
  5846.             printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
  5847.             x = -9;
  5848.             goto xputx;
  5849.         }
  5850.         sndarray = ap;                  /* Array pointer */
  5851.         sndxin = arrayx;                /* Array index */
  5852.         sndxlo = range[0];              /* Array range */
  5853.         sndxhi = range[1];
  5854.         sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
  5855.         if (!asnambuf[0])
  5856.           ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
  5857.         cmarg = "";
  5858.     }
  5859. #endif /* PUTARRAY */
  5860.  
  5861.     moving = 0;
  5862.  
  5863.     if (pv[SND_ARR].ival < 1) {         /* File selection & disposition... */
  5864.         if (pv[SND_DEL].ival > 0)       /* /DELETE was specified */
  5865.           moving = 1;
  5866.         if (pv[SND_AFT].ival > 0)       /* Copy SEND criteria */
  5867.           ckstrncpy(sndafter,pv[SND_AFT].sval,19);
  5868.         if (pv[SND_BEF].ival > 0)
  5869.           ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
  5870.         if (pv[SND_NAF].ival > 0)
  5871.           ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
  5872.         if (pv[SND_NBE].ival > 0)
  5873.           ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
  5874.         if (pv[SND_EXC].ival > 0)
  5875.           makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
  5876.         if (pv[SND_SMA].ival > -1)
  5877.           sndsmaller = pv[SND_SMA].wval;
  5878.         if (pv[SND_LAR].ival > -1)
  5879.           sndlarger = pv[SND_LAR].wval;
  5880.         if (pv[SND_NAM].ival > -1)
  5881.           x_cnv = pv[SND_NAM].ival;
  5882.         if (pv[SND_USN].ival > -1)
  5883.           x_usn = pv[SND_USN].ival;
  5884.         if (pv[SND_ERR].ival > -1)
  5885.           puterror = pv[SND_ERR].ival;
  5886.  
  5887. #ifdef DOUPDATE
  5888.         if (pv[SND_UPD].ival > 0) {
  5889.             if (x_usn) {
  5890.                 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
  5891.                 x = -9;
  5892.                 goto xputx;
  5893.             }
  5894.             putflags |= PUT_UPD;
  5895.         ftp_dates |= 2;
  5896.         }
  5897. #ifdef COMMENT
  5898.     /* This works but it's useless, maybe dangerous */
  5899.         if (pv[SND_DIF].ival > 0) {
  5900.             if (x_usn) {
  5901.                 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
  5902.                 x = -9;
  5903.                 goto xputx;
  5904.             }
  5905.             putflags |= PUT_DIF;
  5906.         ftp_dates |= 2;
  5907.         }
  5908. #endif /* COMMENT */
  5909. #endif /* DOUPDATE */
  5910.  
  5911.         if (pv[SND_SIM].ival > 0)
  5912.           putflags |= PUT_SIM;
  5913.  
  5914.         if (pv[SND_PRM].ival > -1) {
  5915. #ifdef UNIX
  5916.             if (x_usn) {
  5917.                 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
  5918.                 x = -9;
  5919.                 goto xputx;
  5920.             }
  5921.             x_prm = pv[SND_PRM].ival;
  5922. #else /* UNIX */
  5923.             printf("?/PERMISSIONS switch is not supported\n");
  5924. #endif /* UNIX */
  5925.         }
  5926. #ifdef FTP_RESTART
  5927.         if (pv[SND_RES].ival > 0) {
  5928.         if (!sizeok) {
  5929.         printf("?PUT /RESTART can't be used because SIZE disabled.\n");
  5930.                 x = -9;
  5931.                 goto xputx;
  5932.         }
  5933.             if (x_usn || putflags) {
  5934.                 printf("?Conflicting switches: /RECOVER %s\n",
  5935.                        x_usn && putflags ? "/UNIQUE /UPDATE" :
  5936.                        (x_usn ? "/UNIQUE" : "/UPDATE")
  5937.                        );
  5938.                 x = -9;
  5939.                 goto xputx;
  5940.             }
  5941. #ifndef NOCSETS
  5942.             if (x_xla &&
  5943.                 (x_csl == FC_UCS2 ||
  5944.                  x_csl == FC_UTF8 ||
  5945.                  x_csr == FC_UCS2 ||
  5946.                  x_csr == FC_UTF8)) {
  5947.                 printf("?/RECOVER can not be used with Unicode translation\n");
  5948.                 x = -9;
  5949.                 goto xputx;
  5950.             }
  5951. #endif /* NOCSETS */
  5952.             putflags = PUT_RES;
  5953.         }
  5954. #endif /* FTP_RESTART */
  5955.     }
  5956.     debug(F101,"ftp PUT restart","",putflags & PUT_RES);
  5957.     debug(F101,"ftp PUT update","",putflags & PUT_UPD);
  5958.  
  5959. #ifdef PIPESEND
  5960.     if (pv[SND_FLT].ival > 0) {         /* Have SEND FILTER? */
  5961.         if (!pv[SND_FLT].sval) {
  5962.             sndfilter = NULL;
  5963.         } else {
  5964.             sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
  5965.             if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
  5966.         }
  5967.         debug(F110,"ftp put /FILTER", sndfilter, 0);
  5968.     }
  5969.     if (sndfilter || pipesend)          /* No /UPDATE or /RESTART */
  5970.       if (putflags)                     /* with pipes or filters */
  5971.         putflags = 0;
  5972. #endif /* PIPESEND */
  5973.  
  5974.     tfc = (CK_OFF_T)0;            /* Initialize stats and counters */
  5975.     filcnt = 0;
  5976.     pktnum = 0;
  5977.     spackets = 0L;
  5978.  
  5979.     if (wild)                           /* (is this necessary?) */
  5980.       cx = FTP_MPU;
  5981.  
  5982.     t0 = gmstimer();                    /* Record starting time */
  5983.  
  5984.     done = 0;                           /* Loop control */
  5985.     cancelgroup = 0;
  5986.  
  5987.     cdlevel = 0;
  5988.     cdsimlvl = 0;
  5989.     while (!done && !cancelgroup) {     /* Loop for all files */
  5990.                                         /* or until canceled. */
  5991. #ifdef FTP_PROXY
  5992.         /*
  5993.            If we are using a proxy, we don't use the local file list;
  5994.            instead we use the list on the remote machine which we want
  5995.            sent to someone else, and we use remglob() to get the names.
  5996.            But in that case we shouldn't even be executing this routine;
  5997.            see ftp_mput().
  5998.         */
  5999. #endif /* FTP_PROXY */
  6000.  
  6001.         cancelfile = 0;
  6002.         x = gnfile();                   /* Get next file from list(s) */
  6003.  
  6004.         if (x == 0)                     /* (see gnfile() comments...) */
  6005.           x = gnferror;
  6006.         debug(F111,"FTP PUT gnfile",filnam,x);
  6007.         debug(F111,"FTP PUT binary",filnam,binary);
  6008.  
  6009.         switch (x) {
  6010.           case 1:                       /* File to send */
  6011.             s2 = asnambuf;
  6012. #ifndef NOSPL
  6013.             if (asnambuf[0]) {          /* As-name */
  6014.                 int n; char *p;         /* to be evaluated... */
  6015.                 n = TMPBUFSIZ;
  6016.                 p = tmpbuf;
  6017.                 zzstring(asnambuf,&p,&n);
  6018.                 s2 = tmpbuf;
  6019.                 debug(F110,"ftp put asname",s2,0);
  6020.             }
  6021. #endif /* NOSPL */
  6022.             rc = putfile(cx,            /* Function (PUT, APPEND) */
  6023.                     filnam, s2,         /* Name to send, as-name */
  6024.                     forcetype, moving,  /* Parameters from switches... */
  6025.                     snd_move, snd_rename, srv_renam,
  6026.                     x_cnv, x_usn, xfiletype, x_prm,
  6027. #ifndef NOCSETS
  6028.                     x_csl, (!x_xla ? -1 : x_csr),
  6029. #else
  6030.                     -1, -1,
  6031. #endif /* NOCSETS */
  6032.                     putflags
  6033.                     );
  6034.             debug(F111,"ftp put putfile rc",filnam,rc);
  6035.             debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
  6036.             debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
  6037.             if (rc > -1) {
  6038.                 good++;
  6039.                 status = 1;
  6040.             }
  6041.             if (cancelfile)
  6042.               continue;
  6043.             if (rc < 0) {
  6044.                 ftp_fai++;
  6045.                 if (puterror) {
  6046.                     status = 0;
  6047.                     printf("?Fatal upload error: %s\n",filnam);
  6048.                     done++;
  6049.                 }
  6050.             }
  6051.             continue;
  6052.           case 0:                       /* No more files, done */
  6053.             done++;
  6054.             continue;
  6055.           case -1:
  6056.             printf("?%s: file not found - \"%s\"\n",
  6057.                    puterror ? "Fatal" : "Warning",
  6058.                    filnam
  6059.                    );
  6060.             if (puterror) {
  6061.                 status = 0;
  6062.                 done++;
  6063.                 break;
  6064.             }
  6065.             continue;
  6066.           case -2:
  6067.             if (puterror) {
  6068.                 printf("?Fatal: file not found - \"%s\"\n", filnam);
  6069.                 status = 0;
  6070.                 done++;
  6071.                 break;
  6072.             }
  6073.             continue;                   /* Not readable, keep going */
  6074.           case -3:
  6075.             if (puterror) {
  6076.                 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
  6077.                 status = 0;
  6078.                 done++;
  6079.                 break;
  6080.             }
  6081.             printf("?Warning access denied - \"%s\"\n", filnam);
  6082.             continue;
  6083. #ifdef COMMENT
  6084.           case -4:                      /* Canceled */
  6085.             done++;
  6086.             break;
  6087. #endif /* COMMENT */
  6088.           case -5:
  6089.             printf("?Too many files match\n");
  6090.             done++;
  6091.             break;
  6092.           case -6:
  6093.             if (good < 1)
  6094.               printf("?No files selected\n");
  6095.             done++;
  6096.             break;
  6097.           default:
  6098.             printf("?getnextfile() - unknown failure\n");
  6099.             done++;
  6100.         }
  6101.     }
  6102.     if (cdlevel > 0) {
  6103.         while (cdlevel--) {
  6104.             if (cdsimlvl) {
  6105.                 cdsimlvl--;
  6106.             } else if (!doftpcdup())
  6107.               break;
  6108.         }
  6109.     }
  6110.     if (status > 0) {
  6111.         if (cancelgroup)
  6112.           status = 0;
  6113.         else if (cancelfile && good < 1)
  6114.           status = 0;
  6115.     }
  6116.     success = status;
  6117.     x = success;
  6118.  
  6119.   xputx:
  6120.     if (x > -1) {
  6121. #ifdef GFTIMER
  6122.         t1 = gmstimer();                /* End time */
  6123.         sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  6124.         if (!sec) sec = 0.001;
  6125.         fptsecs = sec;
  6126. #else
  6127.         sec = (t1 - t0) / 1000;
  6128.         if (!sec) sec = 1;
  6129. #endif /* GFTIMER */
  6130.         tfcps = (long) (tfc / sec);
  6131.         tsecs = (int)sec;
  6132.         lastxfer = W_FTP|W_SEND;
  6133.         xferstat = success;
  6134.         if (dpyactive)
  6135.       ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
  6136.     }
  6137.     for (i = 0; i <= SND_MAX; i++) {    /* Free malloc'd memory */
  6138.         if (pv[i].sval)
  6139.           free(pv[i].sval);
  6140.     }
  6141.     ftreset();                          /* Undo switch effects */
  6142.     dpyactive = 0;
  6143.     return(x);
  6144. }
  6145.  
  6146.  
  6147. static char ** mgetlist = NULL;         /* For MGET */
  6148. static int mgetn = 0, mgetx = 0;
  6149. static char xtmpbuf[4096];
  6150.  
  6151. /*
  6152.   c m d l i n g e t
  6153.  
  6154.   Get files specified by -g command-line option.
  6155.   File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
  6156. */
  6157. int
  6158. cmdlinget(stay) int stay; {
  6159.     int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
  6160.     int lcs = -1, rcs = -1, xlate = 0;
  6161.     int first = 1;
  6162.     int mget = 1;
  6163.     int nc;
  6164.     char * s, * s2, * s3;
  6165.     ULONG t0, t1;                       /* Times for stats */
  6166. #ifdef GFTIMER
  6167.     CKFLOAT sec;
  6168. #else
  6169.     int sec = 0;
  6170. #endif /* GFTIMER */
  6171.  
  6172.     if (quiet) {                        /* -q really means quiet */
  6173.         displa = 0;
  6174.         fdispla = 0;
  6175.     } else {
  6176.         displa = 1;
  6177.         fdispla = XYFD_B;
  6178.     }
  6179.     testing = 0;
  6180.     dpyactive = 0;
  6181.     out2screen = 0;
  6182.     what = W_FTP|W_RECV;
  6183.     mgetmethod = 0;
  6184.     mgetforced = 0;
  6185.  
  6186.     havetype = 0;
  6187.     havesize = (CK_OFF_T)-1;
  6188.     makestr(&havemdtm,NULL);
  6189.  
  6190.     if (ftp_fnc < 0)
  6191.       ftp_fnc = fncact;
  6192.  
  6193. #ifndef NOSPL
  6194.     cmd_quoting = 0;
  6195. #endif /* NOSPL */
  6196.     debug(F101,"ftp cmdlinget nfils","",nfils);
  6197.  
  6198.     if (ftp_cnv == CNV_AUTO) {          /* Name conversion is auto */
  6199.         if (alike) {                    /* If server & client are alike */
  6200.             nc = 0;                     /* no conversion */
  6201.         } else {                        /* If they are different */
  6202.             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
  6203.               nc = -1;                  /* only minimal conversions needed */
  6204.             else                        /* otherwise */
  6205.               nc = 1;                   /* full conversion */
  6206.         }
  6207.     } else                              /* Not auto - do what user said */
  6208.       nc = ftp_cnv;
  6209.  
  6210.     if (nfils < 1)
  6211.       doexit(BAD_EXIT,-1);
  6212.  
  6213.     t0 = gmstimer();                    /* Starting time for this batch */
  6214.  
  6215. #ifndef NOCSETS
  6216.     if (xlate) {                        /* SET FTP CHARACTER-SET-TRANSLATION */
  6217.         lcs = ftp_csl;                  /* Local charset */
  6218.         if (lcs < 0) lcs = fcharset;
  6219.         if (lcs < 0) xlate = 0;
  6220.     }
  6221.     if (xlate) {                        /* Still ON? */
  6222.         rcs = ftp_csx;                  /* Remote (Server) charset */
  6223.         if (rcs < 0) rcs = ftp_csr;
  6224.         if (rcs < 0) xlate = 0;
  6225.     }
  6226. #endif /* NOCSETS */
  6227.     /*
  6228.       If we have only one file and it is a directory, then we ask for a
  6229.       listing of its contents, rather than retrieving the directory file
  6230.       itself.  This is what (e.g.) Netscape does.
  6231.     */
  6232.     if (nfils == 1) {
  6233.         if (doftpcwd((char *)cmlist[mgetx],-1)) {
  6234.             /* If we can CD to it, it must be a directory */
  6235.             if (recursive) {
  6236.                 cmlist[mgetx] = "*";
  6237.             } else {
  6238.                 status =
  6239.                   (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
  6240.                 done = 1;
  6241.             }
  6242.         }
  6243.     }
  6244. /*
  6245.   The following is to work around UNIX servers which, when given a command
  6246.   like "NLST path/blah" (not wild) returns the basename without the path.
  6247. */
  6248.     if (!done && servertype == SYS_UNIX && nfils == 1) {
  6249.         mget = iswild(cmlist[mgetx]);
  6250.     }
  6251.     if (!mget && !done) {               /* Invoked by command-line FTP URL */
  6252.         if (ftp_deb)
  6253.           printf("DOING GET...\n");
  6254.         done++;
  6255.         cancelfile = 0;                 /* This file not canceled yet */
  6256.         s = cmlist[mgetx];
  6257.         rc = 0;                         /* Initial return code */
  6258.     fsize = (CK_OFF_T)-1;
  6259.     if (sizeok) {
  6260.         x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
  6261.         if (x == REPLY_COMPLETE)
  6262.           fsize = ckatofs(&ftp_reply_str[4]);
  6263.     }
  6264.         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
  6265.         debug(F111,"ftp cmdlinget filnam",filnam,fsize);
  6266.  
  6267.         nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
  6268.         s2 = tmpbuf;
  6269.  
  6270.         /* If local file already exists, take collision action */
  6271.  
  6272.         if (zchki(s2) > -1) {
  6273.             switch (ftp_fnc) {
  6274.               case XYFX_A:              /* Append */
  6275.                 append = 1;
  6276.                 break;
  6277.               case XYFX_R:              /* Rename */
  6278.               case XYFX_B: {            /* Backup */
  6279.                   char * p = NULL;
  6280.                   int x = -1;
  6281.                   znewn(s2,&p);         /* Make unique name */
  6282.                   debug(F110,"ftp cmdlinget znewn",p,0);
  6283.                   if (ftp_fnc == XYFX_B) { /* Backup existing file */
  6284.                       x = zrename(s2,p);
  6285.                       debug(F111,"ftp cmdlinget backup zrename",p,x);
  6286.                   } else {              /* Rename incoming file */
  6287.                       x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
  6288.                       s2 = tmpbuf;
  6289.                       debug(F111,"ftp cmdlinget rename incoming",p,x);
  6290.                   }
  6291.                   if (x < 0) {
  6292.                       printf("?Backup/Rename failed\n");
  6293.                       return(success = 0);
  6294.                   }
  6295.                   break;
  6296.               }
  6297.               case XYFX_D:              /* Discard */
  6298.                 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
  6299.                 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
  6300.                 tlog(F100," refused: name","",0);
  6301.                 debug(F110,"ftp cmdlinget skip name",s2,0);
  6302.                 goto xclget;
  6303.  
  6304.               case XYFX_X:              /* Overwrite */
  6305.               case XYFX_U:              /* Update (already handled above) */
  6306.           case XYFX_M:        /* ditto */
  6307.                 break;
  6308.             }
  6309.         }
  6310.         rc = getfile(s,                 /* Remote name */
  6311.                      s2,                /* Local name */
  6312.                      0,                 /* Recover/Restart */
  6313.                      append,            /* Append */
  6314.                      NULL,              /* Pipename */
  6315.                      0,                 /* Translate charsets */
  6316.                      -1,                /* File charset (none) */
  6317.                      -1                 /* Server charset (none) */
  6318.                      );
  6319.         debug(F111,"ftp cmdlinget rc",s,rc);
  6320.         debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
  6321.         debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
  6322.  
  6323.         if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
  6324.             rc = getfile(&s[1],         /* Remote name without leading '/' */
  6325.                          s2,            /* Local name */
  6326.                          0,             /* Recover/Restart */
  6327.                          append,        /* Append */
  6328.                          NULL,          /* Pipename */
  6329.                          0,             /* Translate charsets */
  6330.                          -1,            /* File charset (none) */
  6331.                          -1             /* Server charset (none) */
  6332.                          );
  6333.         if (rc > -1) {
  6334.             good++;
  6335.             status = 1;
  6336.         }
  6337.         if (cancelfile)
  6338.           goto xclget;
  6339.         if (rc < 0) {
  6340.             ftp_fai++;
  6341. #ifdef FTP_TIMEOUT
  6342.         if (ftp_timed_out)
  6343.           status = 0;
  6344. #endif    /* FTP_TIMEOUT */
  6345.             if (geterror) {
  6346.                 status = 0;
  6347.                 done++;
  6348.             }
  6349.         }
  6350.     }
  6351.     if (ftp_deb && !done)
  6352.       printf("DOING MGET...\n");
  6353.     while (!done && !cancelgroup) {
  6354.         cancelfile = 0;                 /* This file not canceled yet */
  6355.         s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
  6356.         if (!s) s = "";
  6357.         if (!*s) {
  6358.             first = 1;
  6359.             mgetx++;
  6360.             if (mgetx < nfils)
  6361.               s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
  6362.             else
  6363.               s = NULL;
  6364.             debug(F111,"ftp cmdlinget remote_files B",s,0);
  6365.             if (!s) {
  6366.                 done = 1;
  6367.                 break;
  6368.             }
  6369.         }
  6370.         /*
  6371.           The semantics of NLST are ill-defined.  Suppose we have just sent
  6372.           NLST /path/[a-z]*.  Most servers send back names like /path/foo,
  6373.           /path/bar, etc.  But some send back only foo and bar, and subsequent
  6374.           RETR commands based on the pathless names are not going to work.
  6375.         */
  6376.         if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
  6377.             if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
  6378.                 int len, left = 4096;
  6379.                 char * tmp = xtmpbuf;
  6380.                 len = s3 - cmlist[mgetx] + 1;
  6381.                 ckstrncpy(tmp,cmlist[mgetx],left);
  6382.                 tmp += len;
  6383.                 left -= len;
  6384.                 ckstrncpy(tmp,s,left);
  6385.                 s = xtmpbuf;
  6386.         debug(F111,"ftp cmdlinget remote_files X",s,0);
  6387.             }
  6388.         }
  6389.         first = 0;                      /* Not first any more */
  6390.  
  6391.     debug(F111,"ftp cmdlinget havetype",s,havetype);
  6392.     if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
  6393.         debug(F110,"ftp cmdlinget not-a-file",s,0);
  6394.         continue;
  6395.     }
  6396.         rc = 0;                         /* Initial return code */
  6397.     if (havesize > (CK_OFF_T)-1) {    /* Already have file size? */
  6398.         fsize = havesize;
  6399.     } else {            /* No - must ask server */
  6400.         /*
  6401.           Prior to sending the NLST command we necessarily put the
  6402.           server into ASCII mode.  We must now put it back into the
  6403.           the requested mode so the upcoming SIZE command returns
  6404.           right kind of size; this is especially important for
  6405.           GET /RECOVER; otherwise the server returns the "ASCII" size
  6406.           of the file, rather than its true size.
  6407.         */
  6408.         changetype(ftp_typ,0);    /* Change to requested type */
  6409.         fsize = (CK_OFF_T)-1;
  6410.         if (sizeok) {
  6411.         x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
  6412.         if (x == REPLY_COMPLETE)
  6413.           fsize = ckatofs(&ftp_reply_str[4]);
  6414.         }
  6415.     }
  6416.         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
  6417.         debug(F111,"ftp cmdlinget filnam",filnam,fsize);
  6418.  
  6419.         nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
  6420.         s2 = tmpbuf;
  6421.  
  6422.         /* If local file already exists, take collision action */
  6423.  
  6424.         if (zchki(s2) > -1) {
  6425.             switch (ftp_fnc) {
  6426.               case XYFX_A:              /* Append */
  6427.                 append = 1;
  6428.                 break;
  6429.               case XYFX_R:              /* Rename */
  6430.               case XYFX_B: {            /* Backup */
  6431.                   char * p = NULL;
  6432.                   int x = -1;
  6433.                   znewn(s2,&p);         /* Make unique name */
  6434.                   debug(F110,"ftp cmdlinget znewn",p,0);
  6435.                   if (ftp_fnc == XYFX_B) { /* Backup existing file */
  6436.                       x = zrename(s2,p);
  6437.                       debug(F111,"ftp cmdlinget backup zrename",p,x);
  6438.                   } else {              /* Rename incoming file */
  6439.                       x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
  6440.                       s2 = tmpbuf;
  6441.                       debug(F111,"ftp cmdlinget rename incoming",p,x);
  6442.                   }
  6443.                   if (x < 0) {
  6444.                       printf("?Backup/Rename failed\n");
  6445.                       return(success = 0);
  6446.                   }
  6447.                   break;
  6448.               }
  6449.               case XYFX_D:      /* Discard */
  6450.                 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
  6451.                 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
  6452.                 tlog(F100," refused: name","",0);
  6453.                 debug(F110,"ftp cmdlinget skip name",s2,0);
  6454.                 continue;
  6455.               case XYFX_X:              /* Overwrite */
  6456.               case XYFX_U:              /* Update (already handled above) */
  6457.               case XYFX_M:              /* ditto */
  6458.                 break;
  6459.             }
  6460.         }
  6461.                                         /* ^^^ ADD CHARSET STUFF HERE ^^^ */
  6462.         rc = getfile(s,                 /* Remote name */
  6463.                      s2,                /* Local name */
  6464.                      0,                 /* Recover/Restart */
  6465.                      append,            /* Append */
  6466.                      NULL,              /* Pipename */
  6467.                      0,                 /* Translate charsets */
  6468.                      -1,                /* File charset (none) */
  6469.                      -1                 /* Server charset (none) */
  6470.                      );
  6471.         debug(F111,"ftp cmdlinget rc",s,rc);
  6472.         debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
  6473.         debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
  6474.  
  6475.         if (rc > -1) {
  6476.             good++;
  6477.             status = 1;
  6478.         }
  6479.         if (cancelfile)
  6480.           continue;
  6481.         if (rc < 0) {
  6482.             ftp_fai++;
  6483. #ifdef FTP_TIMEOUT
  6484.         if (ftp_timed_out)
  6485.           status = 0;
  6486. #endif    /* FTP_TIMEOUT */
  6487.             if (geterror) {
  6488.                 status = 0;
  6489.                 done++;
  6490.             }
  6491.         }
  6492.     }
  6493.  
  6494.   xclget:
  6495.     if (cancelgroup)
  6496.       mlsreset();
  6497.     if (status > 0) {
  6498.         if (cancelgroup)
  6499.           status = 0;
  6500.         else if (cancelfile && good < 1)
  6501.           status = 0;
  6502.     }
  6503.     success = status;
  6504.  
  6505. #ifdef GFTIMER
  6506.     t1 = gmstimer();                    /* End time */
  6507.     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  6508.     if (!sec) sec = 0.001;
  6509.     fptsecs = sec;
  6510. #else
  6511.     sec = (t1 - t0) / 1000;
  6512.     if (!sec) sec = 1;
  6513. #endif /* GFTIMER */
  6514.  
  6515.     tfcps = (long) (tfc / sec);
  6516.     tsecs = (int)sec;
  6517.     lastxfer = W_FTP|W_RECV;
  6518.     xferstat = success;
  6519.     if (dpyactive)
  6520.       ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
  6521.     if (!stay)
  6522.       doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
  6523.     return(success);
  6524. }
  6525.  
  6526. /*  d o f t p g e t  --  Parse and execute GET, MGET, MDELETE, ...  */
  6527.  
  6528. /*
  6529.   Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
  6530.   zstrdat() to convert to UTC-based time_t.  But it doesn't make sense from
  6531.   the user-interface perspective, since the server's directory listings show
  6532.   its own local times and since we don't know what timezone it's in, there's
  6533.   no way to reconcile our local times with the server's.
  6534. */
  6535. int
  6536. doftpget(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
  6537.     struct FDB fl, sw, cm;
  6538.     int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
  6539.     int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
  6540.     int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
  6541.     int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
  6542.     int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
  6543.     int gotsize = 0;
  6544.     int matchdot = 0;
  6545.     CK_OFF_T getlarger = (CK_OFF_T)-1;
  6546.     CK_OFF_T getsmaller = (CK_OFF_T)-1;
  6547.     char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
  6548.     char * src = "", * local = "";
  6549.     char * pat = "";
  6550.  
  6551.     int x_csl = -1, x_csr = -1;         /* Local and remote charsets */
  6552.     int x_xla = 0;
  6553.     char c;                             /* Worker char */
  6554.     ULONG t0 = 0L, t1;                  /* Times for stats */
  6555. #ifdef GFTIMER
  6556.     CKFLOAT sec;
  6557. #else
  6558.     int sec = 0;
  6559. #endif /* GFTIMER */
  6560.  
  6561.     struct stringint pv[SND_MAX+1];    /* Temporary array for switch values */
  6562.  
  6563.     success = 0;                        /* Assume failure */
  6564.     forcetype = 0;                      /* No /TEXT or /BINARY given yet */
  6565.     restart = 0;                        /* No restart yet */
  6566.     out2screen = 0;            /* No TO-SCREEN switch given yet */
  6567.     mgetmethod = 0;            /* No NLST or MLSD switch yet */
  6568.     mgetforced = 0;
  6569.  
  6570.     g_displa = fdispla;
  6571.     if (ftp_dis > -1)
  6572.       fdispla = ftp_dis;
  6573.  
  6574.     x_cnv = ftp_cnv;                    /* Filename conversion */
  6575.     if (x_cnv == CNV_AUTO) {        /* Name conversion is auto */
  6576.         if (alike) {                    /* If server & client are alike */
  6577.             x_cnv = 0;            /* no conversion */
  6578.         } else {                        /* If they are different */
  6579.             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
  6580.               x_cnv = -1;        /* only minimal conversions needed */
  6581.             else                        /* otherwise */
  6582.               x_cnv = 1;        /* full conversion */
  6583.         }
  6584.     } else                              /* Not auto - do what user said */
  6585.       x_cnv = ftp_cnv;
  6586.  
  6587.     x_prm = ftp_prm;                    /* Permissions */
  6588.     if (x_prm == SET_AUTO)              /* Permissions AUTO */
  6589.       x_prm = alike;
  6590.  
  6591. #ifndef NOCSETS
  6592.     x_csr = ftp_csr;                    /* Inherit global server charset */
  6593.     x_csl = ftp_csl;                    /* Inherit global local charset */
  6594.     if (x_csl < 0)                      /* If none, use current */
  6595.       x_csl = fcharset;                 /* file character-set. */
  6596.     x_xla = ftp_xla;                    /* Translation On/Off */
  6597. #endif /* NOCSETS */
  6598.  
  6599.     geterror = ftp_err;                 /* Inherit global error action. */
  6600.     asnambuf[0] = NUL;                  /* No as-name yet. */
  6601.     pipesave = pipesend;
  6602.     pipesend = 0;
  6603.  
  6604.     havetype = 0;
  6605.     havesize = (CK_OFF_T)-1;
  6606.     makestr(&havemdtm,NULL);
  6607.  
  6608.     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
  6609.         ftp_typ = g_ftp_typ;
  6610.         /* g_ftp_typ = -1; */
  6611.     }
  6612.     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
  6613.         pv[i].sval = NULL;              /* to null pointers */
  6614.         pv[i].ival = -1;                /* and -1 int values */
  6615.         pv[i].wval = (CK_OFF_T)-1;    /* and -1 wide values */
  6616.     }
  6617.     zclose(ZMFILE);                     /* In case it was left open */
  6618.  
  6619.     x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
  6620.  
  6621.     if (fp_nml) {                       /* Reset /NAMELIST */
  6622.         if (fp_nml != stdout)
  6623.           fclose(fp_nml);
  6624.         fp_nml = NULL;
  6625.     }
  6626.     makestr(&ftp_nml,NULL);
  6627.  
  6628.     /* Initialize list of remote filespecs */
  6629.  
  6630.     if (!mgetlist) {
  6631.         mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
  6632.         if (!mgetlist) {
  6633.             printf("?Memory allocation failure - MGET list\n");
  6634.             return(-9);
  6635.         }
  6636.         for (i = 0; i < MGETMAX; i++)
  6637.           mgetlist[i] = NULL;
  6638.     }
  6639.     mgetn = 0;                          /* Number of mget arguments */
  6640.     mgetx = 0;                          /* Current arg */
  6641.  
  6642.     if (who == 0) {                     /* Called with unprefixed command */
  6643.         if (cx == XXGET || cx == XXREGET || cx == XXRETR)
  6644.           getone++;
  6645.         switch (cx) {
  6646.           case XXREGET: pv[SND_RES].ival = 1; break;
  6647.           case XXRETR:  pv[SND_DEL].ival = 1; break;
  6648.           case XXGET:
  6649.           case XXMGET:  mget++; break;
  6650.         }
  6651.     } else {                            /* FTP command */
  6652.         if (cx == FTP_GET || cx == FTP_RGE)
  6653.           getone++;
  6654.         switch (cx) {
  6655.           case FTP_DEL:                 /* (fall thru on purpose) */
  6656.           case FTP_MDE: mdel++;         /* (ditto) */
  6657.           case FTP_GET:                 /* (ditto) */
  6658.           case FTP_MGE: mget++; break;
  6659.           case FTP_RGE: pv[SND_RES].ival = 1; break;
  6660.         }
  6661.     }
  6662.     cmfdbi(&sw,                         /* First FDB - command switches */
  6663.            _CMKEY,                      /* fcode */
  6664.            "Remote filename;\n or switch", /* hlpmsg */
  6665.            "",                          /* default */
  6666.            "",                          /* addtl string data */
  6667.            mdel ? ndelswi : ngetswi,    /* addtl numeric data 1: tbl size */
  6668.            4,                           /* addtl numeric data 2: 4 = cmswi */
  6669.            xxstring,                    /* Processing function */
  6670.            mdel ? delswi : getswi,      /* Keyword table */
  6671.            &fl                          /* Pointer to next FDB */
  6672.            );
  6673.     cmfdbi(&fl,                         /* 2nd FDB - remote filename */
  6674.            _CMFLD,                      /* fcode */
  6675.            "",                          /* hlpmsg */
  6676.            "",                          /* default */
  6677.            "",                          /* addtl string data */
  6678.            0,                           /* addtl numeric data 1 */
  6679.            0,                           /* addtl numeric data 2 */
  6680.            xxstring,
  6681.            NULL,
  6682.            &cm
  6683.            );
  6684.     cmfdbi(&cm,                         /* 3rd FDB - Confirmation */
  6685.            _CMCFM,                      /* fcode */
  6686.            "",                          /* hlpmsg */
  6687.            "",                          /* default */
  6688.            "",                          /* addtl string data */
  6689.            0,                           /* addtl numeric data 1 */
  6690.            0,                           /* addtl numeric data 2 */
  6691.            NULL,
  6692.            NULL,
  6693.            NULL
  6694.            );
  6695.  
  6696.     while (1) {                         /* Parse 0 or more switches */
  6697.         x = cmfdb(&sw);                 /* Parse something */
  6698.         debug(F101,"ftp get cmfdb","",x);
  6699.         if (x < 0)                      /* Error */
  6700.           goto xgetx;                   /* or reparse needed */
  6701.         if (cmresult.fcode != _CMKEY)   /* Break out of loop if not a switch */
  6702.           break;
  6703.         c = cmgbrk();                   /* Get break character */
  6704.         getval = (c == ':' || c == '='); /* to see how they ended the switch */
  6705.         if (getval && !(cmresult.kflags & CM_ARG)) {
  6706.             printf("?This switch does not take arguments\n");
  6707.             x = -9;
  6708.             goto xgetx;
  6709.         }
  6710.         n = cmresult.nresult;           /* Numeric result = switch value */
  6711.         debug(F101,"ftp get switch","",n);
  6712.  
  6713.         if (!getval && (cmgkwflgs() & CM_ARG)) {
  6714.             printf("?This switch requires an argument\n");
  6715.             x = -9;
  6716.             goto xgetx;
  6717.         }
  6718.         switch (n) {                    /* Process the switch */
  6719.           case SND_ASN:                 /* /AS-NAME: */
  6720.             debug(F101,"ftp get /as-name getval","",getval);
  6721.             if (!getval) break;
  6722.             if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
  6723.                 if (x == -3) {
  6724.                     printf("?name required\n");
  6725.                     x = -9;
  6726.                 }
  6727.                 goto xgetx;
  6728.             }
  6729.             s = brstrip(s);
  6730.             if (!*s) s = NULL;
  6731.             makestr(&(pv[n].sval),s);
  6732.             pv[n].ival = 1;
  6733.             break;
  6734.  
  6735.           case SND_BIN:                 /* /BINARY */
  6736.           case SND_TXT:                 /* /TEXT or /ASCII */
  6737.           case SND_TEN:                 /* /TENEX */
  6738.             pv[SND_BIN].ival = 0;
  6739.             pv[SND_TXT].ival = 0;
  6740.             pv[SND_TEN].ival = 0;
  6741.             pv[n].ival = 1;
  6742.             break;
  6743.  
  6744. #ifdef PUTPIPE
  6745.           case SND_CMD:                 /* These take no args */
  6746.             if (nopush) {
  6747.                 printf("?Sorry, system command access is disabled\n");
  6748.                 x = -9;
  6749.                 goto xgetx;
  6750.             }
  6751. #ifdef PIPESEND
  6752.             else if (rcvfilter) {
  6753.                 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
  6754.                 x = -9;
  6755.                 goto xgetx;
  6756.             }
  6757. #endif /* PIPESEND */
  6758.             sw.hlpmsg = "Command, or switch"; /* Change help message */
  6759.             pv[n].ival = 1;             /* Just set the flag */
  6760.             pv[SND_ARR].ival = 0;
  6761.             break;
  6762. #endif /* PUTPIPE */
  6763.  
  6764.           case SND_SHH:                 /* /QUIET */
  6765.           case SND_RES:                 /* /RECOVER (reget) */
  6766.           case SND_NOB:                 /* /NOBACKUPFILES */
  6767.           case SND_DEL:                 /* /DELETE */
  6768.           case SND_UPD:                 /* /UPDATE */
  6769.           case SND_USN:                 /* /UNIQUE */
  6770.           case SND_NOD:                 /* /NODOTFILES */
  6771.           case SND_REC:                 /* /RECOVER */
  6772.           case SND_MAI:                 /* /TO-SCREEN */
  6773.             pv[n].ival = 1;             /* Just set the flag */
  6774.             break;
  6775.  
  6776.           case SND_DIF:                 /* /DATES-DIFFER */
  6777.         pv[SND_COL].ival = XYFX_M;    /* Now it's a collision option */
  6778.         pv[n].ival = 1;
  6779.         break;
  6780.  
  6781.           case SND_COL:                 /* /COLLISION: */
  6782.             if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
  6783.               goto xgetx;
  6784.         if (x == XYFX_M)
  6785.           pv[SND_DIF].ival = 1;    /* (phase this out) */
  6786.         pv[n].ival = x;        /* this should be sufficient */
  6787.             break;
  6788.  
  6789.           case SND_ERR:                 /* /ERROR-ACTION */
  6790.             if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
  6791.               goto xgetx;
  6792.             pv[n].ival = x;
  6793.             break;
  6794.  
  6795.           case SND_EXC:                 /* Exception list */
  6796.             if (!getval) break;
  6797.             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
  6798.                 if (x == -3) {
  6799.                     printf("?Pattern required\n");
  6800.                     x = -9;
  6801.                 }
  6802.                 goto xgetx;
  6803.             }
  6804.             if (s) if (!*s) s = NULL;
  6805.             makestr(&(pv[n].sval),s);
  6806.             if (pv[n].sval)
  6807.               pv[n].ival = 1;
  6808.             break;
  6809.  
  6810. #ifdef PIPESEND
  6811.           case SND_FLT:
  6812.             debug(F101,"ftp get /filter getval","",getval);
  6813.             if (!getval) break;
  6814.             if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
  6815.                 if (x == -3)
  6816.                   s = "";
  6817.                 else
  6818.                   goto xgetx;
  6819.             }
  6820.             s = brstrip(s);
  6821.             if (pv[SND_MAI].ival < 1) {
  6822.                 y = strlen(s);
  6823.                 /* Make sure they included "\v(...)" */
  6824.                 for (x = 0; x < y; x++) {
  6825.                     if (s[x] != '\\') continue;
  6826.                     if (s[x+1] == 'v') break;
  6827.                 }
  6828.                 if (x == y) {
  6829.                     printf(
  6830.                 "?Filter must contain a replacement variable for filename.\n"
  6831.                            );
  6832.                     x = -9;
  6833.                     goto xgetx;
  6834.                 }
  6835.             }
  6836.             if (*s) {
  6837.                 pv[n].ival = 1;
  6838.                 makestr(&(pv[n].sval),s);
  6839.             } else {
  6840.                 pv[n].ival = 0;
  6841.                 makestr(&(pv[n].sval),NULL);
  6842.             }
  6843.             break;
  6844. #endif /* PIPESEND */
  6845.  
  6846.           case SND_NAM:
  6847.             if (!getval) break;
  6848.             if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
  6849.               goto xgetx;
  6850.             debug(F101,"ftp get /filenames","",x);
  6851.             pv[n].ival = x;
  6852.             break;
  6853.  
  6854.           case SND_SMA:                 /* Smaller / larger than */
  6855.           case SND_LAR: {
  6856.           CK_OFF_T y;
  6857.           if (!getval) break;
  6858.           if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
  6859.         goto xgetx;
  6860.           pv[n].wval = y;
  6861.           break;
  6862.       }
  6863.           case SND_FIL:                 /* Name of file containing filnames */
  6864.             if (!getval) break;
  6865.             if ((x = cmifi("Name of file containing list of filenames",
  6866.                                "",&s,&y,xxstring)) < 0) {
  6867.                 if (x == -3) {
  6868.                     printf("?Filename required\n");
  6869.                     x = -9;
  6870.                 }
  6871.                 goto xgetx;
  6872.             } else if (y && iswild(s)) {
  6873.                 printf("?Wildcards not allowed BBB\n");
  6874.                 x = -9;
  6875.                 goto xgetx;
  6876.             }
  6877.             if (s) if (!*s) s = NULL;
  6878.             makestr(&(pv[n].sval),s);
  6879.             if (pv[n].sval)
  6880.               pv[n].ival = 1;
  6881.             break;
  6882.  
  6883.           case SND_MOV:                 /* MOVE after */
  6884.           case SND_REN:                 /* RENAME after */
  6885.           case SND_SRN: {               /* SERVER-RENAME */
  6886.               char * m = "";
  6887.               switch (n) {
  6888.                 case SND_MOV:
  6889.                   m =
  6890.                    "Device and/or directory for incoming file after reception";
  6891.                   break;
  6892.                 case SND_REN:
  6893.                   m = "New name for incoming file after reception";
  6894.                   break;
  6895.                 case SND_SRN:
  6896.                   m = "New name for source file on server after reception";
  6897.                   break;
  6898.               }
  6899.               if (!getval) break;
  6900.               if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
  6901.                   if (x == -3) {
  6902.                       printf("%s\n", n == SND_MOV ?
  6903.                              "?Destination required" :
  6904.                              "?New name required"
  6905.                              );
  6906.                       x = -9;
  6907.                   }
  6908.                   goto xgetx;
  6909.               }
  6910.               makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
  6911.               pv[n].ival = (pv[n].sval) ? 1 : 0;
  6912.               break;
  6913.           }
  6914. #ifndef NOCSETS
  6915.           case SND_CSL:                 /* Local character set */
  6916.           case SND_CSR:                 /* Remote (server) charset */
  6917.             if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
  6918.               return((x == -3) ? -2 : x);
  6919.             if (n == SND_CSL)
  6920.               x_csl = x;
  6921.             else
  6922.               x_csr = x;
  6923.             x_xla = 1;                  /* Overrides global OFF setting */
  6924.             break;
  6925.  
  6926.           case SND_XPA:                 /* Transparent */
  6927.             x_xla =  0;
  6928.             x_csr = -1;
  6929.             x_csl = -1;
  6930.             break;
  6931. #endif /* NOCSETS */
  6932.  
  6933.           case SND_NML:
  6934.             if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
  6935.               goto xgetx;
  6936.             makestr(&ftp_nml,s);
  6937.             break;
  6938.  
  6939.       case SND_PAT:            /* /PATTERN: */
  6940.         if (!getval) break;
  6941.         if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
  6942.           goto xgetx;
  6943.         makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
  6944.         pv[n].ival = (pv[n].sval) ? 1 : 0;
  6945.         break;
  6946.  
  6947.       case SND_NLS:            /* /NLST */
  6948.             pv[n].ival = 1;        /* Use NLST */
  6949.         pv[SND_MLS].ival = 0;    /* Don't use MLSD */
  6950.         break;
  6951.  
  6952.       case SND_MLS:            /* /MLSD */
  6953.             pv[n].ival = 1;        /* Use MLSD */
  6954.         pv[SND_NLS].ival = 0;    /* Don't use NLST */
  6955.         break;
  6956.  
  6957.           default:                      /* /AFTER, /PERMISSIONS, etc... */
  6958.             printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
  6959.             x = -9;
  6960.             goto xgetx;
  6961.         }
  6962.     }
  6963.     line[0] = NUL;
  6964.     cmarg = line;
  6965.     cmarg2 = asnambuf;
  6966.     s = line;
  6967. /*
  6968.   For GET, we want to parse an optional as-name, like with PUT.
  6969.   For MGET, we must parse a list of names, and then send NLST or MLSD
  6970.   commands for each name separately.
  6971. */
  6972.     switch (cmresult.fcode) {           /* How did we get out of switch loop */
  6973.       case _CMFLD:                      /* Field */
  6974.         if (!getone) {
  6975.             s = brstrip(cmresult.sresult);
  6976.             makestr(&(mgetlist[mgetn++]),s);
  6977.             while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
  6978.                 if (x < 0)
  6979.                   goto xgetx;
  6980.                 makestr(&(mgetlist[mgetn++]),brstrip(s));
  6981.                 if (mgetn >= MGETMAX) {
  6982.                     printf("?Too many items in MGET list\n");
  6983.                     goto xgetx;
  6984.                 }
  6985.             }
  6986.             if ((x = cmcfm()) < 0)
  6987.               goto xgetx;
  6988.         } else {
  6989.             s = brstrip(cmresult.sresult);
  6990.             ckstrncpy(line,s,LINBUFSIZ);
  6991.             if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
  6992.               if (x != -3)
  6993.                 goto xgetx;
  6994.             s = brstrip(s);
  6995.             ckstrncpy(asnambuf,s,CKMAXPATH+1);
  6996.             if ((x = cmcfm()) < 0)
  6997.               goto xgetx;
  6998.         }
  6999.         break;
  7000.       case _CMCFM:                      /* Confirmation */
  7001.         break;
  7002.       default:
  7003.         printf("?Unexpected function code: %d\n",cmresult.fcode);
  7004.         x = -9;
  7005.         goto xgetx;
  7006.     }
  7007.     if (pv[SND_REC].ival > 0)           /* /RECURSIVE */
  7008.       recursive = 2;
  7009.  
  7010.     if (pv[SND_BIN].ival > 0) {         /* /BINARY really means binary... */
  7011.         forcetype = 1;                  /* So skip the name-pattern match */
  7012.         ftp_typ = XYFT_B;               /* Set binary */
  7013.     } else if (pv[SND_TXT].ival > 0) {  /* Similarly for /TEXT... */
  7014.         forcetype = 1;
  7015.         ftp_typ = XYFT_T;
  7016.     } else if (pv[SND_TEN].ival > 0) {  /* and /TENEX*/
  7017.         forcetype = 1;
  7018.         ftp_typ = FTT_TEN;
  7019.     } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
  7020.         forcetype = 1;
  7021.         ftp_typ = binary;
  7022.         g_ftp_typ = binary;
  7023.     }
  7024.     if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
  7025.         char * p;
  7026.         p = brstrip(pv[SND_ASN].sval);  /* As-name */
  7027.         ckstrncpy(asnambuf,p,CKMAXPATH+1);
  7028.     }
  7029.     debug(F110,"ftp get asnambuf",asnambuf,0);
  7030.  
  7031. #ifdef PIPESEND
  7032.     if (pv[SND_CMD].ival > 0) {         /* /COMMAND - strip any braces */
  7033.         char * p;
  7034.         p = asnambuf;
  7035.         debug(F110,"GET /COMMAND before stripping",p,0);
  7036.         p = brstrip(p);
  7037.         debug(F110,"GET /COMMAND after stripping",p,0);
  7038.         if (!*p) {
  7039.             printf("?Sorry, a command to write to is required\n");
  7040.             x = -9;
  7041.             goto xgetx;
  7042.         }
  7043.         pipename = p;
  7044.         pipesend = 1;
  7045.     }
  7046. #endif /* PIPESEND */
  7047.  
  7048. /* Set up /MOVE and /RENAME */
  7049.  
  7050. #ifdef COMMENT
  7051.     /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
  7052.     if (pv[SND_DEL].ival > 0 &&
  7053.         (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
  7054.         printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
  7055.         x = -9;
  7056.         goto xgetx;
  7057.     }
  7058. #endif    /* COMMENT */
  7059. #ifdef CK_TMPDIR
  7060.     if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
  7061.         int len;
  7062.         char * p = pv[SND_MOV].sval;
  7063.         len = strlen(p);
  7064.         if (!isdir(p)) {                /* Check directory */
  7065. #ifdef CK_MKDIR
  7066.             char * s = NULL;
  7067.             s = (char *)malloc(len + 4);
  7068.             if (s) {
  7069.                 strcpy(s,p);            /* safe */
  7070. #ifdef datageneral
  7071.                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
  7072. #else
  7073.                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
  7074. #endif /* datageneral */
  7075.                 s[len++] = 'X';
  7076.                 s[len] = NUL;
  7077. #ifdef NOMKDIR
  7078.                 x = -1;
  7079. #else
  7080.                 x = zmkdir(s);
  7081. #endif /* NOMKDIR */
  7082.                 free(s);
  7083.                 if (x < 0) {
  7084.                     printf("?Can't create \"%s\"\n",p);
  7085.                     x = -9;
  7086.                     goto xgetx;
  7087.                 }
  7088.             }
  7089. #else
  7090.             printf("?Directory \"%s\" not found\n",p);
  7091.             x = -9;
  7092.             goto xgetx;
  7093. #endif /* CK_MKDIR */
  7094.         }
  7095.         makestr(&rcv_move,p);
  7096.         moving = 1;
  7097.     }
  7098. #endif /* CK_TMPDIR */
  7099.  
  7100.     if (pv[SND_REN].ival > 0) {         /* /RENAME */
  7101.         char * p = pv[SND_REN].sval;
  7102.         if (!p) p = "";
  7103.         if (!*p) {
  7104.             printf("?New name required for /RENAME\n");
  7105.             x = -9;
  7106.             goto xgetx;
  7107.         }
  7108.         p = brstrip(p);
  7109. #ifndef NOSPL
  7110.     /* If name given is wild, rename string must contain variables */
  7111.         if (mget && !getone) {
  7112.             char * s = tmpbuf;
  7113.             x = TMPBUFSIZ;
  7114.             zzstring(p,&s,&x);
  7115.             if (!strcmp(tmpbuf,p)) {
  7116.                 printf(
  7117.     "?/RENAME for file group must contain variables such as \\v(filename)\n"
  7118.                        );
  7119.                 x = -9;
  7120.                 goto xgetx;
  7121.             }
  7122.         }
  7123. #endif /* NOSPL */
  7124.         renaming = 1;
  7125.         makestr(&rcv_rename,p);
  7126.         debug(F110,"FTP rcv_rename",rcv_rename,0);
  7127.     }
  7128.     if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
  7129.         printf("?Filename required but not given\n");
  7130.         x = -9;
  7131.         goto xgetx;
  7132.     } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
  7133.         printf("?You can't give both /LISTFILE and a remote filename\n");
  7134.         x = -9;
  7135.         goto xgetx;
  7136.     }
  7137.     CHECKCONN();                        /* Check connection */
  7138.  
  7139.     if (pv[SND_COL].ival > -1)
  7140.       x_fnc = pv[SND_COL].ival;
  7141.  
  7142. #ifndef NOSPL
  7143.     /* If as-name given for MGET, as-name must contain variables */
  7144.     if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
  7145.         char * s = tmpbuf;
  7146.         x = TMPBUFSIZ;
  7147.         zzstring(asnambuf,&s,&x);
  7148.         if (!strcmp(tmpbuf,asnambuf)) {
  7149.             printf(
  7150.     "?As-name for MGET must contain variables such as \\v(filename)\n"
  7151.                    );
  7152.             x = -9;
  7153.             goto xgetx;
  7154.         }
  7155.     }
  7156. #endif /* NOSPL */
  7157.  
  7158. /* doget: */
  7159.  
  7160.     if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
  7161.         fdispla = 0;
  7162.     } else {
  7163.         displa = 1;
  7164.         if (mdel || ftp_deb)
  7165.       fdispla = XYFD_B;
  7166.     }
  7167.     deleting = 0;
  7168.     if (pv[SND_DEL].ival > 0)           /* /DELETE was specified */
  7169.       deleting = 1;
  7170.     if (pv[SND_EXC].ival > 0)
  7171.       makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
  7172.     if (pv[SND_SMA].wval > -1)
  7173.       getsmaller = pv[SND_SMA].wval;
  7174.     if (pv[SND_LAR].wval > -1)
  7175.       getlarger = pv[SND_LAR].wval;
  7176.     if (pv[SND_NAM].ival > -1)
  7177.       x_cnv = pv[SND_NAM].ival;
  7178.     if (pv[SND_ERR].ival > -1)
  7179.       geterror = pv[SND_ERR].ival;
  7180.     if (pv[SND_MAI].ival > -1)
  7181.       toscreen = 1;
  7182.  
  7183.     if (pv[SND_NLS].ival > 0) {        /* Force NLST or MLSD? */
  7184.     mgetmethod = SND_NLS;
  7185.     mgetforced = 1;
  7186.     } else if (pv[SND_MLS].ival > 0) {
  7187.     mgetmethod = SND_MLS;
  7188.     mgetforced = 1;
  7189.     }
  7190.  
  7191. #ifdef FTP_RESTART
  7192.     if (pv[SND_RES].ival > 0) {
  7193.         if (!ftp_typ) {
  7194.             printf("?Sorry, GET /RECOVER requires binary mode\n");
  7195.             x = -9;
  7196.             goto xgetx;
  7197. #ifdef COMMENT
  7198.         /* Not true - the fact that the initial REST fails does not mean */
  7199.         /* it will fail here.  */
  7200.         } else if (!okrestart) {
  7201.             printf("WARNING: Server might not support restart...\n");
  7202. #endif /* COMMENT */
  7203.         }
  7204.         restart = 1;
  7205.     }
  7206. #endif /* FTP_RESTART */
  7207.  
  7208. #ifdef PIPESEND
  7209.     if (pv[SND_FLT].ival > 0) {         /* Have SEND FILTER? */
  7210.         if (pipesend) {
  7211.             printf("?Switch conflict: /FILTER and /COMMAND\n");
  7212.             x = -9;
  7213.             goto xgetx;
  7214.         }
  7215.         makestr(&rcvfilter,pv[SND_FLT].sval);
  7216.         debug(F110,"ftp get /FILTER", rcvfilter, 0);
  7217.     }
  7218.     if (rcvfilter || pipesend) {        /* /RESTART */
  7219. #ifdef FTP_RESTART
  7220.         if (restart) {                  /* with pipes or filters */
  7221.             printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
  7222.             x = -9;
  7223.             goto xgetx;
  7224.         }
  7225. #endif /* FTP_RESTART */
  7226.         if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
  7227.             printf(
  7228.         "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
  7229.             x = -9;
  7230.             goto xgetx;
  7231.         }
  7232.     }
  7233. #endif /* PIPESEND */
  7234.  
  7235.     tfc = (CK_OFF_T)0;            /* Initialize stats and counters */
  7236.     filcnt = 0;
  7237.     pktnum = 0;
  7238.     rpackets = 0L;
  7239.  
  7240.     if (pv[SND_FIL].ival > 0) {
  7241.         if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
  7242.             debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
  7243.             printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
  7244.             x = -9;
  7245.             goto xgetx;
  7246.         }
  7247.         if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
  7248.             zclose(ZMFILE);                       /* Failed */
  7249.             debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
  7250.             printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
  7251.             x = -9;
  7252.             goto xgetx;
  7253.         }
  7254.         listfile = 1;
  7255.         debug(F110,"ftp get listfile first",tmpbuf,0);
  7256.         makestr(&(mgetlist[0]),tmpbuf);
  7257.     }
  7258.     t0 = gmstimer();                    /* Record starting time */
  7259.  
  7260.     updating = 0;            /* Checking dates? */
  7261.     if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
  7262.       updating = 1;
  7263.     if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
  7264.       updating = 2;
  7265.     if (updating)            /* These switches force FTP DATES ON */
  7266.       ftp_dates |= 2;
  7267.  
  7268.     what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
  7269.  
  7270.     cancelgroup = 0;                    /* Group not canceled yet */
  7271.     if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
  7272.       changetype(ftp_typ,0);        /* Change to requested type */
  7273.     binary = ftp_typ;                   /* For file-transfer display */
  7274.     first = 1;                          /* For MGET list */
  7275.     done = 0;                           /* Loop control */
  7276.  
  7277. #ifdef CK_TMPDIR
  7278.     if (dldir && !f_tmpdir) {           /* If they have a download directory */
  7279.         if ((s = zgtdir())) {           /* Get current directory */
  7280.             if (zchdir(dldir)) {        /* Change to download directory */
  7281.                 ckstrncpy(savdir,s,TMPDIRLEN);
  7282.                 f_tmpdir = 1;           /* Remember that we did this */
  7283.             }
  7284.         }
  7285.     }
  7286. #endif /* CK_TMPDIR */
  7287.  
  7288.     if (ftp_nml) {                      /* /NAMELIST */
  7289.         debug(F110,"ftp GET ftp_nml",ftp_nml,0);
  7290.         if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
  7291.           fp_nml = stdout;
  7292.         else
  7293.           fp_nml = fopen(ftp_nml, "wb");
  7294.         if (!fp_nml) {
  7295.             printf("?%s: %s\n",ftp_nml,ck_errstr());
  7296.             goto xgetx;
  7297.         }
  7298.     }
  7299.     while (!done && !cancelgroup) {     /* Loop for all files */
  7300.                                         /* or until canceled. */
  7301. #ifdef FTP_PROXY
  7302.         /* do something here if proxy */
  7303. #endif /* FTP_PROXY */
  7304.  
  7305.         rs_len = (CK_OFF_T)0;        /* REGET position */
  7306.         cancelfile = 0;                 /* This file not canceled yet */
  7307.         haspath = 0;                    /* Recalculate this each time thru */
  7308.  
  7309.         if (getone) {                   /* GET */
  7310.             char * p;
  7311.             s = line;
  7312.             src = line;                 /* Server name */
  7313.             done = 1;
  7314.             debug(F111,"ftp get file",s,0);
  7315.         } else if (mget) {              /* MGET */
  7316.             src = mgetlist[mgetx];
  7317.             debug(F111,"ftp mget remote_files A",src,first);
  7318.             s = (char *)remote_files(first,
  7319.                      (CHAR *)mgetlist[mgetx],
  7320.                      (CHAR *)pv[SND_PAT].sval,
  7321.                      0
  7322.                      );
  7323.             debug(F110,"ftp mget remote_files B",s,0);
  7324.             if (!s) s = "";
  7325.             if (!*s) {
  7326.                 first = 1;
  7327.                 if (listfile) {        /* Names from listfile */
  7328.                   again:
  7329.                     tmpbuf[0] = NUL;
  7330.                     while (!tmpbuf[0]) {
  7331.                         if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
  7332.                             zclose(ZMFILE);
  7333.                             debug(F110,"ftp get listfile EOF",
  7334.                                   pv[SND_FIL].sval,0);
  7335.                             makestr(&(mgetlist[0]),NULL);
  7336.                             s = NULL;
  7337.                             done = 1;
  7338.                             break;
  7339.                         }
  7340.                     }
  7341.                     if (done)
  7342.                       continue;
  7343.  
  7344.                     makestr(&(mgetlist[0]),tmpbuf);
  7345.             debug(F110,"ftp get listfile next",tmpbuf,0);
  7346.                     s = (char *)remote_files(first,
  7347.                          (CHAR *)mgetlist[0],
  7348.                          (CHAR *)pv[SND_PAT].sval,
  7349.                          0
  7350.                          );
  7351.             debug(F110,"ftp mget remote_files C",s,0);
  7352.                     if (!s) {
  7353.                         ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
  7354.                         ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
  7355.                         tlog(F110,"ftp get file not found:",s,0);
  7356.                         goto again;
  7357.                     }
  7358.                 } else {        /* Names from command line */
  7359.                     mgetx++;
  7360.                     if (mgetx < mgetn)
  7361.               s = (char *)remote_files(first,
  7362.                            (CHAR *)mgetlist[mgetx],
  7363.                            (CHAR *)pv[SND_PAT].sval,
  7364.                            0
  7365.                            );
  7366.                     else
  7367.               s = NULL;
  7368.             if (!s) mgetx++;
  7369.             debug(F111,"ftp mget remote_files D",s,mgetx);
  7370.                 }
  7371.                 if (!s) {
  7372.             if (!first || mgetx >= mgetn) {
  7373.             done = 1;
  7374.             break;
  7375.             } else if (geterror) {
  7376.             status = 0;
  7377.             done = 1;
  7378.             break;
  7379.             } else {
  7380.             continue;
  7381.             }
  7382.                 }
  7383.             }
  7384.         }
  7385.     debug(F111,"ftp mget remote_files E",s,0);
  7386.         /*
  7387.           The semantics of NLST are ill-defined.  Suppose we have just sent
  7388.           NLST /path/[a-z]*.  Most servers send back names like /path/foo,
  7389.           /path/bar, etc.  But some send back only foo and bar, and subsequent
  7390.           RETR commands based on the pathless names are not going to work.
  7391.         */
  7392.         if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
  7393.             char * s3;
  7394.             if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
  7395.                 int len, left = 4096;
  7396.                 char * tmp = xtmpbuf;
  7397.                 len = s3 - mgetlist[mgetx] + 1;
  7398.                 ckstrncpy(tmp,mgetlist[mgetx],left);
  7399.                 tmp += len;
  7400.                 left -= len;
  7401.                 ckstrncpy(tmp,s,left);
  7402.                 s = xtmpbuf;
  7403.         debug(F111,"ftp mget remote_files F",s,0);
  7404.             }
  7405.         }
  7406.         first = 0;
  7407.         skipthis = 0;                   /* File selection... */
  7408.         msg = "";
  7409.         nam = s;                        /* Filename (without path) */
  7410.         rc = 0;                         /* Initial return code */
  7411.         s2 = "";
  7412.  
  7413.         if (!getone && !skipthis) {     /* For MGET and MDELETE... */
  7414.             char c, * p = s;
  7415.             int srvpath = 0;
  7416.             int usrpath = 0;
  7417.             int i, k = 0;
  7418.  
  7419.         debug(F111,"ftp mget havetype",s,havetype);
  7420.         if (havetype > 0 && havetype != FTYP_FILE) {
  7421.         /* Server says it's not file... */
  7422.         debug(F110,"ftp mget not-a-file",s,0);
  7423.         continue;
  7424.         }
  7425. /*
  7426.   Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
  7427.   But if the client did not ask for a recursive list, we have to ignore any
  7428.   server files that include a pathname that extends beyond any path that
  7429.   was included in the user's request.
  7430.  
  7431.   User's filespec is blah or path/blah (or other non-UNIX syntax).  We need to
  7432.   get the user's path segment.  Then, for each incoming file, if it begins
  7433.   with the same path segment, we must strip it (point past it).
  7434. */
  7435.             src = mgetlist[mgetx];      /* In case it moved! */
  7436.         if (src) {
  7437.         for (i = 0; src[i]; i++) { /* Find rightmost path separator */
  7438.             if (ispathsep(src[i])) /* in user's pathname */
  7439.               k = i + 1;
  7440.         }
  7441.         } else {
  7442.         src = "";
  7443.         }
  7444.             usrpath = k;                /* User path segment length */
  7445.             debug(F111,"ftp get usrpath",src,usrpath);
  7446.  
  7447.             p = s;                      /* Server filename */
  7448.             while ((c = *p++)) {        /* Look for path in server filename */
  7449.                 if (ispathsep(c)) {
  7450.             /* haspath++; */
  7451.                     nam = p;            /* Pathless name (for ckmatch) */
  7452.                     srvpath = p - s;    /* Server path segment length */
  7453.                 }
  7454.             }
  7455.             debug(F111,"ftp get srvpath",s,srvpath);
  7456.  
  7457.         if (usrpath == 0) {
  7458. /*
  7459.   Here we handle the case where the user said "mget foo" where foo is a
  7460.   directory name, and the server is sending back names like "foo/file1",
  7461.   "foo/file2", etc.  This is a nasty trick but it's necessary because the
  7462.   user can't compensate by typing "mget foo/" because then the server is
  7463.   likely to send back "foo//file1, foo//file2" etc, and we still won't
  7464.   get a match...
  7465. */
  7466.         int srclen = 0, srvlen = 0;
  7467.         if (src) srclen = strlen(src);
  7468.         if (s) srvlen = strlen(s);
  7469.         if (src && (srvlen > srclen)) {
  7470.             if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
  7471.             char * tmpsrc = NULL;
  7472.             tmpsrc = (char *)malloc(srclen + 2);
  7473.             strncpy(tmpsrc,src,srclen);
  7474.             tmpsrc[srclen] = s[srclen];
  7475.             tmpsrc[srclen+1] = NUL;
  7476.             free(mgetlist[mgetx]);
  7477.             mgetlist[mgetx] = tmpsrc;
  7478.             tmpsrc = NULL;
  7479.             src = mgetlist[mgetx];
  7480.             usrpath = srclen+1;
  7481.             }                  
  7482.         }
  7483.         }
  7484. /*
  7485.   If as-name not given and server filename includes path that matches
  7486.   the pathname from the user's file specification, we must trim the common
  7487.   path prefix from the server's name when constructing the local name.
  7488. */
  7489.             if (src &&            /* Wed Sep 25 17:27:48 2002 */
  7490.         !asnambuf[0] &&
  7491.         !recursive &&        /* Thu Sep 19 16:11:59 2002 */
  7492.         (srvpath > 0) &&
  7493.         !strncmp(src,s,usrpath)) {
  7494.                 s2 = s + usrpath;       /* Local name skips past remote path */
  7495.             }
  7496. #ifdef COMMENT
  7497.         /* This doesn't work if the path prefix contains wildcards! */
  7498.         haspath = (srvpath > usrpath);
  7499. #else
  7500.         {                /* Count path segments instead */
  7501.         int x1 = 0, x2 = 0;
  7502.         char *p;
  7503.         for (p = s; *p; p++)
  7504.           if (ispathsep(*p)) x1++;
  7505.         for (p = src; *p; p++) {
  7506.             if (ispathsep(*p)) x2++;
  7507.         }
  7508.         haspath = recursive ? x1 || x2 : x1 > x2;
  7509.         debug(F111,"ftp get server path segments",s,x1);
  7510.         debug(F111,"ftp get user   path segments",src,x2);
  7511.         }
  7512.  
  7513. #endif /* COMMENT */
  7514.             debug(F111,"ftp get haspath",s+usrpath,haspath);
  7515.  
  7516.             if (haspath) {              /* Server file has path segments? */
  7517.                 if (!recursive) {       /* [M]GET /RECURSIVE? */
  7518. /*
  7519.   We did not ask for a recursive listing, but the server is sending us one
  7520.   anyway (as wu-ftpd is wont to do).  We get here if the current filename
  7521.   includes a path segment beyond any path segment we asked for in our
  7522.   non-recursive [M]GET command.  We MUST skip this file.
  7523. */
  7524.                     debug(F111,"ftp get skipping because of path",s,0);
  7525.                     continue;
  7526.                 }
  7527.             }
  7528.         } else if (getone && !skipthis) { /* GET (not MGET) */
  7529.             char * p = nam;
  7530.         while ((c = *p++)) {    /* Handle path in local name */
  7531.         if (ispathsep(c)) {
  7532.             if (recursive) {    /* If recursive, keep it */
  7533.             haspath = 1;
  7534.             break;
  7535.             } else {        /* Otherwise lose it. */
  7536.               nam = p;
  7537.             }
  7538.         }
  7539.             }
  7540.             s2 = nam;
  7541.         }
  7542.         if (!*nam)                      /* Name without path */
  7543.           nam = s;
  7544.  
  7545.         if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
  7546.             if (nam[0] == '.')
  7547.           continue;
  7548.         }
  7549.         if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
  7550.         int xx;
  7551.             for (i = 0; i < NSNDEXCEPT; i++) {
  7552.                 if (!rcvexcept[i]) {
  7553.                     break;
  7554.                 }
  7555.         xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
  7556.         debug(F111,"ftp mget /except match",rcvexcept[i],xx);
  7557.                 if (xx) {
  7558.                     tlog(F100," refused: exception list","",0);
  7559.             msg = "Refused: Exception List";
  7560.                     skipthis++;
  7561.                     break;
  7562.                 }
  7563.             }
  7564.         }
  7565.         if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
  7566.             if (ckmatch(
  7567. #ifdef CKREGEX
  7568.                         "*.~[0-9]*~"
  7569. #else
  7570.                         "*.~*~"
  7571. #endif /* CKREGEX */
  7572.                         ,nam,0,1) > 0)
  7573.               continue;
  7574.         }
  7575.         if (!x_xla) {                   /* If translation is off */
  7576.             x_csl = -2;                 /* unset the charsets */
  7577.             x_csr = -2;
  7578.         }
  7579.         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
  7580.         if (!*s2)                       /* Local name */
  7581.           s2 = asnambuf;                /* As-name */
  7582.  
  7583.     if (!*s2)            /* Sat Nov 16 19:19:39 2002 */
  7584.       s2 = recursive ? s : nam;    /* Fri Jan 10 13:15:19 2003 */
  7585.  
  7586.         debug(F110,"ftp get filnam  ",s,0);
  7587.         debug(F110,"ftp get asname A",s2,0);
  7588.  
  7589.         /* Receiving to real file */
  7590.         if (!pipesend &&
  7591. #ifdef PIPESEND
  7592.             !rcvfilter &&
  7593. #endif /* PIPESEND */
  7594.             !toscreen) {
  7595. #ifndef NOSPL
  7596.             /* Do this here so we can decide whether to skip */
  7597.             if (cmd_quoting && !skipthis && asnambuf[0]) {
  7598.                 int n; char *p;
  7599.                 n = TMPBUFSIZ;
  7600.                 p = tmpbuf;
  7601.                 zzstring(asnambuf,&p,&n);
  7602.                 s2 = tmpbuf;
  7603.                 debug(F111,"ftp get asname B",s2,updating);
  7604.             }
  7605. #endif /* NOSPL */
  7606.  
  7607.         local = *s2 ? s2 : s;
  7608.  
  7609.         if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
  7610.         CK_OFF_T x;
  7611.         x = zchki(local);
  7612.         debug(F111,"ftp get DISCARD zchki",local,x);
  7613.         if (x > -1) {
  7614.             skipthis++;
  7615.             debug(F110,"ftp get skip name",local,0);
  7616.             tlog(F100," refused: name","",0);
  7617.             msg = "Refused: Name";
  7618.         }
  7619.         }
  7620.  
  7621. #ifdef DOUPDATE
  7622.             if (!skipthis && updating) { /* If updating and not yet skipping */
  7623.                 if (zchki(local) > -1) {
  7624.                     x = chkmodtime(local,s,0);
  7625. #ifdef DEBUG
  7626.             if (deblog) {
  7627.             if (updating == 2)
  7628.               debug(F111,"ftp get /dates-diff chkmodtime",local,x);
  7629.             else
  7630.               debug(F111,"ftp get /update chkmodtime",local,x);
  7631.             }
  7632. #endif /* DEBUG */
  7633.             if ((updating == 1 && x > 0) ||  /* /UPDATE */
  7634.             (updating == 2 && x == 1)) { /* /DATES-DIFFER */
  7635.             skipthis++;
  7636.             tlog(F100," refused: date","",0);
  7637.             msg = "Refused: Date";
  7638.                         debug(F110,"ftp get skip date",local,0);
  7639.                     }
  7640.                 }
  7641.             }
  7642. #endif /* DOUPDATE */
  7643.         }
  7644.         /* Initialize file size to -1 in case server doesn't understand */
  7645.         /* SIZE command, so xxscreen() will know we don't know the size */
  7646.  
  7647.         fsize = (CK_OFF_T)-1;
  7648.  
  7649.     /* Ask for size now only if we need it for selection */
  7650.     /* because if you're going thru a list 100,000 files to select */
  7651.     /* a small subset, 100,000 SIZE commands can take hours... */
  7652.  
  7653.     gotsize = 0;
  7654.         if (!mdel && !skipthis &&        /* Don't need size for DELE... */
  7655.         (getsmaller >= (CK_OFF_T)0  || getlarger >= (CK_OFF_T)0)) {
  7656.         if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
  7657.         fsize = havesize;
  7658.         gotsize = 1;
  7659.         } else {            /* No - must ask server */
  7660.         /*
  7661.           Prior to sending the NLST command we necessarily put the
  7662.           server into ASCII mode.  We must now put it back into the
  7663.           the requested mode so the upcoming SIZE command returns
  7664.           right kind of size; this is especially important for
  7665.           GET /RECOVER; otherwise the server returns the "ASCII" size
  7666.           of the file, rather than its true size.
  7667.         */
  7668.         changetype(ftp_typ,0);    /* Change to requested type */
  7669.         fsize = (CK_OFF_T)-1;
  7670.         if (sizeok) {
  7671.             x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
  7672.             if (x == REPLY_COMPLETE) {
  7673.             fsize = ckatofs(&ftp_reply_str[4]);
  7674.             gotsize = 1;
  7675.             }
  7676.         }
  7677.         }
  7678.             if (gotsize) {
  7679.                 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
  7680.                   skipthis++;
  7681.                 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
  7682.                   skipthis++;
  7683.                 if (skipthis) {
  7684.                     debug(F111,"ftp get skip size",s,fsize);
  7685.                     tlog(F100," refused: size","",0);
  7686.                     msg = "Refused: Size";
  7687.                 }
  7688. #ifdef COMMENT
  7689.             } else if (getone) {
  7690.                 /* SIZE can fail for many reasons.  Does the file exist? */
  7691.                 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
  7692.                 if (x != REPLY_COMPLETE) {
  7693.                     printf(">>> FILE NOT FOUND: %s\n",s);
  7694.                     break;
  7695.                 }
  7696. #endif /* COMMENT */
  7697.             }
  7698.         }
  7699.         if (skipthis) {                 /* Skipping this file? */
  7700.             ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
  7701.             if (msg)
  7702.               ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
  7703.             else
  7704.               ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
  7705.             continue;
  7706.         }
  7707.         if (fp_nml) {                   /* /NAMELIST only - no transfer */
  7708.             fprintf(fp_nml,"%s\n",s);
  7709.             continue;
  7710.         }
  7711.         if (recursive && haspath && !pipesend
  7712. #ifdef PIPESEND
  7713.             && !rcvfilter
  7714. #endif /* PIPESEND */
  7715.             ) {
  7716.         int x;
  7717.  
  7718. #ifdef NOMKDIR
  7719.         x = -1;
  7720. #else
  7721.             x = zmkdir(s);        /* Try to make the directory */
  7722. #endif /* NOMKDIR */
  7723.  
  7724.             if (x < 0) {
  7725.                 rc = -1;                /* Failure is fatal */
  7726.                 if (geterror) {
  7727.                     status = 0;
  7728.                     ftscreen(SCR_EM,0,(CK_OFF_T)0,
  7729.                  "Directory creation failure");
  7730.                     break;
  7731.                 }
  7732.             }
  7733.         }
  7734.  
  7735.         /* Not skipping */
  7736.  
  7737.     selected++;            /* Count this file as selected */
  7738.         pn = NULL;
  7739.  
  7740.     if (!gotsize && !mdel) {    /* Didn't get size yet */
  7741.         if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
  7742.         fsize = havesize;
  7743.         gotsize = 1;
  7744.         } else {            /* No - must ask server */
  7745.         fsize = (CK_OFF_T)-1;
  7746.         if (sizeok) {
  7747.             x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
  7748.             if (x == REPLY_COMPLETE) {
  7749.             fsize = ckatofs(&ftp_reply_str[4]);
  7750.             gotsize = 1;
  7751.             }
  7752.         }
  7753.         }
  7754.     }
  7755.         if (mdel) {                     /* [M]DELETE */
  7756.             if (displa && !ftp_vbm)
  7757.               printf(" %s...",s);
  7758.             rc =
  7759.              (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
  7760.             if (rc > -1) {
  7761.                 tlog(F110,"ftp mdelete",s,0);
  7762.                 if (displa && !ftp_vbm)
  7763.                   printf("OK\n");
  7764.             } else {
  7765.                 tlog(F110,"ftp mdelete failed:",s,0);
  7766.                 if (displa)
  7767.                   printf("Failed\n");
  7768.             }
  7769. #ifndef NOSPL
  7770. #ifdef PIPESEND
  7771.         } else if (rcvfilter) {         /* [M]GET with filter */
  7772.             int n; char * p;
  7773.             n = CKMAXPATH;
  7774.             p = tmpbuf;                 /* Safe - no asname with filter */
  7775.             zzstring(rcvfilter,&p,&n);
  7776.             if (n > -1)
  7777.               pn = tmpbuf;
  7778.             debug(F111,"ftp get rcvfilter",pn,n);
  7779. #endif /* PIPESEND */
  7780. #endif /* NOSPL */
  7781.             if (toscreen) s2 = "-";
  7782.         } else if (pipesend) {          /* [M]GET /COMMAND */
  7783.             int n; char * p;
  7784.             n = CKMAXPATH;
  7785.             p = tmpbuf;                 /* Safe - no asname with filter */
  7786.             zzstring(pipename,&p,&n);
  7787.             if (n > -1)
  7788.               pn = tmpbuf;
  7789.             debug(F111,"ftp get pipename",pipename,n);
  7790.             if (toscreen) s2 = "-";
  7791.         } else {                        /* [M]GET with no pipes or filters */
  7792.             debug(F111,"ftp get s2 A",s2,x_cnv);
  7793.             if (toscreen) {
  7794.                 s2 = "-";               /* (hokey convention for stdout) */
  7795.             } else if (!*s2) {          /* No asname? */
  7796.                 if (x_cnv) {            /* If converting */
  7797.                     nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
  7798.                     s2 = tmpbuf;
  7799.                     debug(F110,"ftp get nzrtol",s2,0);
  7800.                 } else                  /* otherwise */
  7801.                   s2 = s;               /* use incoming file's name */
  7802.             }
  7803.             debug(F110,"ftp get s2 B",s2,0);
  7804.  
  7805.             /* If local file already exists, take collision action */
  7806.  
  7807.             if (!pipesend &&
  7808. #ifdef PIPESEND
  7809.                 !rcvfilter &&
  7810. #endif /* PIPESEND */
  7811.                 !toscreen) {
  7812.         CK_OFF_T x;
  7813.                 x = zchki(s2);
  7814.                 debug(F111,"ftp get zchki",s2,x);
  7815.                 debug(F111,"ftp get x_fnc",s2,x_fnc);
  7816.  
  7817.                 if (x > (CK_OFF_T)-1 && !restart) {
  7818.             int x = -1;
  7819.             char * newname = NULL;
  7820.  
  7821.                     switch (x_fnc) {
  7822.                       case XYFX_A:      /* Append */
  7823.                         append = 1;
  7824.                         break;
  7825.                       case XYFX_R:      /* Rename */
  7826.                       case XYFX_B:    /* Backup */
  7827.             znewn(s2,&newname); /* Make unique name */
  7828.             debug(F110,"ftp get znewn",newname,0);
  7829.             if (x_fnc == XYFX_B) { /* Backup existing file */
  7830.                 x = zrename(s2,newname);
  7831.                 debug(F111,"ftp get backup zrename",newname,x);
  7832.             } else {      /* Rename incoming file */
  7833.                 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
  7834.                 s2 = tmpbuf;
  7835.                 debug(F111,"ftp get rename incoming",newname,x);
  7836.             }
  7837.             if (x < 0) {
  7838.                 ftscreen(SCR_EM,0,(CK_OFF_T)0,
  7839.                      "Backup/Rename failed");
  7840.                 x = 0;
  7841.                 goto xgetx;
  7842.             }
  7843.             break;
  7844.                       case XYFX_D:      /* Discard (already handled above) */
  7845.                       case XYFX_U:      /* Update (ditto) */
  7846.                       case XYFX_M:      /* Update (ditto) */
  7847.                       case XYFX_X:      /* Overwrite */
  7848.                         break;
  7849.                     }
  7850.                 }
  7851.             }
  7852.         }
  7853.         if (!mdel) {
  7854. #ifdef PIPESEND
  7855.             debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
  7856. #endif /* PIPESEND */
  7857.             if (pipesend && !toscreen)
  7858.               s2 = NULL;
  7859. #ifdef DEBUG
  7860.             if (deblog) {
  7861.                 debug(F101,"ftp get x_xla","",x_xla);
  7862.                 debug(F101,"ftp get x_csl","",x_csl);
  7863.                 debug(F101,"ftp get x_csr","",x_csr);
  7864.                 debug(F101,"ftp get append","",append);
  7865.             }
  7866. #endif /* DEBUG */
  7867.  
  7868.             rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
  7869.  
  7870. #ifdef DEBUG
  7871.             if (deblog) {
  7872.                 debug(F111,"ftp get rc",s,rc);
  7873.                 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
  7874.                 debug(F111,"ftp get cancelfile",s,cancelfile);
  7875.                 debug(F111,"ftp get cancelgroup",s,cancelgroup);
  7876.                 debug(F111,"ftp get renaming",s,renaming);
  7877.                 debug(F111,"ftp get moving",s,moving);
  7878.             }
  7879. #endif /* DEBUG */
  7880.         }
  7881.         if (rc > -1) {
  7882.             good++;
  7883.             status = 1;
  7884.             if (!cancelfile) {
  7885.                 if (deleting) {         /* GET /DELETE (source file) */
  7886.                     rc =
  7887.                       (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
  7888.                         ? 1 : -1;
  7889.                     tlog(F110, (rc > -1) ?
  7890.                          " deleted" : " failed to delete", s, 0);
  7891.                 }
  7892.         if (renaming && rcv_rename && !toscreen) {
  7893.                     char *p;            /* Rename downloaded file */
  7894. #ifndef NOSPL
  7895.                     char tmpbuf[CKMAXPATH+1];
  7896.                     int n;
  7897.                     n = CKMAXPATH;
  7898.                     p = tmpbuf;
  7899.                     debug(F111,"ftp get /rename",rcv_rename,0);
  7900.                     zzstring(rcv_rename,&p,&n);
  7901.                     debug(F111,"ftp get /rename",rcv_rename,0);
  7902.                     p = tmpbuf;
  7903. #else
  7904.                     p = rcv_rename;
  7905. #endif /* NOSPL */
  7906.                     rc = (zrename(s2,p) < 0) ? -1 : 1;
  7907.                     debug(F111,"doftpget /RENAME zrename",p,rc);
  7908.                     tlog(F110, (rc > -1) ?
  7909.                          " renamed to" :
  7910.                          " failed to rename to",
  7911.                          p,
  7912.                          0
  7913.                          );
  7914.                 } else if (moving && rcv_move && !toscreen) {
  7915.                     char *p;            /* Move downloaded file */
  7916. #ifndef NOSPL
  7917.                     char tmpbuf[CKMAXPATH+1];
  7918.                     int n;
  7919.                     n = TMPBUFSIZ;
  7920.                     p = tmpbuf;
  7921.                     debug(F111,"ftp get /move-to",rcv_move,0);
  7922.                     zzstring(rcv_move,&p,&n);
  7923.                     p = tmpbuf;
  7924. #else
  7925.                     p = rcv_move;
  7926. #endif /* NOSPL */
  7927.                     debug(F111,"ftp get /move-to",p,0);
  7928.                     rc = (zrename(s2,p) < 0) ? -1 : 1;
  7929.                     debug(F111,"doftpget /MOVE zrename",p,rc);
  7930.                     tlog(F110, (rc > -1) ?
  7931.                          " moved to" : " failed to move to", p, 0);
  7932.                 }
  7933.                 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
  7934.                     char * s = pv[SND_SRN].sval;
  7935.                     char * srvrn = pv[SND_SRN].sval;
  7936.                     char tmpbuf[CKMAXPATH+1];
  7937. #ifndef NOSPL
  7938.                     int y;              /* Pass it thru the evaluator */
  7939.                     extern int cmd_quoting; /* for \v(filename) */
  7940.                     debug(F111,"ftp get srv_renam",s,1);
  7941.  
  7942.                     if (cmd_quoting) {
  7943.                         y = CKMAXPATH;
  7944.                         s = (char *)tmpbuf;
  7945.                         zzstring(srvrn,&s,&y);
  7946.                         s = (char *)tmpbuf;
  7947.                     }
  7948. #endif /* NOSPL */
  7949.                     debug(F111,"ftp get srv_renam",s,1);
  7950.                     if (s) if (*s) {
  7951.                         int x;
  7952.                         x = ftp_rename(s2,s);
  7953.                         debug(F111,"ftp get ftp_rename",s2,x);
  7954.                         tlog(F110, (x > 0) ?
  7955.                              " renamed source file to" :
  7956.                              " failed to rename source file to",
  7957.                              s,
  7958.                              0
  7959.                              );
  7960.                         if (x < 1)
  7961.               return(-1);
  7962.                     }
  7963.                 }
  7964.             }
  7965.         }
  7966.         if (cancelfile)
  7967.           continue;
  7968.         if (rc < 0) {
  7969.             ftp_fai++;
  7970. #ifdef FTP_TIMEOUT
  7971.         debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
  7972.         if (ftp_timed_out) {
  7973.         status = 0;
  7974.                 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
  7975.         }
  7976. #endif    /* FTP_TIMEOUT */
  7977.             if (geterror) {
  7978.                 status = 0;
  7979.                 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
  7980.                 done++;
  7981.             }
  7982.         }
  7983.     }
  7984. #ifdef DEBUG
  7985.     if (deblog) {
  7986.     debug(F101,"ftp get status","",status);
  7987.     debug(F101,"ftp get cancelgroup","",cancelgroup);
  7988.     debug(F101,"ftp get cancelfile","",cancelfile);
  7989.     debug(F101,"ftp get selected","",selected);
  7990.     debug(F101,"ftp get good","",good);
  7991.     }
  7992. #endif /* DEBUG */
  7993.  
  7994.     if (selected == 0) {        /* No files met selection criteria */
  7995.     status = 1;            /* which is a kind of success. */
  7996.     } else if (status > 0) {        /* Some files were selected */
  7997.         if (cancelgroup)        /* but MGET was canceled */
  7998.           status = 0;            /* so MGET failed */
  7999.         else if (cancelfile && good < 1) /* If file was canceled */
  8000.           status = 0;            /* MGET failed if it got no files */
  8001.     }
  8002.     success = status;
  8003.     x = success;
  8004.     debug(F101,"ftp get success","",success);
  8005.  
  8006.   xgetx:
  8007.     pipesend = pipesave;                /* Restore global pipe selection */
  8008.     if (fp_nml) {                       /* Close /NAMELIST */
  8009.         if (fp_nml != stdout)
  8010.           fclose(fp_nml);
  8011.         fp_nml = NULL;
  8012.     }
  8013.     if (
  8014. #ifdef COMMENT
  8015.     x > -1
  8016. #else
  8017.     success
  8018. #endif    /* COMMENT */
  8019.     ) {                /* Download successful */
  8020. #ifdef GFTIMER
  8021.         t1 = gmstimer();                /* End time */
  8022.         sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
  8023.         if (!sec) sec = 0.001;
  8024.         fptsecs = sec;
  8025. #else
  8026.         sec = (t1 - t0) / 1000;
  8027.         if (!sec) sec = 1;
  8028. #endif /* GFTIMER */
  8029.         tfcps = (long) (tfc / sec);
  8030.         tsecs = (int)sec;
  8031.         lastxfer = W_FTP|W_RECV;
  8032.         xferstat = success;
  8033.     }
  8034.     if (dpyactive)
  8035.       ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
  8036. #ifdef CK_TMPDIR
  8037.     if (f_tmpdir) {                     /* If we changed to download dir */
  8038.         zchdir((char *) savdir);        /* Go back where we came from */
  8039.         f_tmpdir = 0;
  8040.     }
  8041. #endif /* CK_TMPDIR */
  8042.  
  8043.     for (i = 0; i <= SND_MAX; i++) {    /* Free malloc'd memory */
  8044.         if (pv[i].sval)
  8045.           free(pv[i].sval);
  8046.     }
  8047.     for (i = 0; i < mgetn; i++)         /* MGET list too */
  8048.       makestr(&(mgetlist[i]),NULL);
  8049.  
  8050.     if (cancelgroup)            /* Clear temp-file stack */
  8051.       mlsreset();
  8052.  
  8053.     ftreset();                          /* Undo switch effects */
  8054.     dpyactive = 0;
  8055.     return(x);
  8056. }
  8057.  
  8058. static struct keytab ftprmt[] = {
  8059.     { "cd",        XZCWD, 0 },
  8060.     { "cdup",      XZCDU, 0 },
  8061.     { "cwd",       XZCWD, CM_INV },
  8062.     { "delete",    XZDEL, 0 },
  8063.     { "directory", XZDIR, 0 },
  8064.     { "exit",      XZXIT, 0 },
  8065.     { "help",      XZHLP, 0 },
  8066.     { "login",     XZLGI, 0 },
  8067.     { "logout",    XZLGO, 0 },
  8068.     { "mkdir",     XZMKD, 0 },
  8069.     { "pwd",       XZPWD, 0 },
  8070.     { "rename",    XZREN, 0 },
  8071.     { "rmdir",     XZRMD, 0 },
  8072.     { "type",      XZTYP, 0 },
  8073.     { "", 0, 0 }
  8074. };
  8075. static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
  8076.  
  8077. int
  8078. doftpsite() {                /* Send a SITE command */
  8079.     int reply;
  8080.     char * s;
  8081.     int lcs = -1, rcs = -1;
  8082.     int save_vbm = ftp_vbm;
  8083.  
  8084. #ifndef NOCSETS
  8085.     if (ftp_xla) {
  8086.         lcs = ftp_csl;
  8087.         if (lcs < 0) lcs = fcharset;
  8088.         rcs = ftp_csx;
  8089.         if (rcs < 0) rcs = ftp_csr;
  8090.     }
  8091. #endif /* NOCSETS */
  8092.     if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
  8093.       return(x);
  8094.     CHECKCONN();
  8095.     ckstrncpy(line,s,LINBUFSIZ);
  8096.     if (testing) printf(" ftp site \"%s\"...\n",line);
  8097.     if (!ftp_vbm)
  8098.         ftp_vbm = !ckstrcmp("HELP",line,4,0);
  8099.     if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
  8100.     do {
  8101.         reply = getreply(0,lcs,rcs,ftp_vbm,0);
  8102.     } while (reply == REPLY_PRELIM);
  8103.     }
  8104.     ftp_vbm = save_vbm;
  8105.     return(success = (reply == REPLY_COMPLETE));
  8106. }
  8107.  
  8108.  
  8109. int
  8110. dosetftppsv() {                /* Passive mode */
  8111.     x = seton(&ftp_psv);
  8112.     if (x > 0) passivemode = ftp_psv;
  8113.     return(x);
  8114. }
  8115.  
  8116. /*  d o f t p r m t  --  Parse and execute REMOTE commands  */
  8117.  
  8118. int
  8119. doftprmt(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
  8120.     /* cx == 0 means REMOTE */
  8121.     /* cx != 0 is a XZxxx value */
  8122.     char * s;
  8123.  
  8124.     if (who != 0)
  8125.       return(0);
  8126.  
  8127.     if (cx == 0) {
  8128.         if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
  8129.           return(x);
  8130.         cx = x;
  8131.     }
  8132.     switch (cx) {
  8133.       case XZCDU:                       /* CDUP */
  8134.         if ((x = cmcfm()) < 0) return(x);
  8135.         return(doftpcdup());
  8136.  
  8137.       case XZCWD:                       /* RCD */
  8138.         if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
  8139.           return(x);
  8140.         ckstrncpy(line,s,LINBUFSIZ);
  8141.     s = brstrip(line);
  8142.         return(doftpcwd(s,1));
  8143.       case XZPWD:                       /* RPWD */
  8144.         return(doftppwd());
  8145.       case XZDEL:                       /* RDEL */
  8146.         return(doftpget(FTP_MDE,1));
  8147.       case XZDIR:                       /* RDIR */
  8148.         return(doftpdir(FTP_DIR));
  8149.       case XZHLP:                       /* RHELP */
  8150.         return(doftpxhlp());
  8151.       case XZMKD:                       /* RMKDIR */
  8152.         return(doftpmkd());
  8153.       case XZREN:                       /* RRENAME */
  8154.         return(doftpren());
  8155.       case XZRMD:                       /* RRMDIR */
  8156.         return(doftprmd());
  8157.       case XZLGO:                       /* LOGOUT */
  8158.         return(doftpres());
  8159.       case XZXIT:                       /* EXIT */
  8160.         return(ftpbye());
  8161.     }
  8162.     printf("?Not usable with FTP - \"%s\"\n", atmbuf);
  8163.     return(-9);
  8164. }
  8165.  
  8166. int
  8167. doxftp() {                              /* Command parser for built-in FTP */
  8168.     int cx, n;
  8169.     struct FDB kw, fl;
  8170.     char * s;
  8171.     int usetls = 0;
  8172.     int lcs = -1, rcs = -1;
  8173.  
  8174. #ifndef NOCSETS
  8175.     if (ftp_xla) {
  8176.         lcs = ftp_csl;
  8177.         if (lcs < 0) lcs = fcharset;
  8178.         rcs = ftp_csx;
  8179.         if (rcs < 0) rcs = ftp_csr;
  8180.     }
  8181. #endif /* NOCSETS */
  8182.  
  8183.     if (inserver)                       /* FTP not allowed in IKSD. */
  8184.       return(-2);
  8185.  
  8186.     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
  8187.         ftp_typ = g_ftp_typ;
  8188.         /* g_ftp_typ = -1; */
  8189.     }
  8190. #ifdef COMMENT
  8191. /*
  8192.   We'll set the collision action locally in doftpget() based on whether
  8193.   ftp_fnc was ever set to a value.  if not, we'll use the fncact value.
  8194. */
  8195.     if (ftp_fnc < 0)                    /* Inherit global collision action */
  8196.       ftp_fnc = fncact;                 /* if none specified for FTP */
  8197. #endif /* COMMENT */
  8198.  
  8199.     /* Restore global verbose mode */
  8200.     if (ftp_deb)
  8201.       ftp_vbm = 1;
  8202.     else if (quiet)
  8203.       ftp_vbm = 0;
  8204.     else
  8205.       ftp_vbm = ftp_vbx;
  8206.  
  8207.     ftp_dates &= 1;            /* Undo any previous /UPDATE switch */
  8208.  
  8209.     dpyactive = 0;                      /* Reset global transfer-active flag */
  8210.     printlines = 0;                     /* Reset printlines */
  8211.  
  8212.     if (fp_nml) {                       /* Reset /NAMELIST */
  8213.         if (fp_nml != stdout)
  8214.           fclose(fp_nml);
  8215.         fp_nml = NULL;
  8216.     }
  8217.     makestr(&ftp_nml,NULL);
  8218.  
  8219.     cmfdbi(&kw,                         /* First FDB - commands */
  8220.            _CMKEY,                      /* fcode */
  8221.            "Hostname; or FTP command",  /* help */
  8222.            "",                          /* default */
  8223.            "",                          /* addtl string data */
  8224.            nftpcmd,                     /* addtl numeric data 1: tbl size */
  8225.            0,                           /* addtl numeric data 2: none */
  8226.            xxstring,                    /* Processing function */
  8227.            ftpcmdtab,                   /* Keyword table */
  8228.            &fl                          /* Pointer to next FDB */
  8229.            );
  8230.     cmfdbi(&fl,                         /* A host name or address */
  8231.            _CMFLD,                      /* fcode */
  8232.            "Hostname or address",       /* help */
  8233.            "",                          /* default */
  8234.            "",                          /* addtl string data */
  8235.            0,                           /* addtl numeric data 1 */
  8236.            0,                           /* addtl numeric data 2 */
  8237.            xxstring,
  8238.            NULL,
  8239.            NULL
  8240.            );
  8241.     x = cmfdb(&kw);                     /* Parse a hostname or a keyword */
  8242.     if (x == -3) {
  8243.         printf("?ftp what? \"help ftp\" for hints\n");
  8244.         return(-9);
  8245.     }
  8246.     if (x < 0)
  8247.       return(x);
  8248.     if (cmresult.fcode == _CMFLD) {     /* If hostname */
  8249.         return(openftp(cmresult.sresult,0)); /* go open the connection */
  8250.     } else {
  8251.         cx = cmresult.nresult;
  8252.     }
  8253.     switch (cx) {
  8254.       case FTP_ACC:                     /* ACCOUNT */
  8255.         if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
  8256.           return(x);
  8257.         CHECKCONN();
  8258.         makestr(&ftp_acc,s);
  8259.         if (testing)
  8260.           printf(" ftp account: \"%s\"\n",ftp_acc);
  8261.         success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
  8262.         return(success);
  8263.  
  8264.       case FTP_GUP:                     /* Go UP */
  8265.         if ((x = cmcfm()) < 0) return(x);
  8266.         CHECKCONN();
  8267.         if (testing) printf(" ftp cd: \"(up)\"\n");
  8268.         return(success = doftpcdup());
  8269.  
  8270.       case FTP_CWD:                     /* CD */
  8271.         if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
  8272.           return(x);
  8273.         CHECKCONN();
  8274.         ckstrncpy(line,s,LINBUFSIZ);
  8275.         if (testing)
  8276.           printf(" ftp cd: \"%s\"\n", line);
  8277.         return(success = doftpcwd(line,1));
  8278.  
  8279.       case FTP_CHM:                     /* CHMOD */
  8280.         if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
  8281.           return(x);
  8282.         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  8283.         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
  8284.           return(x);
  8285.         CHECKCONN();
  8286.         ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
  8287.         if (testing)
  8288.           printf(" ftp chmod: %s\n",ftpcmdbuf);
  8289.         success =
  8290.           (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
  8291.         return(success);
  8292.  
  8293.       case FTP_CLS:                     /* CLOSE FTP connection */
  8294.         if ((y = cmcfm()) < 0)
  8295.           return(y);
  8296.         CHECKCONN();
  8297.         if (testing)
  8298.           printf(" ftp closing...\n");
  8299.         ftpclose();
  8300.         return(success = 1);
  8301.  
  8302.       case FTP_DIR:                     /* DIRECTORY of remote files */
  8303.       case FTP_VDI:
  8304.         return(doftpdir(cx));
  8305.  
  8306.       case FTP_GET:                     /* GET a remote file */
  8307.       case FTP_RGE:                     /* REGET */
  8308.       case FTP_MGE:                     /* MGET */
  8309.       case FTP_MDE:                     /* MDELETE */
  8310.         return(doftpget(cx,1));
  8311.  
  8312.       case FTP_IDL:                     /* IDLE */
  8313.         if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
  8314.           return(x);
  8315.         if ((y = cmcfm()) < 0)
  8316.           return(y);
  8317.         CHECKCONN();
  8318.         if (z < 0)  {                   /* Display idle timeout */
  8319.             if (testing)
  8320.               printf(" ftp query idle timeout...\n");
  8321.             success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
  8322.         } else {                        /* Set idle timeout */
  8323.             if (testing)
  8324.               printf(" ftp idle timeout set: %d...\n",z);
  8325.             success =
  8326.               (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
  8327.         }
  8328.         return(success);
  8329.  
  8330.       case FTP_MKD:                     /* MKDIR */
  8331.         return(doftpmkd());
  8332.  
  8333.       case FTP_MOD:                     /* MODTIME */
  8334.         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
  8335.           return(x);
  8336.         CHECKCONN();
  8337.         ckstrncpy(line,s,LINBUFSIZ);
  8338.         if (testing)
  8339.           printf(" ftp modtime \"%s\"...\n",line);
  8340.         success = 0;
  8341.         if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
  8342.         success = 1;
  8343.         mdtmok = 1;
  8344.         if (!quiet) {
  8345.         int flag = 0;
  8346.         char c, * s;
  8347.         struct tm tmremote;
  8348.  
  8349.         bzero((char *)&tmremote, sizeof(struct tm));
  8350.         s = ftp_reply_str;
  8351.         while ((c = *s++)) {
  8352.             if (c == SP) {
  8353.             flag++;
  8354.             break;
  8355.             }
  8356.         }
  8357.         if (flag) {
  8358.             if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
  8359.                    &tmremote.tm_year,
  8360.                    &tmremote.tm_mon,
  8361.                    &tmremote.tm_mday,
  8362.                    &tmremote.tm_hour,
  8363.                    &tmremote.tm_min,
  8364.                    &tmremote.tm_sec
  8365.                    ) == 6) {
  8366.             printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
  8367.                    line,
  8368.                    tmremote.tm_year,
  8369.                    tmremote.tm_mon,
  8370.                    tmremote.tm_mday,
  8371.                    tmremote.tm_hour,
  8372.                    tmremote.tm_min,
  8373.                    tmremote.tm_sec
  8374.                    );
  8375.             } else {
  8376.             success = 0;
  8377.             }
  8378.         }
  8379.         }
  8380.         }
  8381.         return(success);
  8382.  
  8383.       case FTP_OPN:                     /* OPEN connection */
  8384. #ifdef COMMENT
  8385.         x = cmfld("IP hostname or address","",&s,xxstring);
  8386.         if (x < 0) {
  8387.             success = 0;
  8388.             return(x);
  8389.         }
  8390.         ckstrncpy(line,s,LINBUFSIZ);
  8391.         s = line;
  8392.         return(openftp(s,0));
  8393. #else
  8394.         {                               /* OPEN connection */
  8395.             char name[TTNAMLEN+1], *p;
  8396.             extern int network;
  8397.             extern char ttname[];
  8398.             if (network)                /* If we have a current connection */
  8399.               ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
  8400.             else
  8401.               *name = '\0';             /* as default host */
  8402.             for (p = name; *p; p++)     /* Remove ":service" from end. */
  8403.               if (*p == ':') { *p = '\0'; break; }
  8404. #ifndef USETLSTAB
  8405.             x = cmfld("IP hostname or address",name,&s,xxstring);
  8406. #else
  8407.             cmfdbi(&kw,                 /* First FDB - commands */
  8408.                    _CMKEY,              /* fcode */
  8409.                    "Hostname or switch", /* help */
  8410.                    "",                  /* default */
  8411.                    "",                  /* addtl string data */
  8412.                    ntlstab,             /* addtl numeric data 1: tbl size */
  8413.                    0,                   /* addtl numeric data 2: none */
  8414.                    xxstring,            /* Processing function */
  8415.                    tlstab,              /* Keyword table */
  8416.                    &fl                  /* Pointer to next FDB */
  8417.                    );
  8418.             cmfdbi(&fl,                 /* A host name or address */
  8419.                    _CMFLD,              /* fcode */
  8420.                    "Hostname or address", /* help */
  8421.                    "",                  /* default */
  8422.                    "",                  /* addtl string data */
  8423.                    0,                   /* addtl numeric data 1 */
  8424.                    0,                   /* addtl numeric data 2 */
  8425.                    xxstring,
  8426.                    NULL,
  8427.                    NULL
  8428.                    );
  8429.  
  8430.             for (n = 0;; n++) {
  8431.                 x = cmfdb(&kw);         /* Parse a hostname or a keyword */
  8432.                 if (x == -3) {
  8433.                   printf("?ftp open what? \"help ftp\" for hints\n");
  8434.                   return(-9);
  8435.                 }
  8436.                 if (x < 0)
  8437.                   break;
  8438.                 if (cmresult.fcode == _CMFLD) { /* Hostname */
  8439.                     s = cmresult.sresult;
  8440.                     break;
  8441.                 } else if (cmresult.nresult == OPN_TLS) {
  8442.                     usetls = 1;
  8443.                 }
  8444.             }
  8445. #endif /* USETLSTAB */
  8446.             if (x < 0) {
  8447.                 success = 0;
  8448.                 return(x);
  8449.             }
  8450.             ckstrncpy(line,s,LINBUFSIZ);
  8451.             s = line;
  8452.             return(openftp(s,usetls));
  8453.         }
  8454. #endif /* COMMENT */
  8455.  
  8456.       case FTP_PUT:                     /* PUT */
  8457.       case FTP_MPU:                     /* MPUT */
  8458.       case FTP_APP:                     /* APPEND */
  8459.       case FTP_REP:            /* REPUT */
  8460.         return(doftpput(cx,1));
  8461.  
  8462.       case FTP_PWD:                     /* PWD */
  8463.         x = doftppwd();
  8464.         if (x > -1) success = x;
  8465.         return(x);
  8466.  
  8467.       case FTP_REN:                     /* RENAME */
  8468.         return(doftpren());
  8469.  
  8470.       case FTP_RES:                     /* RESET */
  8471.         return(doftpres());
  8472.  
  8473.       case FTP_HLP:                     /* (remote) HELP */
  8474.         return(doftpxhlp());
  8475.  
  8476.       case FTP_RMD:                     /* RMDIR */
  8477.         return(doftprmd());
  8478.  
  8479.       case FTP_STA:                     /* STATUS */
  8480.         if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
  8481.           return(x);
  8482.         CHECKCONN();
  8483.         ckstrncpy(line,s,LINBUFSIZ);
  8484.         if (testing) printf(" ftp status \"%s\"...\n",line);
  8485.         success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
  8486.         return(success);
  8487.  
  8488.       case FTP_SIT: {                   /* SITE */
  8489.       return(doftpsite());
  8490.       }
  8491.  
  8492.       case FTP_SIZ:                     /* (ask for) SIZE */
  8493.         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
  8494.           return(x);
  8495.         CHECKCONN();
  8496.         ckstrncpy(line,s,LINBUFSIZ);
  8497.         if (testing)
  8498.           printf(" ftp size \"%s\"...\n",line);
  8499.         success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
  8500.     if (success)
  8501.       sizeok = 1;
  8502.         return(success);
  8503.  
  8504.       case FTP_SYS:                     /* Ask for server's SYSTEM type */
  8505.         if ((x = cmcfm()) < 0) return(x);
  8506.         CHECKCONN();
  8507.         if (testing)
  8508.           printf(" ftp system...\n");
  8509.         success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
  8510.         return(success);
  8511.  
  8512.       case FTP_UMA:                     /* Set/query UMASK */
  8513.         if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
  8514.           if (x != -3)
  8515.             return(x);
  8516.         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
  8517.         if ((x = cmcfm()) < 0) return(x);
  8518.         CHECKCONN();
  8519.         if (testing) {
  8520.             if (tmpbuf[0])
  8521.               printf(" ftp umask \"%s\"...\n",tmpbuf);
  8522.             else
  8523.               printf(" ftp query umask...\n");
  8524.         }
  8525.         success = ftp_umask(tmpbuf);
  8526.         return(success);
  8527.  
  8528.       case FTP_USR:
  8529.         return(doftpusr());
  8530.  
  8531.       case FTP_QUO:
  8532.         if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
  8533.           return(x);
  8534.         CHECKCONN();
  8535.         success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
  8536.         return(success);
  8537.  
  8538.       case FTP_TYP:                     /* Type */
  8539.         if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
  8540.           return(x);
  8541.         if ((y = cmcfm()) < 0) return(y);
  8542.         CHECKCONN();
  8543.         ftp_typ = x;
  8544.         g_ftp_typ = x;
  8545.         tenex = (ftp_typ == FTT_TEN);
  8546.         changetype(ftp_typ,ftp_vbm);
  8547.         return(1);
  8548.  
  8549.       case FTP_CHK:                     /* Check if remote file(s) exist(s) */
  8550.         if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
  8551.           return(x);
  8552.         CHECKCONN();
  8553.         success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
  8554.         return(success);
  8555.  
  8556.       case FTP_FEA:                     /* RFC2389 */
  8557.         if ((y = cmcfm()) < 0)
  8558.           return(y);
  8559.         CHECKCONN();
  8560.     success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
  8561.     if (success) {
  8562.         if (sfttab[0] > 0) {
  8563.         ftp_aut = sfttab[SFT_AUTH];
  8564.         sizeok  = sfttab[SFT_SIZE];
  8565.         mdtmok  = sfttab[SFT_MDTM];
  8566.         mlstok  = sfttab[SFT_MLST];
  8567.         }
  8568.     }
  8569.     return(success);
  8570.  
  8571.       case FTP_OPT:                     /* RFC2389 */
  8572.         /* Perhaps this should be a keyword list... */
  8573.         if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
  8574.           return(x);
  8575.         CHECKCONN();
  8576.         ckstrncpy(line,s,LINBUFSIZ);
  8577.         if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
  8578.           return(x);
  8579.         success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
  8580.         return(success);
  8581.  
  8582.       case FTP_ENA:            /* FTP ENABLE */
  8583.       case FTP_DIS:            /* FTP DISABLE */
  8584.         if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
  8585.           return(x);
  8586.         if ((y = cmcfm()) < 0) return(y);
  8587.     switch (x) {
  8588.       case ENA_AUTH:        /* OK to use autoauthentication */
  8589.         ftp_aut = (cx == FTP_ENA) ? 1 : 0;
  8590.         sfttab[SFT_AUTH] = ftp_aut;
  8591.         break;
  8592.       case ENA_FEAT:        /* OK to send FEAT command */
  8593.         featok = (cx == FTP_ENA) ? 1 : 0;
  8594.         break;
  8595.       case ENA_MLST:        /* OK to use MLST/MLSD */
  8596.         mlstok = (cx == FTP_ENA) ? 1 : 0;
  8597.         sfttab[SFT_MLST] = mlstok;
  8598.         break;
  8599.       case ENA_MDTM:        /* OK to use MDTM */
  8600.         mdtmok = (cx == FTP_ENA) ? 1 : 0;
  8601.         sfttab[SFT_MDTM] = mdtmok;
  8602.         break;
  8603.       case ENA_SIZE:        /* OK to use SIZE */
  8604.         sizeok = (cx == FTP_ENA) ? 1 : 0;
  8605.         sfttab[SFT_SIZE] = sizeok;
  8606.         break;
  8607.     }
  8608.     return(success = 1);
  8609.     }
  8610.     return(-2);
  8611. }
  8612.  
  8613. #ifndef NOSHOW
  8614. static char *
  8615. shopl(x) int x; {
  8616.     switch (x) {
  8617.       case FPL_CLR: return("clear");
  8618.       case FPL_PRV: return("private");
  8619.       case FPL_SAF: return("safe");
  8620.       case 0:  return("(not set)");
  8621.       default: return("(unknown)");
  8622.     }
  8623. }
  8624.  
  8625. int
  8626. shoftp(brief) int brief; {
  8627.     char * s = "?";
  8628.     int n, x;
  8629.  
  8630.     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
  8631.         ftp_typ = g_ftp_typ;
  8632.         /* g_ftp_typ = -1; */
  8633.     }
  8634.     printf("\n");
  8635.     printf("FTP connection:                 %s\n",connected ?
  8636.            ftp_host :
  8637.            "(none)"
  8638.            );
  8639.     n = 2;
  8640.     if (connected) {
  8641.         n++;
  8642.         printf("FTP server type:                %s\n",
  8643.                ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
  8644.     }
  8645.     if (loggedin)
  8646.       printf("Logged in as:                   %s\n",
  8647.              strval(ftp_logname,"(unknown)"));
  8648.     else
  8649.       printf("Not logged in\n");
  8650.     n++;
  8651.     if (brief) return(0);
  8652.  
  8653.     printf("\nSET FTP values:\n\n");
  8654.     n += 3;
  8655.  
  8656.     printf(" ftp anonymous-password:        %s\n",
  8657.        ftp_apw ? ftp_apw : "(default)"
  8658.        );
  8659.     printf(" ftp auto-login:                %s\n",showoff(ftp_log));
  8660.     printf(" ftp auto-authentication:       %s\n",showoff(ftp_aut));
  8661.     switch (ftp_typ) {
  8662.       case FTT_ASC: s = "text"; break;
  8663.       case FTT_BIN: s = "binary"; break;
  8664.       case FTT_TEN: s = "tenex"; break;
  8665.     }
  8666. #ifdef FTP_TIMEOUT
  8667.     printf(" ftp timeout:                   %ld\n",ftp_timeout);
  8668. #endif    /* FTP_TIMEOUT */
  8669.     printf(" ftp type:                      %s\n",s);
  8670.     printf(" ftp get-filetype-switching:    %s\n",showoff(get_auto));
  8671.     printf(" ftp dates:                     %s\n",showoff(ftp_dates));
  8672.     printf(" ftp error-action:              %s\n",ftp_err ? "quit":"proceed");
  8673.     printf(" ftp filenames:                 %s\n",
  8674.            ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
  8675.            );
  8676.     printf(" ftp debug                      %s\n",showoff(ftp_deb));
  8677.  
  8678.     printf(" ftp passive-mode:              %s\n",showoff(ftp_psv));
  8679.     printf(" ftp permissions:               %s\n",showooa(ftp_prm));
  8680.     printf(" ftp verbose-mode:              %s\n",showoff(ftp_vbx));
  8681.     printf(" ftp send-port-commands:        %s\n",showoff(ftp_psv));
  8682.     printf(" ftp unique-server-names:       %s\n",showoff(ftp_usn));
  8683. #ifdef COMMENT
  8684.     /* See note in doxftp() */
  8685.     if (ftp_fnc < 0)
  8686.       ftp_fnc = fncact;
  8687. #endif /* COMMENT */
  8688.     printf(" ftp collision:                 %s\n",
  8689.        fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
  8690.     printf(" ftp server-time-offset:        %s\n",
  8691.        fts_sto ? fts_sto : "(none)");
  8692.     n += 15;
  8693.  
  8694. #ifndef NOCSETS
  8695.     printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
  8696.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8697.  
  8698.     printf(" ftp server-character-set:      %s\n",fcsinfo[ftp_csr].keyword);
  8699.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8700.  
  8701.     printf(" file character-set:            %s\n",fcsinfo[fcharset].keyword);
  8702.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8703. #endif /* NOCSETS */
  8704.  
  8705.     x = ftp_dis;
  8706.     if (x < 0)
  8707.       x = fdispla;
  8708.     switch (x) {
  8709.       case XYFD_N: s = "none"; break;
  8710.       case XYFD_R: s = "serial"; break;
  8711.       case XYFD_C: s = "fullscreen"; break;
  8712.       case XYFD_S: s = "crt"; break;
  8713.       case XYFD_B: s = "brief"; break;
  8714.     }
  8715.     printf(" ftp display:                   %s\n",s);
  8716.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8717.  
  8718.     if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
  8719.     printf(" enabled:                      ");
  8720.     if (ftp_aut) printf(" AUTH");
  8721.     if (featok)  printf(" FEAT");
  8722.     if (mdtmok)  printf(" MDTM");
  8723.     if (mlstok)  printf(" MLST");
  8724.     if (sizeok)  printf(" SIZE");
  8725.     printf("\n");
  8726.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8727.     }
  8728.     if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
  8729.     printf(" disabled:                     ");
  8730.     if (!ftp_aut) printf(" AUTH");
  8731.     if (!featok)  printf(" FEAT");
  8732.     if (!mdtmok)  printf(" MDTM");
  8733.     if (!mlstok)  printf(" MLST");
  8734.     if (!sizeok)  printf(" SIZE");
  8735.     printf("\n");
  8736.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8737.     }
  8738.     switch (ftpget) {
  8739.       case 0: s = "kermit"; break;
  8740.       case 1: s = "ftp"; break;
  8741.       case 2: s = "auto"; break;
  8742.       default: s = "?";
  8743.     }
  8744.     printf(" get-put-remote:                %s\n",s);
  8745.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8746.  
  8747.     printf("\n");
  8748.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8749.  
  8750. #ifdef FTP_SECURITY
  8751.     printf("Available security methods:    ");
  8752. #ifdef FTP_GSSAPI
  8753.     printf("GSSAPI ");
  8754. #endif /* FTP_GSSAPI */
  8755. #ifdef FTP_KRB4
  8756.     printf("Kerberos4 ");
  8757. #endif /* FTP_KRB4 */
  8758. #ifdef FTP_SRP
  8759.     printf("SRP ");
  8760. #endif /* FTP_SRP */
  8761. #ifdef FTP_SSL
  8762.     printf("SSL ");
  8763. #endif /* FTP_SSL */
  8764.  
  8765.     n++;
  8766.     printf("\n\n");
  8767.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8768.     printf(" ftp authtype:                  %s\n",strval(auth_type,NULL));
  8769.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8770.     printf(" ftp auto-encryption:           %s\n",showoff(ftp_cry));
  8771.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8772.     printf(" ftp credential-forwarding:     %s\n",showoff(ftp_cfw));
  8773.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8774.     printf(" ftp command-protection-level:  %s\n",shopl(ftp_cpl));
  8775.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8776.     printf(" ftp data-protection-level:     %s\n",shopl(ftp_dpl));
  8777.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8778.     printf(" ftp secure proxy:              %s\n",shopl(ssl_ftp_proxy));
  8779.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8780. #else
  8781.     printf("Available security methods:     (none)\n");
  8782.     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
  8783. #endif /* FTP_SECURITY */
  8784.  
  8785.     if (n <= cmd_rows - 3)
  8786.       printf("\n");
  8787.     return(0);
  8788. }
  8789. #endif /* NOSHOW */
  8790.  
  8791. #ifndef NOHELP
  8792. /* FTP HELP text strings */
  8793.  
  8794. static char * fhs_ftp[] = {
  8795.     "Syntax: FTP subcommand [ operands ]",
  8796.     "  Makes an FTP connection, or sends a command to the FTP server.",
  8797.     "  To see a list of available FTP subcommands, type \"ftp ?\".",
  8798.     "  and then use HELP FTP xxx to get help about subcommand xxx.",
  8799.     "  Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
  8800.     ""
  8801. };
  8802.  
  8803. static char * fhs_acc[] = {             /* ACCOUNT */
  8804.     "Syntax: FTP ACCOUNT text",
  8805.     "  Sends an account designator to an FTP server that needs one.",
  8806.     "  Most FTP servers do not use accounts; some use them for other",
  8807.     "  other purposes, such as disk-access passwords.",
  8808.     ""
  8809. };
  8810. static char * fhs_app[] = {             /* APPEND */
  8811.     "Syntax: FTP APPEND filname",
  8812.     "  Equivalent to [ FTP ] PUT /APPEND.  See HELP FTP PUT.",
  8813.     ""
  8814. };
  8815. static char * fhs_cls[] = {             /* BYE, CLOSE */
  8816.     "Syntax: [ FTP ] BYE",
  8817.     "  Logs out from the FTP server and closes the FTP connection.",
  8818.     "  Also see HELP SET GET-PUT-REMOTE.  Synonym: [ FTP ] CLOSE.",
  8819.     ""
  8820. };
  8821. static char * fhs_cwd[] = {             /* CD, CWD */
  8822.     "Syntax: [ FTP ] CD directory",
  8823.     "  Asks the FTP server to change to the given directory.",
  8824.     "  Also see HELP SET GET-PUT-REMOTE.  Synonyms: [ FTP ] CWD, RCD, RCWD.",
  8825.     ""
  8826. };
  8827. static char * fhs_gup[] = {             /* CDUP, UP */
  8828.     "Syntax: FTP CDUP",
  8829.     "  Asks the FTP server to change to the parent directory of its current",
  8830.     "  directory.  Also see HELP SET GET-PUT-REMOTE.  Synonym: FTP UP.",
  8831.     ""
  8832. };
  8833. static char * fhs_chm[] = {             /* CHMOD */
  8834.     "Syntax: FTP CHMOD filename permissions",
  8835.     "  Asks the FTP server to change the permissions, protection, or mode of",
  8836.     "  the given file.  The given permissions must be in the syntax of the",
  8837.     "  the server's file system, e.g. an octal number for UNIX.  Also see",
  8838.     "  FTP PUT /PERMISSIONS",
  8839.     ""
  8840. };
  8841. static char * fhs_mde[] = {             /* DELETE */
  8842.     "Syntax: FTP DELETE [ switches ] filespec",
  8843.     "  Asks the FTP server to delete the given file or files.",
  8844.     "  Synonym: MDELETE (Kermit makes no distinction between single and",
  8845.     "  multiple file deletion).  Optional switches:",
  8846.     " ",
  8847.     "  /ERROR-ACTION:{PROCEED,QUIT}",
  8848.     "  /EXCEPT:pattern",
  8849.     "  /FILENAMES:{AUTO,CONVERTED,LITERAL}",
  8850.     "  /LARGER-THAN:number",
  8851. #ifdef UNIXOROSK
  8852.     "  /NODOTFILES",
  8853. #endif /* UNIXOROSK */
  8854.     "  /QUIET",
  8855. #ifdef RECURSIVE
  8856.     "  /RECURSIVE (depends on server)",
  8857.     "  /SUBDIRECTORIES",
  8858. #endif /* RECURSIVE */
  8859.     "  /SMALLER-THAN:number",
  8860.     ""
  8861. };
  8862. static char * fhs_dir[] = {             /* DIRECTORY */
  8863.     "Syntax: FTP DIRECTORY [ filespec ]",
  8864.     "  Asks the server to send a directory listing of the files that match",
  8865.     "  the given filespec, or if none is given, all the files in its current",
  8866.     "  directory.  The filespec, including any wildcards, must be in the",
  8867.     "  syntax of the server's file system.  Also see HELP SET GET-PUT-REMOTE.",
  8868.     "  Synonym: RDIRECTORY.",
  8869.     ""
  8870. };
  8871. static char * fhs_vdi[] = {             /* VDIRECTORY */
  8872.     "Syntax: FTP VDIRECTORY [ filespec ]",
  8873.     "  Asks the server to send a directory listing of the files that match",
  8874.     "  the given filespec, or if none is given, all the files in its current",
  8875.     "  directory.  VDIRECTORY is needed for getting verbose directory",
  8876.     "  listings from certain FTP servers, such as on TOPS-20.  Try it if",
  8877.     "  FTP DIRECTORY lists only filenames without details.",
  8878.     ""
  8879. };
  8880. static char * fhs_fea[] = {             /* FEATURES */
  8881.     "Syntax: FTP FEATURES",
  8882.     "  Asks the FTP server to list its special features.  Most FTP servers",
  8883.     "  do not recognize this command.",
  8884.     ""
  8885. };
  8886. static char * fhs_mge[] = {             /* MGET */
  8887.     "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
  8888.     "  Download a single file or multiple files.  Asks the FTP server to send",
  8889.     "  the given file or files.  Also see FTP GET.  Optional switches:",
  8890.     " ",
  8891.     "  /AS-NAME:text",
  8892.     "    Name under which to store incoming file.",
  8893.     "    Pattern required for for multiple files.",
  8894.     "  /BINARY",                        /* /IMAGE */
  8895.     "    Force binary mode.  Synonym: /IMAGE.",
  8896.     "  /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
  8897.    "    What to do if an incoming file has the same name as an existing file.",
  8898.  
  8899. #ifdef PUTPIPE
  8900.     "  /COMMAND",
  8901.     "    Specifies that the as-name is a command to which the incoming file",
  8902.     "    is to be piped as standard input.",
  8903. #endif /* PUTPIPE */
  8904.  
  8905. #ifdef DOUPDATE
  8906.     "  /DATES-DIFFER",
  8907.     "    Download only those files whose modification date-times differ from",
  8908.     "    those of the corresponding local files, or that do not already",
  8909.     "    exist on the local computer.",
  8910. #endif /* DOUPDATE */
  8911.  
  8912.     "  /DELETE",
  8913.     "    Specifies that each file is to be deleted from the server after,",
  8914.     "    and only if, it is successfully downloaded.",
  8915.     "  /ERROR-ACTION:{PROCEED,QUIT}",
  8916.     "    When downloading a group of files, what to do upon failure to",
  8917.     "    transfer a file: quit or proceed to the next one.",
  8918.     "  /EXCEPT:pattern",
  8919.     "    Exception list: don't download any files that match this pattern.",
  8920.     "    See HELP WILDCARD for pattern syntax.",
  8921.     "  /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
  8922.     "    Whether to convert incoming filenames to local syntax.",
  8923. #ifdef PIPESEND
  8924. #ifndef NOSPL
  8925.     "  /FILTER:command",
  8926.     "    Pass incoming files through the given command.",
  8927. #endif /* NOSPL */
  8928. #endif /* PIPESEND */
  8929.     "  /LARGER-THAN:number",
  8930.     "    Only download files that are larger than the given number of bytes.",
  8931.     "  /LISTFILE:filename",
  8932.     "    Obtain the list of files to download from the given file.",
  8933. #ifndef NOCSETS
  8934.     "  /LOCAL-CHARACTER-SET:name",
  8935.     "    When downloading in text mode and character-set conversion is",
  8936.     "    desired, this specifies the target set.",
  8937. #endif /* NOCSETS */
  8938.     "  /MATCH:pattern",
  8939.     "    Specifies a pattern to be used to select filenames locally from the",
  8940.     "    server's list.",
  8941.     "  /MLSD",
  8942.     "    Forces sending of MLSD (rather than NLST) to get the file list.",
  8943. #ifdef CK_TMPDIR
  8944.     "  /MOVE-TO:directory",
  8945.     "    Each file that is downloaded is to be moved to the given local",
  8946.     "    directory immediately after, and only if, it has been received",
  8947.     "    successfully.",
  8948. #endif /* CK_TMPDIR */
  8949.     "  /NAMELIST:filename",
  8950.     "    Instead of downloading the files, stores the list of files that",
  8951.     "    would be downloaded in the given local file, one filename per line.",
  8952.     "  /NLST",
  8953.     "    Forces sending of NLST (rather than MLSD) to get the file list.",
  8954.     "  /NOBACKUPFILES",
  8955.     "    Don't download any files whose names end with .~<number>~.",
  8956.     "  /NODOTFILES",
  8957.     "    Don't download any files whose names begin with period (.).",
  8958.     "  /QUIET",
  8959.     "    Suppress the file-transfer display.",
  8960. #ifdef FTP_RESTART
  8961.     "  /RECOVER",                       /* /RESTART */
  8962.     "    Resume a download that was previously interrupted from the point of",
  8963.     "    failure.  Works only in binary mode.  Not supported by all servers.",
  8964.     "    Synonym: /RESTART.",
  8965. #endif /* FTP_RESTART */
  8966. #ifdef RECURSIVE
  8967.     "  /RECURSIVE",                     /* /SUBDIRECTORIES */
  8968.     "    Create subdirectories automatically if the server sends files",
  8969.     "    recursively and includes pathnames (most don't).",
  8970. #endif /* RECURSIVE */
  8971.     "  /RENAME-TO:text",
  8972.     "    Each file that is downloaded is to be renamed as indicated just,",
  8973.     "    after, and only if, it has arrived successfully.",
  8974. #ifndef NOCSETS
  8975.     "  /SERVER-CHARACTER-SET:name",
  8976.     "    When downloading in text mode and character-set conversion is desired"
  8977. ,   "    this specifies the original file's character set on the server.",
  8978. #endif /* NOCSETS */
  8979.     "  /SERVER-RENAME:text",
  8980.     "    Each server source file is to be renamed on the server as indicated",
  8981.     "    immediately after, but only if, it has arrived successfully.",
  8982.     "  /SMALLER-THAN:number",
  8983.     "    Download only those files smaller than the given number of bytes.",
  8984.     "  /TEXT",                          /* /ASCII */
  8985.     "    Force text mode.  Synonym: /ASCII.",
  8986.     "  /TENEX",
  8987.     "    Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
  8988. #ifndef NOCSETS
  8989.     "  /TRANSPARENT",
  8990.     "    When downloading in text mode, do not convert chracter-sets.",
  8991. #endif /* NOCSETS */
  8992.     "  /TO-SCREEN",
  8993.     "    The downloaded file is to be displayed on the screen.",
  8994. #ifdef DOUPDATE
  8995.     "  /UPDATE",
  8996.     "    Equivalent to /COLLISION:UPDATE.  Download only those files that are",
  8997.     "    newer than than their local counterparts, or that do not exist on",
  8998.     "    the local computer.",
  8999. #endif /* DOUPDATE */
  9000.     ""
  9001. };
  9002. static char * fhs_hlp[] = {             /* HELP */
  9003.     "Syntax: FTP HELP [ command [ subcommand... ] ]",
  9004.     "  Asks the FTP server for help about the given command.  First use",
  9005.     "  FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
  9006.     "  to get help for command \"xxx\".  Synonyms: REMOTE HELP, RHELP.",
  9007.     ""
  9008. };
  9009. static char * fhs_idl[] = {             /* IDLE */
  9010.     "Syntax: FTP IDLE [ number ]",
  9011.     "  If given without a number, this asks the FTP server to tell its",
  9012.     "  current idle-time limit.  If given with a number, it asks the server",
  9013.     "  to change its idle-time limit to the given number of seconds.",
  9014.     ""
  9015. };
  9016. static char * fhs_usr[] = {             /* USER, LOGIN */
  9017.     "Syntax: FTP USER username [ password [ account ] ]",
  9018.     "  Log in to the FTP server.  To be used when connected but not yet",
  9019.     "  logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
  9020.     "  If you omit the password, and one is required by the server, you are",
  9021.     "  prompted for it.  If you omit the account, no account is sent.",
  9022.     "  Synonym: FTP LOGIN.",
  9023.     ""
  9024. };
  9025. static char * fhs_get[] = {             /* GET */
  9026.     "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
  9027.     "  Download a single file.  Asks the FTP server to send the given file.",
  9028.     "  The optional as-name is the name to store it under when it arrives;",
  9029.     "  if omitted, the file is stored with the name it arrived with, as",
  9030.     "  modified according to the FTP FILENAMES setting or /FILENAMES: switch",
  9031.     "  value.  Aside from the file list and as-name, syntax and options are",
  9032.     "  the same as for FTP MGET, which is used for downloading multiple files."
  9033. ,   ""
  9034. };
  9035. static char * fhs_mkd[] = {             /* MKDIR */
  9036.     "Syntax: FTP MKDIR directory",
  9037.     "  Asks the FTP server to create a directory with the given name,",
  9038.     "  which must be in the syntax of the server's file system.  Synonyms:",
  9039.     "  REMOTE MKDIR, RMKDIR.",
  9040.     ""
  9041. };
  9042. static char * fhs_mod[] = {             /* MODTIME */
  9043.     "Syntax: FTP MODTIME filename",
  9044.     "  Asks the FTP server to send the modification time of the given file,",
  9045.     "  to be displayed on the screen.  The date-time format is all numeric:",
  9046.     "  yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
  9047.     "  fractions of seconds).",
  9048.     ""
  9049. };
  9050. static char * fhs_mpu[] = {             /* MPUT */
  9051.     "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
  9052.     "  Uploads files.  Sends the given file or files to the FTP server.",
  9053.     "  Also see FTP PUT.  Optional switches are:",
  9054.     " ",
  9055.     "  /AFTER:date-time",
  9056.     "    Uploads only those files newer than the given date-time.",
  9057.     "    HELP DATE for info about date-time formats.  Synonym: /SINCE.",
  9058. #ifdef PUTARRAY
  9059.     "  /ARRAY:array-designator",
  9060.     "    Tells Kermit to upload the contents of the given array, rather than",
  9061.     "    a file.",
  9062. #endif /* PUTARRAY */
  9063.     "  /AS-NAME:text",
  9064.     "    Name under which to send files.",
  9065.     "    Pattern required for for multiple files.",
  9066.     "  /BEFORE:date-time",
  9067.     "    Upload only those files older than the given date-time.",
  9068.     "  /BINARY",
  9069.     "    Force binary mode.  Synonym: /IMAGE.",
  9070. #ifdef PUTPIPE
  9071.     "  /COMMAND",
  9072.     "    Specifies that the filespec is a command whose standard output is",
  9073.     "    to be sent.",
  9074. #endif /* PUTPIPE */
  9075.  
  9076. #ifdef COMMENT
  9077. #ifdef DOUPDATE
  9078.     "  /DATES-DIFFER",
  9079.     "    Upload only those files whose modification date-times differ from",
  9080.     "    those on the server, or that don't exist on the server at all.",
  9081. #endif /* DOUPDATE */
  9082. #endif /* COMMENT */
  9083.  
  9084.     "  /DELETE",
  9085.     "    Specifies that each source file is to be deleted after, and only if,",
  9086.     "    it is successfully uploaded.",
  9087.     "  /DOTFILES",
  9088.     "    Include files whose names begin with period (.).",
  9089.     "  /ERROR-ACTION:{PROCEED,QUIT}",
  9090.     "    When uploading a group of files, what to do upon failure to",
  9091.     "    transfer a file: quit or proceed to the next one.",
  9092.     "  /EXCEPT:pattern",
  9093.     "    Exception list: don't upload any files that match this pattern.",
  9094.     "    See HELP WILDCARD for pattern syntax.",
  9095.     "  /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
  9096.     "    Whether to convert outbound filenames to common syntax.",
  9097. #ifdef PIPESEND
  9098. #ifndef NOSPL
  9099.     "  /FILTER:command",
  9100.     "    Pass outbound files through the given command.",
  9101. #endif /* NOSPL */
  9102. #endif /* PIPESEND */
  9103. #ifdef CKSYMLINK
  9104.     "  /FOLLOWINKS",
  9105.     "    Send files that are pointed to by symbolic links.",
  9106.     "  /NOFOLLOWINKS",
  9107.     "    Skip over symbolic links (default).",
  9108. #endif /* CKSYMLINK */
  9109.     "  /LARGER-THAN:number",
  9110.     "    Only upload files that are larger than the given number of bytes.",
  9111.     "  /LISTFILE:filename",
  9112.     "    Obtain the list of files to upload from the given file.",
  9113. #ifndef NOCSETS
  9114.     "  /LOCAL-CHARACTER-SET:name",
  9115.     "    When uploading in text mode and character-set conversion is",
  9116.     "    desired, this specifies the source-file character set.",
  9117. #endif /* NOCSETS */
  9118. #ifdef CK_TMPDIR
  9119.     "  /MOVE-TO:directory",
  9120.     "    Each source file that is uploaded is to be moved to the given local",
  9121.     "    directory when, and only if, the transfer is successful.",
  9122. #endif /* CK_TMPDIR */
  9123.     "  /NOBACKUPFILES",
  9124.     "    Don't upload any files whose names end with .~<number>~.",
  9125. #ifdef UNIXOROSK
  9126.     "  /NODOTFILES",
  9127.     "    Don't upload any files whose names begin with period (.).",
  9128. #endif /* UNIXOROSK */
  9129.     "  /NOT-AFTER:date-time",
  9130.     "    Upload only files that are not newer than the given date-time",
  9131.     "  /NOT-BEFORE:date-time",
  9132.     "    Upload only files that are not older than the given date-time",
  9133. #ifdef UNIX
  9134.     "  /PERMISSIONS",
  9135.     "    Ask the server to set the permissions of each file it receives",
  9136.     "    according to the source file's permissions.",
  9137. #endif /* UNIX */
  9138.     "  /QUIET",
  9139.     "    Suppress the file-transfer display.",
  9140. #ifdef FTP_RESTART
  9141.     "  /RECOVER",
  9142.     "    Resume an upload that was previously interrupted from the point of",
  9143.     "    failure.  Synonym: /RESTART.",
  9144. #endif /* FTP_RESTART */
  9145. #ifdef RECURSIVE
  9146.     "  /RECURSIVE",
  9147.     "    Send files from the given directory and all the directories beneath",
  9148.     "    it.  Synonym: /SUBDIRECTORIES.",
  9149. #endif /* RECURSIVE */
  9150.     "  /RENAME-TO:text",
  9151.     "    Each source file that is uploaded is to be renamed on the local",
  9152.     "    local computer as indicated when and only if, the transfer completes",
  9153.     "    successfully.",
  9154. #ifndef NOCSETS
  9155.     "  /SERVER-CHARACTER-SET:name",
  9156.     "    When uploading in text mode and character-set conversion is desired,",
  9157.     "    this specifies the character set to which the file should be",
  9158.     "    converted for storage on the server.",
  9159. #endif /* NOCSETS */
  9160.     "  /SERVER-RENAME:text",
  9161.     "    Each file that is uploaded is to be renamed as indicated on the",
  9162.     "    server after, and only if, if arrives successfully.",
  9163.     "  /SIMULATE",
  9164.     "    Show which files would be sent without actually sending them.",
  9165.     "  /SMALLER-THAN:number",
  9166.     "    Upload only those files smaller than the given number of bytes.",
  9167.     "  /TEXT",
  9168.     "    Force text mode.  Synonym: /ASCII.",
  9169.     "  /TENEX",
  9170.     "    Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
  9171. #ifndef NOCSETS
  9172.     "  /TRANSPARENT",
  9173.     "    When uploading in text mode, do not convert chracter-sets.",
  9174. #endif /* NOCSETS */
  9175.     "  /TYPE:{TEXT,BINARY}",
  9176.     "    Upload only files of the given type.",
  9177. #ifdef DOUPDATE
  9178.     "  /UPDATE",
  9179.     "    If a file of the same name exists on the server, upload only if",
  9180.     "    the local file is newer.",
  9181. #endif /* DOUPDATE */
  9182.     "  /UNIQUE-SERVER-NAMES",
  9183.     "    Ask the server to compute new names for any incoming file that has",
  9184.     "    the same name as an existing file.",
  9185.     ""
  9186. };
  9187. static char * fhs_opn[] = {             /* OPEN */
  9188. #ifdef CK_SSL
  9189.     "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
  9190.     "  Opens a connection to the FTP server on the given host.  The default",
  9191.     "  TCP port is 21 (990 if SSL/TLS is used), but a different port number",
  9192.     "  can be supplied if necessary.  Optional switches are:",
  9193. #else /* CK_SSL */
  9194.     "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
  9195.     "  Opens a connection to the FTP server on the given host.  The default",
  9196.     "  TCP port is 21, but a different port number can be supplied if",
  9197.     "  necessary.  Optional switches are:",
  9198. #endif /* CK_SSL */
  9199.     " ",
  9200.     "  /ANONYMOUS",
  9201.     "    Logs you in anonymously.",
  9202.     "  /USER:text",
  9203.     "    Supplies the given text as your username.",
  9204.     "  /PASSWORD:text",
  9205.     "    Supplies the given text as your password.  If you include a username",
  9206.     "    but omit this switch and the server requires a password, you are",
  9207.     "    prompted for it.",
  9208.     "  /ACCOUNT:text",
  9209.     "    Supplies the given text as your account, if required by the server.",
  9210.     "  /ACTIVE",
  9211.     "    Forces an active (rather than passive) connection.",
  9212.     "  /PASSIVE",
  9213.     "    Forces a passive (rather than active) connection.",
  9214.     "  /NOINIT",
  9215.     "    Inhibits sending initial REST, STRU, and MODE commands, which are",
  9216.     "    well-known standard commands, but to which some servers react badly.",
  9217.     "  /NOLOGIN",
  9218.     "    Inhibits autologin for this connection only.",
  9219.     ""
  9220. };
  9221. static char * fhs_opt[] = {             /* OPTS, OPTIONS */
  9222.     "Syntax: FTP OPTIONS",
  9223.     "  Asks the FTP server to list its current options.  Advanced, new,",
  9224.     "  not supported by most FTP servers.",
  9225.     ""
  9226. };
  9227. static char * fhs_put[] = {             /* PUT, SEND */
  9228.     "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
  9229.     "  Like FTP MPUT, but only one filespec is allowed, and if it is followed",
  9230.     "  by an additional field, this is interpreted as the name under which",
  9231.     "  to send the file or files.  See HELP FTP MPUT.",
  9232.     ""
  9233. };
  9234. static char * fhs_reput[] = {        /* REPUT, RESEND */
  9235.     "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
  9236.     "  Synonym for FTP PUT /RECOVER.  Recovers an interrupted binary-mode",
  9237.     "  upload from the point of failure if the FTP server supports recovery.",
  9238.     "  Synonym: [ FTP ] RESEND.  For details see HELP FTP MPUT.",
  9239.     ""
  9240. };
  9241. static char * fhs_pwd[] = {             /* PWD */
  9242.     "Syntax: FTP PWD",
  9243.     "  Asks the FTP server to reveal its current working directory.",
  9244.     "  Synonyms: REMOTE PWD, RPWD.",
  9245.     ""
  9246. };
  9247. static char * fhs_quo[] = {             /* QUOTE */
  9248.     "Syntax: FTP QUOTE text",
  9249.     "  Sends an FTP protocol command to the FTP server.  Use this command",
  9250.     "  for sending commands that Kermit might not support.",
  9251.     ""
  9252. };
  9253. static char * fhs_rge[] = {             /* REGET */
  9254.     "Syntax: FTP REGET",
  9255.     "  Synonym for FTP GET /RECOVER.",
  9256.     ""
  9257. };
  9258. static char * fhs_ren[] = {             /* RENAME */
  9259.     "Syntax: FTP RENAME name1 name1",
  9260.     "  Asks the FTP server to change the name of the file whose name is name1",
  9261.     "  and which resides in the FTP server's file system, to name2.  Works",
  9262.     "  only for single files; wildcards are not accepted.",
  9263.     ""
  9264. };
  9265. static char * fhs_res[] = {             /* RESET */
  9266.     "Syntax: FTP RESET",
  9267.     "  Asks the server to log out your session, terminating your access",
  9268.     "  rights, without closing the connection.",
  9269.     ""
  9270. };
  9271. static char * fhs_rmd[] = {             /* RMDIR */
  9272.     "Syntax: FTP RMDIR directory",
  9273.     "  Asks the FTP server to remove the directory whose name is given.",
  9274.     "  This usually requires the directory to be empty.  Synonyms: REMOTE",
  9275.     "  RMDIR, RRMDIR.",
  9276.     ""
  9277. };
  9278. static char * fhs_sit[] = {             /* SITE */
  9279.     "Syntax: FTP SITE text",
  9280.     "  Sends a site-specific command to the FTP server.",
  9281.     ""
  9282. };
  9283. static char * fhs_siz[] = {             /* SIZE */
  9284.     "Syntax: FTP SIZE filename",
  9285.     "  Asks the FTP server to send a numeric string representing the size",
  9286.     "  of the given file.",
  9287.     ""
  9288. };
  9289. static char * fhs_sta[] = {             /* STATUS */
  9290.     "Syntax: FTP STATUS [ filename ]",
  9291.     "  Asks the FTP server to report its status.  If a filename is given,",
  9292.     "  the FTP server should report details about the file.",
  9293.     ""
  9294. };
  9295. static char * fhs_sys[] = {             /* SYSTEM */
  9296.     "Syntax: FTP SYSTEM",
  9297.     "  Asks the FTP server to report its operating system type.",
  9298.     ""
  9299. };
  9300. static char * fhs_typ[] = {             /* TYPE */
  9301.     "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
  9302.     "  Puts the client and server in the indicated transfer mode.",
  9303.     "  ASCII is a synonym for TEXT.  TENEX is used only for uploading 8-bit",
  9304.     "  binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
  9305.     "  downloading files from TENEX or TOPS-20 that have been uploaded in",
  9306.     "  TENEX mode.",
  9307.     ""
  9308. };
  9309. static char * fhs_uma[] = {             /* UMASK */
  9310.     "Syntax: FTP UMASK number",
  9311.     "  Asks the FTP server to set its file creation mode mask.  Applies",
  9312.     "  only (or mainly) to UNIX-based FTP servers.",
  9313.     ""
  9314. };
  9315. static char * fhs_chk[] = {             /* CHECK */
  9316.     "Syntax: FTP CHECK remote-filespec",
  9317.     "  Asks the FTP server if the given file or files exist.  If the",
  9318.     "  remote-filespec contains wildcards, this command fails if no server",
  9319.     "  files match, and succeeds if at least one file matches.  If the",
  9320.     "  remote-filespec does not contain wildcards, this command succeeds if",
  9321.     "  the given file exists and fails if it does not.",
  9322.     ""
  9323. };
  9324. static char * fhs_ena[] = {        /* ENABLE */
  9325.     "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
  9326.     "  Enables the use of the given FTP protocol command in case it has been",
  9327.     "  disabled (but this is no guarantee that the FTP server understands it)."
  9328. ,
  9329.     "  Use SHOW FTP to see which of these commands is enabled and disabled.",
  9330.     "  Also see FTP DISABLE.",
  9331.     ""
  9332. };
  9333. static char * fhs_dis[] = {        /* DISABLE */
  9334.     "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
  9335.     "  Disables the use of the given FTP protocol command.",
  9336.     "  Also see FTP ENABLE.",
  9337.     ""
  9338. };
  9339.  
  9340. #endif /* NOHELP */
  9341.  
  9342. int
  9343. doftphlp() {
  9344.     int cx;
  9345.     if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
  9346.       if (cx != -3)
  9347.         return(cx);
  9348.     if ((x = cmcfm()) < 0)
  9349.       return(x);
  9350.  
  9351. #ifdef NOHELP
  9352.     printf("Sorry, no help available\n");
  9353. #else
  9354.     switch (cx) {
  9355.       case -3:
  9356.         return(hmsga(fhs_ftp));
  9357.       case FTP_ACC:                     /* ACCOUNT */
  9358.         return(hmsga(fhs_acc));
  9359.       case FTP_APP:                     /* APPEND */
  9360.         return(hmsga(fhs_app));
  9361.       case FTP_CLS:                     /* BYE, CLOSE */
  9362.         return(hmsga(fhs_cls));
  9363.       case FTP_CWD:                     /* CD, CWD */
  9364.         return(hmsga(fhs_cwd));
  9365.       case FTP_GUP:                     /* CDUP, UP */
  9366.         return(hmsga(fhs_gup));
  9367.       case FTP_CHM:                     /* CHMOD */
  9368.         return(hmsga(fhs_chm));
  9369.       case FTP_MDE:                     /* DELETE, MDELETE */
  9370.         return(hmsga(fhs_mde));
  9371.       case FTP_DIR:                     /* DIRECTORY */
  9372.         return(hmsga(fhs_dir));
  9373.       case FTP_VDI:                     /* VDIRECTORY */
  9374.         return(hmsga(fhs_vdi));
  9375.       case FTP_FEA:                     /* FEATURES */
  9376.         return(hmsga(fhs_fea));
  9377.       case FTP_GET:                     /* GET */
  9378.         return(hmsga(fhs_get));
  9379.       case FTP_HLP:                     /* HELP */
  9380.         return(hmsga(fhs_hlp));
  9381.       case FTP_IDL:                     /* IDLE */
  9382.         return(hmsga(fhs_idl));
  9383.       case FTP_USR:                     /* USER, LOGIN */
  9384.         return(hmsga(fhs_usr));
  9385.       case FTP_MGE:                     /* MGET */
  9386.         return(hmsga(fhs_mge));
  9387.       case FTP_MKD:                     /* MKDIR */
  9388.         return(hmsga(fhs_mkd));
  9389.       case FTP_MOD:                     /* MODTIME */
  9390.         return(hmsga(fhs_mod));
  9391.       case FTP_MPU:                     /* MPUT */
  9392.         return(hmsga(fhs_mpu));
  9393.       case FTP_OPN:                     /* OPEN */
  9394.         return(hmsga(fhs_opn));
  9395.       case FTP_OPT:                     /* OPTS, OPTIONS */
  9396.         return(hmsga(fhs_opt));
  9397.       case FTP_PUT:                     /* PUT, SEND */
  9398.         return(hmsga(fhs_put));
  9399.       case FTP_REP:                     /* REPUT, RESEND */
  9400.         return(hmsga(fhs_reput));
  9401.       case FTP_PWD:                     /* PWD */
  9402.         return(hmsga(fhs_pwd));
  9403.       case FTP_QUO:                     /* QUOTE */
  9404.         return(hmsga(fhs_quo));
  9405.       case FTP_RGE:                     /* REGET */
  9406.         return(hmsga(fhs_rge));
  9407.       case FTP_REN:                     /* RENAME */
  9408.         return(hmsga(fhs_ren));
  9409.       case FTP_RES:                     /* RESET */
  9410.         return(hmsga(fhs_res));
  9411.       case FTP_RMD:                     /* RMDIR */
  9412.         return(hmsga(fhs_rmd));
  9413.       case FTP_SIT:                     /* SITE */
  9414.         return(hmsga(fhs_sit));
  9415.       case FTP_SIZ:                     /* SIZE */
  9416.         return(hmsga(fhs_siz));
  9417.       case FTP_STA:                     /* STATUS */
  9418.         return(hmsga(fhs_sta));
  9419.       case FTP_SYS:                     /* SYSTEM */
  9420.         return(hmsga(fhs_sys));
  9421.       case FTP_TYP:                     /* TYPE */
  9422.         return(hmsga(fhs_typ));
  9423.       case FTP_UMA:                     /* UMASK */
  9424.         return(hmsga(fhs_uma));
  9425.       case FTP_CHK:                     /* CHECK */
  9426.         return(hmsga(fhs_chk));
  9427.       case FTP_ENA:
  9428.         return(hmsga(fhs_ena));
  9429.       case FTP_DIS:
  9430.         return(hmsga(fhs_dis));
  9431.       default:
  9432.         printf("Sorry, help available for this command.\n");
  9433.         break;
  9434.     }
  9435. #endif /* NOHELP */
  9436.     return(success = 0);
  9437. }
  9438.  
  9439. int
  9440. dosetftphlp() {
  9441.     int cx;
  9442.     if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
  9443.       if (cx != -3)
  9444.         return(cx);
  9445.     if (cx != -3)
  9446.       ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
  9447.     if ((x = cmcfm()) < 0)
  9448.       return(x);
  9449.  
  9450. #ifdef NOHELP
  9451.     printf("Sorry, no help available\n");
  9452. #else
  9453.     switch (cx) {
  9454.       case -3:
  9455.         printf("\nSyntax: SET FTP parameter value\n");
  9456.         printf("  Type \"help set ftp ?\" for a list of parameters.\n");
  9457.         printf("  Type \"help set ftp xxx\" for information about setting\n");
  9458.         printf("  parameter xxx.  Type \"show ftp\" for current values.\n\n");
  9459.         return(0);
  9460.  
  9461.       case FTS_BUG:
  9462.     printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
  9463.     printf(
  9464.         "  Activates a workaround for the named bug in the FTP server.\n");
  9465.     printf("  Type SET FTP BUG ? for a list of names.\n");
  9466.     printf("  For each bug, the default is OFF\n\n");
  9467.     return(0);
  9468.  
  9469. #ifdef FTP_SECURITY
  9470.       case FTS_ATP:                     /* "authtype" */
  9471.         printf("\nSyntax: SET FTP AUTHTYPE list\n");
  9472.         printf("  Specifies an ordered list of authentication methods to be\n"
  9473.                );
  9474.         printf("  when FTP AUTOAUTHENTICATION is ON.  The default list is:\n");
  9475.         printf("  GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
  9476.         return(0);
  9477.  
  9478.       case FTS_AUT:                     /* "autoauthentication" */
  9479.         printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
  9480.         printf("  Tells whether authentication should be negotiated by the\n");
  9481.         printf("  FTP OPEN command.  Default is ON.\n\n");
  9482.         break;
  9483.  
  9484.       case FTS_CRY:                     /* "autoencryption" */
  9485.         printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
  9486.         printf("  Tells whether encryption (privacy) should be negotiated\n");
  9487.         printf("  by the FTP OPEN command.  Default is ON.\n\n");
  9488.         break;
  9489. #endif /* FTP_SECURITY */
  9490.  
  9491.       case FTS_LOG:                     /* "autologin" */
  9492.         printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
  9493.         printf("  Tells Kermit whether to try to log you in automatically\n");
  9494.         printf("  as part of the connection process.\n\n");
  9495.         break;
  9496.  
  9497.       case FTS_DIS:
  9498.         printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
  9499.     printf("  Chooses the file-transfer display style for FTP.\n");
  9500.         printf("  Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
  9501.         break;
  9502.  
  9503. #ifndef NOCSETS
  9504.       case FTS_XLA:                     /* "character-set-translation" */
  9505.         printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
  9506.         printf("  Whether to translate character sets when transferring\n");
  9507.         printf("  text files with FTP.  OFF by default.\n\n");
  9508.         break;
  9509.  
  9510. #endif /* NOCSETS */
  9511.       case FTS_FNC:                     /* "collision" */
  9512.         printf("\n");
  9513.         printf(
  9514. "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
  9515.                );
  9516.         printf("  Tells what do when an incoming file has the same name as\n");
  9517.         printf("  an existing file when downloading with FTP.\n\n");
  9518.         break;
  9519.  
  9520. #ifdef FTP_SECURITY
  9521.       case FTS_CPL:                     /* "command-protection-level" */
  9522.         printf("\n");
  9523.         printf(
  9524. "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
  9525.                );
  9526.         printf("\n");
  9527.         printf(
  9528. "  Tells what level of protection is applied to the FTP command channel.\n\n");
  9529.         break;
  9530.       case FTS_CFW:                     /* "credential-forwarding" */
  9531.         printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
  9532.         printf("  Tells whether end-user credentials are to be forwarded\n");
  9533.         printf("  to the server if supported by the authentication method\n");
  9534.         printf("  (GSSAPI-KRB5 only).\n\n");
  9535.         break;
  9536.       case FTS_DPL:                     /* "data-protection-level" */
  9537.         printf("\n");
  9538.         printf(
  9539. "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
  9540.                );
  9541.         printf("\n");
  9542.         printf(
  9543. "  Tells what level of protection is applied to the FTP data channel.\n\n");
  9544.         break;
  9545. #endif /* FTP_SECURITY */
  9546.  
  9547.       case FTS_DBG:                     /* "debug" */
  9548.         printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
  9549.         printf("  Whether to print FTP protocol messages.\n\n");
  9550.         return(0);
  9551.  
  9552.       case FTS_ERR:                     /* "error-action" */
  9553.         printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
  9554.         printf("  What to do when an error occurs when transferring a group\n")
  9555.           ;
  9556.         printf("  of files: quit and fail, or proceed to the next file.\n\n");
  9557.         return(0);
  9558.  
  9559.       case FTS_CNV:                     /* "filenames" */
  9560.         printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
  9561.         printf("  What to do with filenames: convert them, take and use them\n"
  9562.                );
  9563.         printf("  literally; or choose what to do automatically based on the\n"
  9564.                );
  9565.         printf("  OS type of the server.  The default is AUTO.\n\n");
  9566.         return(0);
  9567.  
  9568.       case FTS_PSV:                     /* "passive-mode" */
  9569.         printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
  9570.         printf("  Whether to use passive mode, which helps to get through\n");
  9571.         printf("  firewalls.  ON by default.\n\n");
  9572.         return(0);
  9573.  
  9574.       case FTS_PRM:                     /* "permissions" */
  9575.         printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
  9576.         printf("  Whether to try to send file permissions when uploading.\n");
  9577.         printf("  OFF by default.  AUTO means only if client and server\n");
  9578.         printf("  have the same OS type.\n\n");
  9579.         return(0);
  9580.  
  9581.       case FTS_TST:                     /* "progress-messages" */
  9582.         printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
  9583.         printf("  Whether Kermit should print locally-generated feedback\n");
  9584.         printf("  messages for each non-file-transfer command.");
  9585.         printf("  ON by default.\n\n");
  9586.         return(0);
  9587.  
  9588.       case FTS_SPC:                     /* "send-port-commands" */
  9589.         printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
  9590.         printf("  Whether Kermit should send a new PORT command for each");
  9591.         printf("  task.\n\n");
  9592.         return(0);
  9593.  
  9594. #ifndef NOCSETS
  9595.       case FTS_CSR:                     /* "server-character-set" */
  9596.         printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
  9597.         printf("  The name of the character set used for text files on the\n");
  9598.         printf("  server.  Enter a name of '?' for a menu.\n\n");
  9599.         return(0);
  9600. #endif /* NOCSETS */
  9601.  
  9602.       case FTS_STO:            /* "server-time-offset */
  9603.     printf(
  9604. "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
  9605.         printf(
  9606. "  Specifies an offset to apply to the server's file timestamps.\n");
  9607.         printf(
  9608. "  Use this to correct for misconfigured server time or timezone.\n");
  9609.         printf(
  9610. "  Format: must begin with + or - sign.  Hours must be given; minutes\n");
  9611.         printf(
  9612. "  and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
  9613.         return(0);
  9614.  
  9615.       case FTS_TYP:                     /* "type" */
  9616.         printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
  9617.         printf("  Establishes the default transfer mode.\n");
  9618.         printf("  TENEX is used for uploading 8-bit binary files to 36-bit\n");
  9619.         printf("  platforms such as TENEX and TOPS-20 and for downloading\n");
  9620.         printf("  them again.  ASCII is a synonym for TEXT.  Normally each\n");
  9621.         printf("  file's type is determined automatically from its contents\n"
  9622.            );
  9623.         printf("  or its name; SET FTP TYPE does not prevent that, it only\n");
  9624.         printf("  tells which mode to use when the type can't be determined\n"
  9625.            );
  9626.         printf("  automatically.  To completely disable automatic transfer-\n"
  9627.            );
  9628.         printf("  mode switching and force either text or binary mode, give\n"
  9629.            );
  9630.         printf("  the top-level command ASCII or BINARY, as in traditional\n");
  9631.         printf("  FTP clients.\n\n");
  9632.         return(0);
  9633.  
  9634. #ifdef FTP_TIMEOUT
  9635.       case FTS_TMO:
  9636.        printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
  9637.        printf("  Establishes a timeout for FTP transfers.\n");
  9638.        printf("  The timeout applies per network read or write on the data\n");
  9639.        printf("  connection, not to the whole transfer.  By default the\n");
  9640.        printf("  timeout value is 0, meaning no timeout.  Use a positive\n");
  9641.        printf("  number to escape gracefully from hung data connections or\n");
  9642.        printf("  directory listings.\n\n");
  9643.         return(0);
  9644. #endif    /* FTP_TIMEOUT */
  9645.  
  9646. #ifdef PATTERNS
  9647.       case FTS_GFT:
  9648.         printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
  9649.         printf("  Tells whether GET and MGET should automatically switch\n");
  9650.         printf("  the appropriate file type, TEXT, BINARY, or TENEX, by\n");
  9651.         printf("  matching the name of each incoming file with its list of\n");
  9652.         printf("  FILE TEXT-PATTERNS and FILE BINARY-PATTERNS.  ON by\n");
  9653.         printf("  default.  SHOW PATTERNS displays the current pattern\n");
  9654.         printf("  list.  HELP SET FILE to see how to change it.\n");
  9655.         break;
  9656. #endif /* PATTERNS */
  9657.  
  9658.       case FTS_USN:                     /* "unique-server-names" */
  9659.         printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
  9660.         printf("  Tells whether to ask the server to create unique names\n");
  9661.         printf("  for any uploaded file that has the same name as an\n");
  9662.         printf("  existing file.  Default is OFF.\n\n");
  9663.         return(0);
  9664.  
  9665.       case FTS_VBM:                     /* "verbose-mode" */
  9666.         printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
  9667.         printf("  Whether to display all responses from the FTP server.\n");
  9668.         printf("  OFF by default.\n\n");
  9669.         return(0);
  9670.  
  9671.       case FTS_DAT:
  9672.         printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
  9673.         printf("  Whether to set date of incoming files from the file date\n");
  9674.         printf("  on the server.  ON by default.  Note: there is no way to\n")
  9675.           ;
  9676.         printf("  set the date on files uploaded to the server.  Also note\n");
  9677.     printf("  that not all servers support this feature.\n\n");
  9678.         return(0);
  9679.  
  9680.       case FTS_APW:
  9681.     printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
  9682.     printf("  Password to supply automatically on anonymous FTP\n");
  9683.     printf("  connections instead of the default user@host.\n");
  9684.     printf("  Omit optional text to restore default.\n\n");
  9685.     return(0);
  9686.  
  9687.       default:
  9688.         printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
  9689.     }
  9690. #endif /* NOHELP */
  9691.     return(0);
  9692. }
  9693.  
  9694. #ifndef L_SET
  9695. #define L_SET 0
  9696. #endif /* L_SET */
  9697. #ifndef L_INCR
  9698. #define L_INCR 1
  9699. #endif /* L_INCR */
  9700.  
  9701. #ifdef FTP_SRP
  9702. char srp_user[BUFSIZ];                  /* where is BUFSIZ defined? */
  9703. char *srp_pass;
  9704. char *srp_acct;
  9705. #endif /* FTP_SRP */
  9706.  
  9707. static int kerror;                      /* Needed for all auth types */
  9708.  
  9709. static struct   sockaddr_in hisctladdr;
  9710. static struct   sockaddr_in hisdataaddr;
  9711. static struct   sockaddr_in data_addr;
  9712. static int      data = -1;
  9713. static int      ptflag = 0;
  9714. static struct   sockaddr_in myctladdr;
  9715.  
  9716. #ifdef COMMENT
  9717. #ifndef OS2
  9718. UID_T getuid();
  9719. #endif /* OS2 */
  9720. #endif /* COMMENT */
  9721.  
  9722.  
  9723. static int cpend = 0;                   /* No pending replies */
  9724.  
  9725. #ifdef CK_SSL
  9726. extern SSL *ssl_ftp_con;
  9727. extern SSL_CTX *ssl_ftp_ctx;
  9728. extern SSL *ssl_ftp_data_con;
  9729. extern int ssl_ftp_active_flag;
  9730. extern int ssl_ftp_data_active_flag;
  9731. #endif /* CK_SSL */
  9732.  
  9733. /*  f t p c m d  --  Send a command to the FTP server  */
  9734. /*
  9735.   Call with:
  9736.     char * cmd: The command to send.
  9737.     char * arg: The argument (e.g. a filename).
  9738.     int lcs: The local character set index.
  9739.     int rcs: The remote (server) character set index.
  9740.     int vbm: Verbose mode:
  9741.       0 = force verbosity off
  9742.      >0 = force verbosity on
  9743.  
  9744.   If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
  9745.   and neither lcs or rcs is UCS-2, the arg is translated from the local
  9746.   character set to the remote one before sending the result to the server.
  9747.  
  9748.    Returns:
  9749.     0 on failure with ftpcode = -1
  9750.     >= 0 on success (getreply() result) with ftpcode = 0.
  9751. */
  9752. static char xcmdbuf[RFNBUFSIZ];
  9753.  
  9754. static int
  9755. ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
  9756.     char * s = NULL;
  9757.     int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
  9758.     sig_t oldintr;
  9759.  
  9760.     if (ftp_deb)                        /* DEBUG */
  9761.       vbm = 1;
  9762.     else if (quiet || dpyactive)        /* QUIET or File Transfer Active */
  9763.       vbm = 0;
  9764.     else if (vbm < 0)                   /* VERBOSE */
  9765.       vbm = ftp_vbm;
  9766.  
  9767.     cancelfile = 0;
  9768.     if (!cmd) cmd = "";
  9769.     if (!arg) arg = "";
  9770.     cmdlen = (int)strlen(cmd);
  9771.     len = cmdlen + (int)strlen(arg) + 1;
  9772.  
  9773.     if (ftp_deb /* && !dpyactive */ ) {
  9774. #ifdef FTP_PROXY
  9775.         if (ftp_prx) printf("%s ", ftp_host);
  9776. #endif /* FTP_PROXY */
  9777.         printf("---> ");
  9778.         if (!anonymous && strcmp("PASS",cmd) == 0)
  9779.           printf("PASS XXXX");
  9780.         else
  9781.           printf("%s %s",cmd,arg);
  9782.         printf("\n");
  9783.     }
  9784.     /* bzero(xcmdbuf,RFNBUFSIZ); */
  9785.     ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
  9786.  
  9787. #ifdef DEBUG
  9788.     if (deblog) {
  9789.         debug(F110,"ftpcmd cmd",cmd,0);
  9790.         debug(F110,"ftpcmd arg",arg,0);
  9791.         debug(F101,"ftpcmd lcs","",lcs);
  9792.         debug(F101,"ftpcmd rcs","",rcs);
  9793.     }
  9794. #endif /* DEBUG */
  9795.  
  9796.     if (csocket == -1) {
  9797.         perror("No control connection for command");
  9798.         ftpcode = -1;
  9799.         return(0);
  9800.     }
  9801.     havesigint = 0;
  9802.     oldintr = signal(SIGINT, cmdcancel);
  9803.  
  9804. #ifndef NOCSETS
  9805.     if (*arg &&                         /* If an arg was given */
  9806.         lcs > -1 &&                     /* and a local charset */
  9807.         rcs > -1 &&                     /* and a remote charset */
  9808.         lcs != rcs &&                   /* and the two are not the same */
  9809.         lcs != FC_UCS2 &&               /* and neither one is UCS-2 */
  9810.         rcs != FC_UCS2                  /* ... */
  9811.         ) {
  9812.         initxlate(lcs,rcs);             /* Translate arg from lcs to rcs */
  9813.         xgnbp = arg;                    /* Global pointer to input string */
  9814.         rfnptr = rfnbuf;                /* Global pointer to output buffer */
  9815.  
  9816.         while (1) {
  9817.             if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
  9818.             if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
  9819.         }
  9820.         /*
  9821.           We have to copy here instead of translating directly into
  9822.           xcmdbuf[] so strputc() can check length.  Alternatively we could
  9823.           write yet another xpnbyte() output function.
  9824.         */
  9825.         if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
  9826.             printf("?FTP command too long: %s + arg\n",cmd);
  9827.             ftpcode = -1;
  9828.             return(0);
  9829.         }
  9830.         x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
  9831.     }
  9832. #endif /* NOCSETS */
  9833.  
  9834.     s = xcmdbuf;                        /* Command to send to server */
  9835.  
  9836. #ifdef DEBUG
  9837.     if (deblog) {            /* Log it */
  9838.     if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
  9839.         /* But don't log passwords */
  9840.         debug(F110,"FTP SENT ","PASS XXXX",0);
  9841.     } else {
  9842.         debug(F110,"FTP SENT ",s,0);
  9843.     }
  9844.     }
  9845. #endif /* DEBUG */
  9846.  
  9847. #ifdef CK_ENCRYPTION
  9848.   again:
  9849. #endif /* CK_ENCRYPTION */
  9850.     if (scommand(s) == 0) {              /* Send it. */
  9851.       signal(SIGINT, oldintr);
  9852.       return(0);
  9853.     }
  9854.     cpend = 1;
  9855.     x = !strcmp(cmd,"QUIT");        /* Is it the QUIT command? */
  9856.     if (x)                /* In case we're interrupted */
  9857.       connected = 0;            /* while waiting for the reply... */
  9858.  
  9859.     fc = 0;                /* Function code for getreply() */
  9860.     if (!strncmp(cmd,"AUTH ",5)        /* Must parse AUTH reply */
  9861. #ifdef FTPHOST
  9862.     && strncmp(cmd, "HOST ",5)
  9863. #endif /* FTPHOST */
  9864.     ) {
  9865.     fc = GRF_AUTH;
  9866.     } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
  9867.     fc = GRF_FEAT;            /* But FEAT not widely understood */
  9868.     if (!ftp_deb)            /* So suppress error messages */
  9869.       vbm = 9;
  9870.     }
  9871.     r = getreply(x,            /* Expect connection to close */
  9872.          lcs,rcs,        /* Charsets */
  9873.          vbm,            /* Verbosity */
  9874.          fc            /* Function code */
  9875.          );
  9876.     if (q > -1)
  9877.       quiet = q;
  9878.  
  9879. #ifdef CK_ENCRYPTION
  9880.     if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
  9881.         fprintf(stderr,
  9882.                "ENC command not supported at server; retrying under MIC...\n");
  9883.         ftp_cpl = FPL_SAF;
  9884.         goto again;
  9885.     }
  9886. #endif /* CK_ENCRYPTION */
  9887. #ifdef COMMENT
  9888.     if (cancelfile && oldintr != SIG_IGN)
  9889.       (*oldintr)(SIGINT);
  9890. #endif /* COMMENT */
  9891.     signal(SIGINT, oldintr);
  9892.     return(r);
  9893. }
  9894.  
  9895. static VOID
  9896. lostpeer() {
  9897.     debug(F100,"lostpeer","",0);
  9898.     if (connected) {
  9899.         if (csocket != -1) {
  9900. #ifdef CK_SSL
  9901.             if (ssl_ftp_active_flag) {
  9902.                 SSL_shutdown(ssl_ftp_con);
  9903.                 SSL_free(ssl_ftp_con);
  9904.                 ssl_ftp_proxy = 0;
  9905.                 ssl_ftp_active_flag = 0;
  9906.                 ssl_ftp_con = NULL;
  9907.             }
  9908. #endif /* CK_SSL */
  9909. #ifdef TCPIPLIB
  9910.             socket_close(csocket);
  9911. #else /* TCPIPLIB */
  9912. #ifdef USE_SHUTDOWN
  9913.             shutdown(csocket, 1+1);
  9914. #endif /* USE_SHUTDOWN */
  9915.             close(csocket);
  9916. #endif /* TCPIPLIB */
  9917.             csocket = -1;
  9918.         }
  9919.         if (data != -1) {
  9920. #ifdef CK_SSL
  9921.             if (ssl_ftp_data_active_flag) {
  9922.                 SSL_shutdown(ssl_ftp_data_con);
  9923.                 SSL_free(ssl_ftp_data_con);
  9924.                 ssl_ftp_data_active_flag = 0;
  9925.                 ssl_ftp_data_con = NULL;
  9926.             }
  9927. #endif /* CK_SSL */
  9928. #ifdef TCPIPLIB
  9929.             socket_close(data);
  9930. #else /* TCPIPLIB */
  9931. #ifdef USE_SHUTDOWN
  9932.             shutdown(data, 1+1);
  9933. #endif /* USE_SHUTDOWN */
  9934.             close(data);
  9935. #endif /* TCPIPLIB */
  9936.             data = -1;
  9937.             globaldin = -1;
  9938.         }
  9939.         connected = 0;
  9940.         anonymous = 0;
  9941.         loggedin = 0;
  9942.         auth_type = NULL;
  9943.         ftp_cpl = ftp_dpl = FPL_CLR;
  9944. #ifdef CKLOGDIAL
  9945.         ftplogend();
  9946. #endif /* CKLOGDIAL */
  9947.  
  9948. #ifdef LOCUS
  9949.     if (autolocus)            /* Auotomatic locus switching... */
  9950.       setlocus(1,1);        /* Switch locus to local. */
  9951. #endif /* LOCUS */
  9952. #ifdef OS2
  9953.         DialerSend(OPT_KERMIT_HANGUP, 0);
  9954. #endif /* OS2 */
  9955.     }
  9956. #ifdef FTP_PROXY
  9957.     pswitch(1);
  9958.     if (connected) {
  9959.         if (csocket != -1) {
  9960. #ifdef TCPIPLIB
  9961.             socket_close(csocket);
  9962. #else /* TCPIPLIB */
  9963. #ifdef USE_SHUTDOWN
  9964.             shutdown(csocket, 1+1);
  9965. #endif /* USE_SHUTDOWN */
  9966.             close(csocket);
  9967. #endif /* TCPIPLIB */
  9968.             csocket = -1;
  9969.         }
  9970.         connected = 0;
  9971.         anonymous = 0;
  9972.         loggedin = 0;
  9973.         auth_type = NULL;
  9974.         ftp_cpl = ftp_dpl = FPL_CLR;
  9975.     }
  9976.     proxflag = 0;
  9977.     pswitch(0);
  9978. #endif /* FTP_PROXY */
  9979. }
  9980.  
  9981. int
  9982. ftpisopen() {
  9983.     return(connected);
  9984. }
  9985.  
  9986. static int
  9987. ftpclose() {
  9988.     extern int quitting;
  9989.     if (!connected)
  9990.       return(0);
  9991.     ftp_xfermode = xfermode;
  9992.     if (!ftp_vbm && !quiet)
  9993.       printlines = 1;
  9994.     ftpcmd("QUIT",NULL,0,0,ftp_vbm);
  9995.     if (csocket) {
  9996. #ifdef CK_SSL
  9997.         if (ssl_ftp_active_flag) {
  9998.             SSL_shutdown(ssl_ftp_con);
  9999.             SSL_free(ssl_ftp_con);
  10000.             ssl_ftp_proxy = 0;
  10001.             ssl_ftp_active_flag = 0;
  10002.             ssl_ftp_con = NULL;
  10003.         }
  10004. #endif /* CK_SSL */
  10005. #ifdef TCPIPLIB
  10006.         socket_close(csocket);
  10007. #else /* TCPIPLIB */
  10008. #ifdef USE_SHUTDOWN
  10009.         shutdown(csocket, 1+1);
  10010. #endif /* USE_SHUTDOWN */
  10011.         close(csocket);
  10012. #endif /* TCPIPLIB */
  10013.     }
  10014.     csocket = -1;
  10015.     connected = 0;
  10016.     anonymous = 0;
  10017.     loggedin = 0;
  10018.     mdtmok = 1;
  10019.     sizeok = 1;
  10020.     featok = 1;
  10021.     stouarg = 1;
  10022.     typesent = 0;
  10023.     data = -1;
  10024.     globaldin = -1;
  10025. #ifdef FTP_PROXY
  10026.     if (!proxy)
  10027.       macnum = 0;
  10028. #endif /* FTP_PROXY */
  10029.     auth_type = NULL;
  10030.     ftp_dpl = FPL_CLR;
  10031. #ifdef CKLOGDIAL
  10032.     ftplogend();
  10033. #endif /* CKLOGDIAL */
  10034. #ifdef LOCUS
  10035.     /* Unprefixed file management commands are executed locally */
  10036.     if (autolocus && !ftp_cmdlin && !quitting) {
  10037.         setlocus(1,1);
  10038.     }
  10039. #endif /* LOCUS */
  10040. #ifdef OS2
  10041.     DialerSend(OPT_KERMIT_HANGUP, 0);
  10042. #endif /* OS2 */
  10043.     return(0);
  10044. }
  10045.  
  10046. int
  10047. ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
  10048.     char * host;
  10049.  
  10050.     if (connected) {
  10051.         printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
  10052.         ftpcode = -1;
  10053.         return(0);
  10054.     }
  10055. #ifdef FTPHOST
  10056.     hostcmd = 0;
  10057. #endif /* FTPHOST */
  10058.     alike = 0;
  10059.     ftp_srvtyp[0] = NUL;
  10060.     if (!service) service = "";
  10061.     if (!*service) service = use_tls ? "ftps" : "ftp";
  10062.  
  10063.     if (!isdigit(service[0])) {
  10064.         struct servent *destsp;
  10065.         destsp = getservbyname(service, "tcp");
  10066.         if (!destsp) {
  10067.             if (!ckstrcmp(service,"ftp",-1,0)) {
  10068.                 ftp_port = 21;
  10069.             } else if (!ckstrcmp(service,"ftps",-1,0)) {
  10070.                 ftp_port = 990;
  10071.             } else {
  10072.                 printf("?Bad port name - \"%s\"\n", service);
  10073.                 ftpcode = -1;
  10074.                 return(0);
  10075.             }
  10076.         } else {
  10077.             ftp_port = destsp->s_port;
  10078.             ftp_port = ntohs((unsigned short)ftp_port);    /* SMS 2007/02/15 */
  10079.         }
  10080.     } else
  10081.         ftp_port = atoi(service);
  10082.     if (ftp_port <= 0) {
  10083.         printf("?Bad port name - \"%s\"\n", service);
  10084.         ftpcode = -1;
  10085.         return(0);
  10086.     }
  10087.     host = ftp_hookup(remote, ftp_port, use_tls);
  10088.     if (host) {
  10089.         ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
  10090.         connected = 1;                  /* Set FTP defaults */
  10091.         ftp_cpl = ftp_dpl = FPL_CLR;
  10092.         curtype = FTT_ASC;              /* Server uses ASCII mode */
  10093.         form = FORM_N;
  10094.         mode = MODE_S;
  10095.         stru = STRU_F;
  10096.         strcpy(bytename, "8");
  10097.         bytesize = 8;
  10098.  
  10099. #ifdef FTP_SECURITY
  10100.         if (ftp_aut) {
  10101.             if (ftp_auth()) {
  10102.                 if (ftp_cry 
  10103. #ifdef OS2
  10104.                      && ck_crypt_is_installed()
  10105. #endif /* OS2 */
  10106.                      ) {
  10107.                     if (!quiet)
  10108.                       printf("FTP Command channel is Private (encrypted)\n");
  10109.                     ftp_cpl = FPL_PRV;
  10110.                     if (setpbsz(DEFAULT_PBSZ) < 0) {
  10111.                         /* a failure here is most likely caused by a mixup */
  10112.                         /* in the session key used by client and server    */
  10113.             printf("?Protection buffer size negotiation failed\n");
  10114.                         return(0);
  10115.                     }
  10116.                     if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
  10117.                         if (!quiet)
  10118.                           printf("FTP Data channel is Private (encrypted)\n");
  10119.                         ftp_dpl = FPL_PRV;
  10120.                     } else
  10121.                       printf("?Unable to enable encryption on data channel\n");
  10122.                 } else {
  10123.                     ftp_cpl = FPL_SAF;
  10124.                 }
  10125.             }
  10126.             if (!connected)
  10127.           goto fail;
  10128.         }
  10129. #endif /* FTP_SECURITY */
  10130.         if (ftp_log)            /* ^^^ */
  10131.           ftp_login(remote);
  10132.  
  10133.         if (!connected)
  10134.       goto fail;
  10135.  
  10136.     ftp_xfermode = xfermode;
  10137.  
  10138. #ifdef CKLOGDIAL
  10139.         dologftp();
  10140. #endif /* CKLOGDIAL */
  10141. #ifdef OS2
  10142.         DialerSend(OPT_KERMIT_CONNECT, 0);
  10143. #endif /* OS2 */
  10144.         passivemode = ftp_psv;
  10145.         sendport = ftp_spc;
  10146.     mdtmok = 1;
  10147.     sizeok = 1;
  10148.     stouarg = 1;
  10149.     typesent = 0;
  10150.  
  10151.         if (ucbuf == NULL) {
  10152.             actualbuf = DEFAULT_PBSZ;
  10153.             while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
  10154.               actualbuf >>= 2;
  10155.         }
  10156.         if (!maxbuf)
  10157.           ucbufsiz = actualbuf - FUDGE_FACTOR;
  10158.     debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
  10159.         return(1);
  10160.     }
  10161.   fail:
  10162.     printf("?Can't FTP connect to %s:%s\n",remote,service);
  10163.     ftpcode = -1;
  10164.     return(0);
  10165. }
  10166.  
  10167. #ifdef CK_SSL
  10168. int
  10169. ssl_auth() {
  10170.     int i;
  10171.     char* p;
  10172.  
  10173.     if (ssl_debug_flag) {
  10174.         fprintf(stderr,"SSL DEBUG ACTIVE\n");
  10175.         fflush(stderr);
  10176.         /* for the moment I want the output on screen */
  10177.     }
  10178.     if (ssl_ftp_data_con != NULL) {
  10179.         SSL_free(ssl_ftp_data_con);
  10180.         ssl_ftp_data_con = NULL;
  10181.     }
  10182.     if (ssl_ftp_con != NULL) {
  10183.         SSL_free(ssl_ftp_con);
  10184.         ssl_ftp_con=NULL;
  10185.     }
  10186.     if (ssl_ftp_ctx != NULL) {
  10187.         SSL_CTX_free(ssl_ftp_ctx);
  10188.         ssl_ftp_ctx = NULL;
  10189.     }
  10190.  
  10191.     /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 
  10192.      * was added to OpenSSL 0.9.6e and 0.9.7.  It does not exist in previous
  10193.      * versions
  10194.      */
  10195. #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  10196. #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
  10197. #endif
  10198.     if (auth_type && !strcmp(auth_type,"TLS")) {
  10199.         ssl_ftp_ctx=SSL_CTX_new(SSLv3_client_method());
  10200.         if (!ssl_ftp_ctx)
  10201.           return(0);
  10202.         SSL_CTX_set_options(ssl_ftp_ctx,
  10203.                             SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
  10204.                             );
  10205.     } else {
  10206.         ssl_ftp_ctx = SSL_CTX_new(ftp_bug_use_ssl_v2 ? SSLv23_client_method() : 
  10207.                                   SSLv3_client_method());
  10208.         if (!ssl_ftp_ctx)
  10209.           return(0);
  10210.         SSL_CTX_set_options(ssl_ftp_ctx,
  10211.                             (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
  10212.                             SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
  10213.                             );
  10214.     }
  10215.     SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
  10216.                                   (pem_password_cb *)ssl_passwd_callback);
  10217.     SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
  10218.     SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
  10219.  
  10220. #ifdef OS2
  10221. #ifdef NT
  10222.     /* The defaults in the SSL crypto library are not appropriate for OS/2 */
  10223.     {
  10224.         char path[CKMAXPATH];
  10225.         extern char exedir[];
  10226.  
  10227.         ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
  10228.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
  10229.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10230.             if (ssl_debug_flag)
  10231.                 printf("?Unable to load verify-dir: %s\r\n",path);
  10232.         }
  10233.  
  10234.         ckmakmsg(path,CKMAXPATH,
  10235.                  (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
  10236.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
  10237.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10238.             if (ssl_debug_flag)
  10239.                 printf("?Unable to load verify-dir: %s\r\n",path);
  10240.         }
  10241.  
  10242.         ckmakmsg(path,CKMAXPATH,
  10243.                  (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
  10244.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
  10245.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10246.             if (ssl_debug_flag)
  10247.                 printf("?Unable to load verify-dir: %s\r\n",path);
  10248.         }
  10249.  
  10250.         ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
  10251.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
  10252.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10253.             if (ssl_debug_flag)
  10254.                 printf("?Unable to load verify-file: %s\r\n",path);
  10255.         }
  10256.  
  10257.         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
  10258.          "kermit 95/ca_certs.pem",NULL,NULL);
  10259.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
  10260.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10261.             if (ssl_debug_flag)
  10262.                 printf("?Unable to load verify-file: %s\r\n",path);
  10263.         }
  10264.  
  10265.         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
  10266.          "kermit 95/ca_certs.pem",NULL,NULL);
  10267.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
  10268.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10269.             if (ssl_debug_flag)
  10270.                 printf("?Unable to load verify-file: %s\r\n",path);
  10271.         }
  10272.     }
  10273. #else /* NT */
  10274.     /* The defaults in the SSL crypto library are not appropriate for OS/2 */
  10275.     {
  10276.  
  10277.         char path[CKMAXPATH];
  10278.         extern char exedir[];
  10279.  
  10280.         ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
  10281.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
  10282.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10283.             if (ssl_debug_flag)
  10284.                 printf("?Unable to load verify-dir: %s\r\n",path);
  10285.         }
  10286.         ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
  10287.         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
  10288.             debug(F110,"ftp ssl_auth unable to load path",path,0);
  10289.             if (ssl_debug_flag)
  10290.                 printf("?Unable to load verify-file: %s\r\n",path);
  10291.         }
  10292.     }
  10293. #endif /* NT */
  10294. #else /* OS2 */
  10295.     SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
  10296. #endif /* OS2 */
  10297.  
  10298.     if (ssl_verify_file &&
  10299.         SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
  10300.         debug(F110,
  10301.               "ftp ssl auth unable to load ssl_verify_file",
  10302.               ssl_verify_file,
  10303.               0
  10304.               );
  10305.         if (ssl_debug_flag)
  10306.           printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
  10307.     }
  10308.     if (ssl_verify_dir &&
  10309.         SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
  10310.         debug(F110,
  10311.               "ftp ssl auth unable to load ssl_verify_dir",
  10312.               ssl_verify_dir,
  10313.               0
  10314.               );
  10315.         if (ssl_debug_flag)
  10316.           printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
  10317.     }
  10318.  
  10319.     /* set up the new CRL Store */
  10320.     crl_store = (X509_STORE *)X509_STORE_new();
  10321.     if (crl_store) {
  10322. #ifdef OS2
  10323.         char path[CKMAXPATH];
  10324.         extern char exedir[];
  10325.  
  10326.         ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
  10327.         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
  10328.             debug(F110,"ftp ssl auth unable to load dir",path,0);
  10329.             if (ssl_debug_flag)
  10330.                 printf("?Unable to load crl-dir: %s\r\n",path);
  10331.         }
  10332. #ifdef NT
  10333.         ckmakmsg(path,CKMAXPATH,
  10334.          (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
  10335.         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
  10336.             debug(F110,"ftp ssl auth unable to load dir",path,0);
  10337.             if (ssl_debug_flag)
  10338.                 printf("?Unable to load crl-dir: %s\r\n",path);
  10339.         }
  10340.         ckmakmsg(path,CKMAXPATH,
  10341.          (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
  10342.         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
  10343.             debug(F110,"ftp ssl auth unable to load dir",path,0);
  10344.             if (ssl_debug_flag)
  10345.                 printf("?Unable to load crl-dir: %s\r\n",path);
  10346.         }
  10347. #endif /* NT */
  10348.         
  10349.         ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
  10350.         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
  10351.             debug(F110,"ftp ssl auth unable to load file",path,0);
  10352.             if (ssl_debug_flag)
  10353.                 printf("?Unable to load crl-file: %s\r\n",path);
  10354.         }
  10355. #ifdef NT
  10356.         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
  10357.          "kermit 95/ca_crls.pem",NULL,NULL);
  10358.         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
  10359.             debug(F110,"ftp ssl auth unable to load file",path,0);
  10360.             if (ssl_debug_flag)
  10361.                 printf("?Unable to load crl-file: %s\r\n",path);
  10362.         }
  10363.         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
  10364.          "kermit 95/ca_crls.pem",NULL,NULL);
  10365.         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
  10366.             debug(F110,"ftp ssl auth unable to load file",path,0);
  10367.             if (ssl_debug_flag)
  10368.                 printf("?Unable to load crl-file: %s\r\n",path);
  10369.         }
  10370. #endif /* NT */
  10371. #endif /* OS2 */
  10372.  
  10373.         if (ssl_crl_file || ssl_crl_dir) {
  10374.             if (ssl_crl_file &&
  10375.                 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
  10376.                 debug(F110,
  10377.                       "ftp ssl auth unable to load ssl_crl_file",
  10378.                       ssl_crl_file,
  10379.                       0
  10380.                       );
  10381.                 if (ssl_debug_flag)
  10382.                   printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
  10383.             }
  10384.             if (ssl_crl_dir &&
  10385.                 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
  10386.                 debug(F110,
  10387.                       "ftp ssl auth unable to load ssl_crl_dir",
  10388.                       ssl_crl_dir,
  10389.                       0
  10390.                       );
  10391.                 if (ssl_debug_flag)
  10392.                   printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
  10393.             }
  10394.         } else {
  10395.             X509_STORE_set_default_paths(crl_store);
  10396.         }
  10397.     }
  10398.     SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
  10399.                        ssl_client_verify_callback);
  10400.     ssl_verify_depth = -1;
  10401.     ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
  10402.     tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
  10403.     SSL_set_fd(ssl_ftp_con,csocket);
  10404.     SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
  10405.     if (ssl_cipher_list) {
  10406.         SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
  10407.     } else {
  10408.         char * p;
  10409.         if (p = getenv("SSL_CIPHER")) {
  10410.             SSL_set_cipher_list(ssl_ftp_con,p);
  10411.         } else {
  10412.             SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
  10413.         }
  10414.     }
  10415.     if (ssl_debug_flag) {
  10416.         fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
  10417.         fflush(stderr);
  10418.     }
  10419.     if (SSL_connect(ssl_ftp_con) <= 0) {
  10420.         static char errbuf[1024];
  10421.         ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
  10422.                  ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
  10423.         fprintf(stderr,"%s\n", errbuf);
  10424.         fflush(stderr);
  10425.         ssl_ftp_active_flag=0;
  10426.         SSL_free(ssl_ftp_con);
  10427.         ssl_ftp_con = NULL;
  10428.     } else {
  10429.         ssl_ftp_active_flag = 1;
  10430.  
  10431.         if (!ssl_certsok_flag && !tls_is_krb5(1)) {
  10432.             char *subject = ssl_get_subject_name(ssl_ftp_con);
  10433.  
  10434.             if (!subject) {
  10435.                 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
  10436.                     debug(F110,"ssl_auth","[SSL - FAILED]",0);
  10437.                     return(ssl_ftp_active_flag = 0);
  10438.                 } else {
  10439.                     if (uq_ok("Warning: Server didn't provide a certificate\n",
  10440.                                "Continue? (Y/N)",3,NULL,0) <= 0) {
  10441.                         debug(F110, "ssl_auth","[SSL - FAILED]",0);
  10442.                         return(ssl_ftp_active_flag = 0);
  10443.                     }
  10444.                 }
  10445.             } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
  10446.                 debug(F110,"ssl_auth","[SSL - FAILED]",0);
  10447.                 return(ssl_ftp_active_flag = 0);
  10448.             }
  10449.         }
  10450.         debug(F110,"ssl_auth","[SSL - OK]",0);
  10451.         ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
  10452.     }
  10453.     if (ssl_debug_flag) {
  10454.         fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
  10455.         fflush(stderr);
  10456.     }
  10457.     return(ssl_ftp_active_flag);
  10458. }
  10459. #endif /* CK_SSL */
  10460.  
  10461. static sigtype
  10462. cmdcancel(sig) int sig; {
  10463. #ifdef OS2
  10464.     /* In Unix we "chain" to trap(), which prints this */
  10465.     printf("^C...\n");
  10466. #endif /* OS2 */
  10467.     debug(F100,"ftp cmdcancel caught SIGINT ","",0);
  10468.     fflush(stdout);
  10469.     secure_getc(0,1);            /* Initialize net input buffers */
  10470.     cancelfile++;
  10471.     cancelgroup++;
  10472.     mlsreset();
  10473. #ifndef OS2
  10474. #ifdef FTP_PROXY
  10475.     if (ptflag)                         /* proxy... */
  10476.       longjmp(ptcancel,1);
  10477. #endif /* FTP_PROXY */
  10478.     debug(F100,"ftp cmdcancel chain to trap()...","",0);
  10479.     trap(SIGINT);
  10480.     /* NOTREACHED */
  10481.     debug(F100,"ftp cmdcancel return from trap()...","",0);
  10482. #else
  10483.     debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
  10484.     PostCtrlCSem();
  10485. #endif /* OS2 */
  10486. }
  10487.  
  10488. static int
  10489. #ifdef CK_ANSIC
  10490. scommand(char * s)                      /* Was secure_command() */
  10491. #else
  10492. scommand(s) char * s;
  10493. #endif /* CK_ANSIC */
  10494. {
  10495.     int length = 0, len2;
  10496.     char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
  10497. #ifdef CK_SSL
  10498.     if (ssl_ftp_active_flag) {
  10499.         int error, rc;
  10500.         length = strlen(s) + 2;
  10501.         length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
  10502.         rc = SSL_write(ssl_ftp_con,out,length);
  10503.         error = SSL_get_error(ssl_ftp_con,rc);
  10504.         switch (error) {
  10505.           case SSL_ERROR_NONE:
  10506.             return(1);
  10507.           case SSL_ERROR_WANT_WRITE:
  10508.           case SSL_ERROR_WANT_READ:
  10509.           case SSL_ERROR_SYSCALL:
  10510. #ifdef NT
  10511.             {
  10512.                 int gle = GetLastError();
  10513.             }
  10514. #endif /* NT */
  10515.           case SSL_ERROR_WANT_X509_LOOKUP:
  10516.           case SSL_ERROR_SSL:
  10517.           case SSL_ERROR_ZERO_RETURN:
  10518.           default:
  10519.             lostpeer();
  10520.         }
  10521.         return(0);
  10522.     }
  10523. #endif /* CK_SSL */
  10524.  
  10525.     if (auth_type && ftp_cpl != FPL_CLR) {
  10526. #ifdef FTP_SRP
  10527.         if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
  10528.           if ((length = srp_encode(ftp_cpl == FPL_PRV,
  10529.                                    (CHAR *)s,
  10530.                                    (CHAR *)out,
  10531.                                    strlen(s))) < 0) {
  10532.               fprintf(stderr, "SRP failed to encode message\n");
  10533.               return(0);
  10534.           }
  10535. #endif /* FTP_SRP */
  10536. #ifdef FTP_KRB4
  10537.         if (ck_krb4_is_installed() &&
  10538.             (strcmp(auth_type, "KERBEROS_V4") == 0)) {
  10539.             if (ftp_cpl == FPL_PRV) {
  10540.                 length =
  10541.                   krb_mk_priv((CHAR *)s, (CHAR *)out,
  10542.                               strlen(s), ftp_sched,
  10543. #ifdef KRB524
  10544.                               ftp_cred.session,
  10545. #else /* KRB524 */
  10546.                               &ftp_cred.session,
  10547. #endif /* KRB524 */
  10548.                               &myctladdr, &hisctladdr);
  10549.             } else {
  10550.                 length =
  10551.                   krb_mk_safe((CHAR *)s,
  10552.                               (CHAR *)out,
  10553.                               strlen(s),
  10554. #ifdef KRB524
  10555.                               ftp_cred.session,
  10556. #else /* KRB524 */
  10557.                               &ftp_cred.session,
  10558. #endif /* KRB524 */
  10559.                               &myctladdr, &hisctladdr);
  10560.             }
  10561.             if (length == -1) {
  10562.                 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
  10563.                         ftp_cpl == FPL_PRV ? "priv" : "safe");
  10564.                 return(0);
  10565.             }
  10566.         }
  10567. #endif /* FTP_KRB4 */
  10568. #ifdef FTP_GSSAPI
  10569.         /* Scommand (based on level) */
  10570.         if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
  10571.             gss_buffer_desc in_buf, out_buf;
  10572.             OM_uint32 maj_stat, min_stat;
  10573.             int conf_state;
  10574.             in_buf.value = s;
  10575.             in_buf.length = strlen(s) + 1;
  10576.             maj_stat = gss_seal(&min_stat, gcontext,
  10577.                                 (ftp_cpl==FPL_PRV), /* private */
  10578.                                 GSS_C_QOP_DEFAULT,
  10579.                                 &in_buf, &conf_state,
  10580.                                 &out_buf);
  10581.             if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
  10582.                 user_gss_error(maj_stat, min_stat,
  10583.                                (ftp_cpl==FPL_PRV)?
  10584.                                "gss_seal ENC didn't complete":
  10585.                                "gss_seal MIC didn't complete");
  10586.             } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
  10587.                 fprintf(stderr, "GSSAPI didn't encrypt message");
  10588.             } else {
  10589.                 if (ftp_deb)
  10590.                   fprintf(stderr, "sealed (%s) %d bytes\n",
  10591.                           ftp_cpl==FPL_PRV?"ENC":"MIC",
  10592.                           out_buf.length);
  10593.                 memcpy(out, out_buf.value,
  10594.                        length=out_buf.length);
  10595.                 gss_release_buffer(&min_stat, &out_buf);
  10596.             }
  10597.         }
  10598. #endif /* FTP_GSSAPI */
  10599.         /* Other auth types go here ... */
  10600.  
  10601.         len2 = FTP_BUFSIZ;
  10602.         if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
  10603.                                    length, &len2, RADIX_ENCODE))
  10604.             ) {
  10605.             fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
  10606.                     radix_error(kerror));
  10607.             return(0);
  10608.         }
  10609.         if (ftp_deb)
  10610.           fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
  10611.         len2 = ckmakmsg(out,
  10612.             FTP_BUFSIZ,
  10613.             ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
  10614.                         in,
  10615.             "\r\n",
  10616.             NULL
  10617.             );
  10618.         send(csocket,(SENDARG2TYPE)out,len2,0);
  10619.     } else {
  10620.         char out[FTP_BUFSIZ];
  10621.         int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
  10622.         send(csocket,(SENDARG2TYPE)out,len,0);
  10623.     }
  10624.     return(1);
  10625. }
  10626.  
  10627. static int
  10628. mygetc() {
  10629.     static char inbuf[4096];
  10630.     static int bp = 0, ep = 0;
  10631.     int rc;
  10632.  
  10633.     if (bp == ep) {
  10634.         bp = ep = 0;
  10635. #ifdef CK_SSL
  10636.         if (ssl_ftp_active_flag) {
  10637.             int error;
  10638.             rc = SSL_read(ssl_ftp_con,inbuf,4096);
  10639.             error = SSL_get_error(ssl_ftp_con,rc);
  10640.             switch (error) {
  10641.               case SSL_ERROR_NONE:
  10642.                 break;
  10643.               case SSL_ERROR_WANT_WRITE:
  10644.               case SSL_ERROR_WANT_READ:
  10645.                 return(0);
  10646.               case SSL_ERROR_SYSCALL:
  10647.                 if (rc == 0) {          /* EOF */
  10648.                     break;
  10649.                 } else {
  10650. #ifdef NT
  10651.                     int gle = GetLastError();
  10652. #endif /* NT */
  10653.                     break;
  10654.                 }
  10655.               case SSL_ERROR_WANT_X509_LOOKUP:
  10656.               case SSL_ERROR_SSL:
  10657.               case SSL_ERROR_ZERO_RETURN:
  10658.               default:
  10659.                 break;
  10660.             }
  10661.         } else
  10662. #endif /* CK_SSL */
  10663.           rc = recv(csocket,(char *)inbuf,4096,0);
  10664.         if (rc <= 0)
  10665.           return(EOF);
  10666.         ep = rc;
  10667.     }
  10668.     return(inbuf[bp++]);
  10669. }
  10670.  
  10671. /*  x l a t e c  --  Translate a character  */
  10672. /*
  10673.     Call with:
  10674.       fc    = Function code: 0 = translate, 1 = initialize.
  10675.       c     = Character (as int).
  10676.       incs  = Index of charset to translate from.
  10677.       outcs = Index of charset to translate to.
  10678.  
  10679.     Returns:
  10680.       0: OK
  10681.      -1: Error
  10682. */
  10683. static int
  10684. xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
  10685. #ifdef NOCSETS
  10686.     return(c);
  10687. #else
  10688.     static char buf[128];
  10689.     static int cx;
  10690.     int c0, c1;
  10691.  
  10692.     if (fc == 1) {                      /* Initialize */
  10693.         cx = 0;                         /* Catch-up buffer write index */
  10694.         xgnbp = buf;                    /* Catch-up buffer read pointer */
  10695.         buf[0] = NUL;                   /* Buffer is empty */
  10696.         return(0);
  10697.     }
  10698.     if (cx >= 127) {                    /* Catch-up buffer full */
  10699.         debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
  10700.         printf("?Translation buffer overflow\n");
  10701.         return(-1);
  10702.     }
  10703.     /* Add char to buffer. */
  10704.     /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
  10705.  
  10706.     debug(F000,"xlatec buf",ckitoa(cx),c);
  10707.     buf[cx++] = c;
  10708.     buf[cx] = NUL;
  10709.  
  10710.     while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
  10711.         if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0)    /* (NULL was xprintc) */
  10712.           return(-1);
  10713.     }
  10714.     /* If we're caught up, reinitialize the buffer */
  10715.     return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
  10716. #endif /* NOCSETS */
  10717. }
  10718.  
  10719.  
  10720. /*  p a r s e f e a t  */
  10721.  
  10722. /* Note: for convenience we align keyword values with table indices */
  10723. /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
  10724.  
  10725. static struct keytab feattab[] = {
  10726.     { "$$$$", 0,        0 },        /* Dummy for sfttab[0] */
  10727.     { "AUTH", SFT_AUTH, 0 },
  10728.     { "LANG", SFT_LANG, 0 },
  10729.     { "MDTM", SFT_MDTM, 0 },
  10730.     { "MLST", SFT_MLST, 0 },
  10731.     { "PBSZ", SFT_PBSZ, 0 },
  10732.     { "PROT", SFT_PROT, 0 },
  10733.     { "REST", SFT_REST, 0 },
  10734.     { "SIZE", SFT_SIZE, 0 },
  10735.     { "TVFS", SFT_TVFS, 0 },
  10736.     { "UTF8", SFT_UTF8, 0 }
  10737. };
  10738. static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
  10739.  
  10740. #define FACT_CSET  1
  10741. #define FACT_CREA  2
  10742. #define FACT_LANG  3
  10743. #define FACT_MTYP  4
  10744. #define FACT_MDTM  5
  10745. #define FACT_PERM  6
  10746. #define FACT_SIZE  7
  10747. #define FACT_TYPE  8
  10748. #define FACT_UNIQ  9
  10749.  
  10750. static struct keytab facttab[] = {
  10751.     { "CHARSET",    FACT_CSET, 0 },
  10752.     { "CREATE",     FACT_CREA, 0 },
  10753.     { "LANG",       FACT_LANG, 0 },
  10754.     { "MEDIA-TYPE", FACT_MTYP, 0 },
  10755.     { "MODIFY",     FACT_MDTM, 0 },
  10756.     { "PERM",       FACT_PERM, 0 },
  10757.     { "SIZE",       FACT_SIZE, 0 },
  10758.     { "TYPE",       FACT_TYPE, 0 },
  10759.     { "UNIQUE",     FACT_UNIQ, 0 }
  10760. };
  10761. static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
  10762.  
  10763. static struct keytab ftyptab[] = {
  10764.     { "CDIR", FTYP_CDIR, 0 },
  10765.     { "DIR",  FTYP_DIR,  0 },
  10766.     { "FILE", FTYP_FILE, 0 },
  10767.     { "PDIR", FTYP_PDIR, 0 }
  10768. };
  10769. static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
  10770.  
  10771. static VOID
  10772. parsefeat(s) char * s; {        /* Parse a FEATURE response */
  10773.     char kwbuf[8];
  10774.     int i, x;
  10775.     if (!s) return;
  10776.     if (!*s) return;
  10777.     while (*s < '!')
  10778.       s++;
  10779.     for (i = 0; i < 4; i++) {
  10780.     if (s[i] < '!')
  10781.       break;
  10782.     kwbuf[i] = s[i];
  10783.     }
  10784.     if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
  10785.       return;
  10786.     kwbuf[i] = NUL;
  10787.     /* xlookup requires a full (but case independent) match */
  10788.     i = xlookup(feattab,kwbuf,nfeattab,&x);
  10789.     debug(F111,"ftp parsefeat",s,i);
  10790.     if (i < 0 || i > 15)
  10791.       return;
  10792.  
  10793.     switch (i) {
  10794.       case SFT_MDTM:            /* Controlled by ENABLE/DISABLE */
  10795.     sfttab[i] = mdtmok;
  10796.     if (mdtmok) sfttab[0]++;
  10797.     break;
  10798.       case SFT_MLST:            /* ditto */
  10799.     sfttab[i] = mlstok;
  10800.     if (mlstok) sfttab[0]++;
  10801.     break;
  10802.       case SFT_SIZE:            /* ditto */
  10803.     sfttab[i] = sizeok;
  10804.     if (sizeok) sfttab[0]++;
  10805.     break;
  10806.       case SFT_AUTH:            /* ditto */
  10807.     sfttab[i] = ftp_aut;
  10808.     if (ftp_aut) sfttab[0]++;
  10809.     break;
  10810.       default:                /* Others */
  10811.     sfttab[0]++;
  10812.     sfttab[i]++;
  10813.     }
  10814. }
  10815.  
  10816. static char *
  10817. parsefacts(s) char * s; {        /* Parse MLS[DT] File Facts */
  10818.     char * p;
  10819.     int i, j, x;
  10820.     if (!s) return(NULL);
  10821.     if (!*s) return(NULL);
  10822.  
  10823.     /* Maybe we should make a copy of s so we can poke it... */
  10824.  
  10825.     while ((p = ckstrchr(s,'='))) {
  10826.     *p = NUL;            /* s points to fact */
  10827.     i = xlookup(facttab,s,nfacttab,&x); 
  10828.     debug(F111,"ftp parsefact fact",s,i);
  10829.     *p = '=';
  10830.     s = p+1;            /* Now s points to arg */
  10831.     p = ckstrchr(s,';');
  10832.         if (!p)
  10833.       p = ckstrchr(s,SP);
  10834.     if (!p) {
  10835.         debug(F110,"ftp parsefact end-of-val search fail",s,0);
  10836.         break;
  10837.     }
  10838.     *p = NUL;
  10839.     debug(F110,"ftp parsefact valu",s,0);
  10840.     switch (i) {
  10841.       case FACT_CSET:        /* Ignore these for now */
  10842.       case FACT_CREA:
  10843.       case FACT_LANG:
  10844.       case FACT_PERM:
  10845.       case FACT_MTYP:
  10846.       case FACT_UNIQ:
  10847.         break;
  10848.       case FACT_MDTM:        /* Modtime */
  10849.         makestr(&havemdtm,s);
  10850.         debug(F110,"ftp parsefact mdtm",havemdtm,0);
  10851.         break;
  10852.       case FACT_SIZE:        /* Size */
  10853.         havesize = ckatofs(s);
  10854.         debug(F101,"ftp parsefact size","",havesize);
  10855.         break;
  10856.       case FACT_TYPE:        /* Type */
  10857.         j = xlookup(ftyptab,s,nftyptab,NULL);
  10858.         debug(F111,"ftp parsefact type",s,j);
  10859.         havetype = (j < 1) ? 0 : j;
  10860.         break;
  10861.     }
  10862.     *p = ';';
  10863.     s = p+1;            /* s points next fact or name */
  10864.     }
  10865.     while (*s == SP)            /* Skip past spaces. */
  10866.       s++;
  10867.     if (!*s)                /* Make sure we still have a name */
  10868.       s = NULL;
  10869.     debug(F110,"ftp parsefact name",s,0);
  10870.     return(s);
  10871. }
  10872.  
  10873. /*  g e t r e p l y  --  (to an FTP command sent to server)  */
  10874.  
  10875. /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
  10876.  
  10877. static int
  10878. getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
  10879.     /* lcs, rcs, vbm parameters as in ftpcmd() */
  10880.     register int i, c, n;
  10881.     register int dig;
  10882.     register char *cp;
  10883.     int xlate = 0;
  10884.     int count = 0;
  10885.     int auth = 0;
  10886.     int originalcode = 0, continuation = 0;
  10887.     sig_t oldintr;
  10888.     int pflag = 0;
  10889.     char *pt = pasv;
  10890.     char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
  10891.     int safe = 0;
  10892.     int xquiet = 0;
  10893.  
  10894.     auth = (fc == GRF_AUTH);
  10895.  
  10896. #ifndef NOCSETS
  10897.     debug(F101,"ftp getreply lcs","",lcs);
  10898.     debug(F101,"ftp getreply rcs","",rcs);
  10899.     if (lcs > -1 && rcs > -1 && lcs != rcs) {
  10900.         xlate = 1;
  10901.         initxlate(rcs,lcs);
  10902.         xlatec(1,0,rcs,lcs);
  10903.     }
  10904. #endif /* NOCSETS */
  10905.     debug(F101,"ftp getreply fc","",fc);
  10906.  
  10907.     if (quiet)
  10908.       xquiet = 1;
  10909.     if (vbm == 9) {
  10910.         xquiet = 1;
  10911.         vbm = 0;
  10912.     }
  10913.     if (ftp_deb)                        /* DEBUG */
  10914.       vbm = 1;
  10915.     else if (quiet || dpyactive)        /* QUIET or File Transfer Active */
  10916.       vbm = 0;
  10917.     else if (vbm < 0)                   /* VERBOSE */
  10918.       vbm = ftp_vbm;
  10919.  
  10920.     ibuf[0] = '\0';
  10921.     if (reply_parse)
  10922.       reply_ptr = reply_buf;
  10923.     havesigint = 0;
  10924.     oldintr = signal(SIGINT, cmdcancel);
  10925.     for (count = 0;; count++) {
  10926.         obuf[0] = '\0';
  10927.         dig = n = ftpcode = i = 0;
  10928.         cp = ftp_reply_str;
  10929.         while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
  10930.             if (c == IAC) {             /* Handle telnet commands */
  10931.                 switch (c = mygetc()) {
  10932.                   case WILL:
  10933.                   case WONT:
  10934.                     c = mygetc();
  10935.                     obuf[0] = IAC;
  10936.                     obuf[1] = DONT;
  10937.                     obuf[2] = c;
  10938.                     obuf[3] = NUL;
  10939. #ifdef CK_SSL
  10940.                     if (ssl_ftp_active_flag) {
  10941.                         int error, rc;
  10942.                         rc = SSL_write(ssl_ftp_con,obuf,3);
  10943.                         error = SSL_get_error(ssl_ftp_con,rc);
  10944.                         switch (error) {
  10945.                           case SSL_ERROR_NONE:
  10946.                             break;
  10947.                           case SSL_ERROR_WANT_WRITE:
  10948.                           case SSL_ERROR_WANT_READ:
  10949.                             return(0);
  10950.                           case SSL_ERROR_SYSCALL:
  10951.                             if (rc == 0) { /* EOF */
  10952.                                 break;
  10953.                             } else {
  10954. #ifdef NT
  10955.                                 int gle = GetLastError();
  10956. #endif /* NT */
  10957.                                 break;
  10958.                             }
  10959.                           case SSL_ERROR_WANT_X509_LOOKUP:
  10960.                           case SSL_ERROR_SSL:
  10961.                           case SSL_ERROR_ZERO_RETURN:
  10962.                           default:
  10963.                             break;
  10964.                         }
  10965.                     } else
  10966. #endif /* CK_SSL */
  10967.                       send(csocket,(SENDARG2TYPE)obuf,3,0);
  10968.                     break;
  10969.                   case DO:
  10970.                   case DONT:
  10971.                     c = mygetc();
  10972.                     obuf[0] = IAC;
  10973.                     obuf[1] = WONT;
  10974.                     obuf[2] = c;
  10975.                     obuf[3] = NUL;
  10976. #ifdef CK_SSL
  10977.                     if (ssl_ftp_active_flag) {
  10978.                         int error, rc;
  10979.                         rc = SSL_write(ssl_ftp_con,obuf,3);
  10980.                         error = SSL_get_error(ssl_ftp_con,rc);
  10981.                         switch (error) {
  10982.                           case SSL_ERROR_NONE:
  10983.                             break;
  10984.                           case SSL_ERROR_WANT_WRITE:
  10985.                           case SSL_ERROR_WANT_READ:
  10986.                               signal(SIGINT,oldintr);
  10987.                               return(0);
  10988.                           case SSL_ERROR_SYSCALL:
  10989.                             if (rc == 0) { /* EOF */
  10990.                                 break;
  10991.                             } else {
  10992. #ifdef NT
  10993.                                 int gle = GetLastError();
  10994. #endif /* NT */
  10995.                                 break;
  10996.                             }
  10997.                           case SSL_ERROR_WANT_X509_LOOKUP:
  10998.                           case SSL_ERROR_SSL:
  10999.                           case SSL_ERROR_ZERO_RETURN:
  11000.                           default:
  11001.                             break;
  11002.                         }
  11003.                     } else
  11004. #endif /* CK_SSL */
  11005.                       send(csocket,(SENDARG2TYPE)obuf,3,0);
  11006.                     break;
  11007.                   default:
  11008.                     break;
  11009.                 }
  11010.                 continue;
  11011.             }
  11012.             dig++;
  11013.             if (c == EOF) {
  11014.                 if (expecteof) {
  11015.                     signal(SIGINT,oldintr);
  11016.                     ftpcode = 221;
  11017.                     debug(F101,"ftp getreply EOF","",ftpcode);
  11018.                     return(0);
  11019.                 }
  11020.                 lostpeer();
  11021.                 if (!xquiet) {
  11022.                     if (ftp_deb)
  11023.                       printf("421 ");
  11024.                     printf(
  11025.                       "Service not available, connection closed by server\n");
  11026.                     fflush(stdout);
  11027.                 }
  11028.                 signal(SIGINT,oldintr);
  11029.                 ftpcode = 421;
  11030.                 debug(F101,"ftp getreply EOF","",ftpcode);
  11031.                 return(4);
  11032.             }
  11033.             if (n == 0) {        /* First digit */
  11034.         n = c;            /* Save it */
  11035.         }
  11036.             if (auth_type &&
  11037. #ifdef CK_SSL
  11038.                 !ssl_ftp_active_flag &&
  11039. #endif /* CK_SSL */
  11040.                 !ibuf[0] && (n == '6' || continuation)) {
  11041.                 if (c != '\r' && dig > 4)
  11042.                   obuf[i++] = c;
  11043.             } else {
  11044.                 if (auth_type &&
  11045. #ifdef CK_SSL
  11046.                     !ssl_ftp_active_flag &&
  11047. #endif /* CK_SSL */
  11048.                     !ibuf[0] && dig == 1 && vbm)
  11049.                   printf("Unauthenticated reply received from server:\n");
  11050.                 if (reply_parse) {
  11051.                     *reply_ptr++ = c;
  11052.                     *reply_ptr = NUL;
  11053.                 }
  11054.                 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
  11055.                     ftp_cmdlin < 2) {
  11056.                     if ((c != '\r') &&
  11057.                         (ftp_deb || ((vbm || (!auth && n == '5')) &&
  11058.                         (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
  11059.                         )))))
  11060.                     {
  11061. #ifdef FTP_PROXY
  11062.                         if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
  11063.                           printf("%s:",ftp_host);
  11064. #endif /* FTP_PROXY */
  11065.  
  11066.                         if (!xquiet) {
  11067. #ifdef NOCSETS
  11068.                             printf("%c",c);
  11069. #else
  11070.                             if (xlate) {
  11071.                                 xlatec(0,c,rcs,lcs);
  11072.                             } else {
  11073.                                 printf("%c",c);
  11074.                             }
  11075. #endif /* NOCSETS */
  11076.                         }
  11077.                     }
  11078.                 }
  11079.             }
  11080.             if (auth_type &&
  11081. #ifdef CK_SSL
  11082.                 !ssl_ftp_active_flag &&
  11083. #endif /* CK_SSL */
  11084.                 !ibuf[0] && n != '6')
  11085.               continue;
  11086.             if (dig < 4 && isdigit(c))
  11087.               ftpcode = ftpcode * 10 + (c - '0');
  11088.             if (!pflag && ftpcode == 227)
  11089.               pflag = 1;
  11090.             if (dig > 4 && pflag == 1 && isdigit(c))
  11091.               pflag = 2;
  11092.             if (pflag == 2) {
  11093.                 if (c != '\r' && c != ')')
  11094.                   *pt++ = c;
  11095.                 else {
  11096.                     *pt = '\0';
  11097.                     pflag = 3;
  11098.                 }
  11099.             }
  11100.             if (dig == 4 && c == '-' && n != '6') {
  11101.                 if (continuation)
  11102.                   ftpcode = 0;
  11103.                 continuation++;
  11104.             }
  11105.             if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
  11106.                 *cp++ = c;
  11107.                 *cp = NUL;
  11108.             }
  11109.         }
  11110.         if (deblog ||
  11111. #ifdef COMMENT
  11112. /*
  11113.   Sometimes we need to print the server reply.  printlines is nonzero for any
  11114.   command where the results are sent back on the control connection rather
  11115.   than the data connection, e.g. STAT.  In the TOPS-20 case, each file line
  11116.   has ftpcode 213.  But if you do this with a UNIX server, it sends "213-Start
  11117.   STAT", <line with ftpcode == 0>, "213-End" or somesuch.  So when printlines
  11118.   is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
  11119.   lines from UNIX.  Further experimentation needed with other servers.  Of
  11120.   course RFC959 is mute as to the format of the server reply.
  11121.  
  11122.   'printlines' is also true for PWD and BYE.
  11123. */
  11124.         (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
  11125. #else
  11126. /* No, we can't be that clever -- it breaks other things like RPWD... */
  11127.             (printlines &&
  11128.              (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
  11129. #endif /* COMMENT */
  11130.             ) {
  11131.             char * q = cp;
  11132.             char *r = ftp_reply_str;
  11133.             *q-- = NUL;                 /* NUL-terminate */
  11134.             while (*q < '!' && q > r)   /* Strip CR, etc */
  11135.               *q-- = NUL;
  11136.             if (!ftp_deb && printlines) { /* If printing */
  11137.                 if (ftpcode != 0)       /* strip ftpcode if any */
  11138.                   r += 4;
  11139. #ifdef NOCSETS
  11140.                 printf("%s\n",r);       /* and print */
  11141. #else
  11142.                 if (!xlate) {
  11143.                     printf("%s\n",r);
  11144.                 } else {        /* Translating */
  11145.                     xgnbp = r;        /* Set up strgetc() */
  11146.                     while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
  11147.                         if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) {    /* (xprintc) */
  11148.                             signal(SIGINT,oldintr);
  11149.                             return(-1);
  11150.                         }
  11151.                     }
  11152.                     printf("\n");
  11153.                 }
  11154. #endif /* NOCSETS */
  11155.             }
  11156.         }
  11157.     debug(F110,"FTP RCVD ",ftp_reply_str,0);
  11158.  
  11159.     if (fc == GRF_FEAT) {        /* Parsing FEAT command response? */
  11160.         if (count == 0 && n == '2') {
  11161.         int i;            /* (Re)-init server FEATure table */
  11162.         debug(F100,"ftp getreply clearing feature table","",0);
  11163.         for (i = 0; i < 16; i++)
  11164.           sfttab[i] = 0;
  11165.         } else {
  11166.         parsefeat((char *)ftp_reply_str);
  11167.         }
  11168.     }
  11169.         if (auth_type &&
  11170. #ifdef CK_SSL
  11171.             !ssl_ftp_active_flag &&
  11172. #endif /* CK_SSL */
  11173.              !ibuf[0] && n != '6') {
  11174.             signal(SIGINT,oldintr);
  11175.             return(getreply(expecteof,lcs,rcs,vbm,auth));
  11176.         }
  11177.         ibuf[0] = obuf[i] = '\0';
  11178.         if (ftpcode && n == '6')
  11179.           if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
  11180.               printf("Unknown reply: %d %s\n", ftpcode, obuf);
  11181.               n = '5';
  11182.           } else safe = (ftpcode == 631);
  11183.         if (obuf[0]                     /* if there is a string to decode */
  11184. #ifdef CK_SSL
  11185.             && !ssl_ftp_active_flag     /* and not SSL/TLS */
  11186. #endif /* CK_SSL */
  11187.             ) {
  11188.             if (!auth_type) {
  11189.                 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
  11190.                 n = '5';
  11191.             }
  11192. #ifndef CK_ENCRYPTION
  11193.             else if (ftpcode == 632) {
  11194.                 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
  11195.                 n = '5';
  11196.             }
  11197. #endif /* CK_ENCRYPTION */
  11198. #ifdef NOCONFIDENTIAL
  11199.             else if (ftpcode == 633) {
  11200.                 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
  11201.                 n = '5';
  11202.             }
  11203. #endif /* NOCONFIDENTIAL */
  11204.             else {
  11205.                 int len = FTP_BUFSIZ;
  11206.                 if ((kerror = radix_encode((CHAR *)obuf,
  11207.                                            (CHAR *)ibuf,
  11208.                                            0,
  11209.                                            &len,
  11210.                                            RADIX_DECODE))
  11211.                     ) {
  11212.                     printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
  11213.                            ftpcode, radix_error(kerror), obuf);
  11214.                     n = '5';
  11215.                 }
  11216. #ifdef FTP_SRP
  11217.                 else if (strcmp(auth_type, "SRP") == 0) {
  11218.                     int outlen;
  11219.                     outlen = srp_decode(!safe, (CHAR *)ibuf,
  11220.                                         (CHAR *) ibuf, len);
  11221.                     if (outlen < 0) {
  11222.                         printf("Warning: %d reply %s!\n",
  11223.                                ftpcode, safe ? "modified" : "garbled");
  11224.                         n = '5';
  11225.                     } else {
  11226.                         ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
  11227.                         if (ftp_deb)
  11228.                           printf("%c:", safe ? 'S' : 'P');
  11229.                         continue;
  11230.                     }
  11231.                 }
  11232. #endif /* FTP_SRP */
  11233. #ifdef FTP_KRB4
  11234.                 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
  11235.                     if (safe) {
  11236.                         kerror = krb_rd_safe((CHAR *)ibuf, len,
  11237. #ifdef KRB524
  11238.                                              ftp_cred.session,
  11239. #else /* KRB524 */
  11240.                                              &ftp_cred.session,
  11241. #endif /* KRB524 */
  11242.                                              &hisctladdr,
  11243.                                              &myctladdr,
  11244.                                              &ftp_msg_data
  11245.                                              );
  11246.                     } else {
  11247.                         kerror = krb_rd_priv((CHAR *)ibuf, len,
  11248.                                              ftp_sched,
  11249. #ifdef KRB524
  11250.                                              ftp_cred.session,
  11251. #else /* KRB524 */
  11252.                                              &ftp_cred.session,
  11253. #endif /* KRB524 */
  11254.                                              &hisctladdr,
  11255.                                              &myctladdr,
  11256.                                              &ftp_msg_data
  11257.                                              );
  11258.                     }
  11259.                     if (kerror != KSUCCESS) {
  11260.                         printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
  11261.                                safe ? "modified" : "garbled",
  11262.                                safe ? "safe" : "priv",
  11263.                                krb_get_err_text(kerror));
  11264.                         n = '5';
  11265.                     } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
  11266.                         kerror = KFAILURE;
  11267.                         n = '5';
  11268.                         printf("reply data too large for buffer\n");
  11269.                     } else {
  11270.                         if (ftp_deb)
  11271.                           printf("%c:", safe ? 'S' : 'P');
  11272.                         memcpy(ibuf,ftp_msg_data.app_data,
  11273.                                ftp_msg_data.app_length);
  11274.                         ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
  11275.                                   FTP_BUFSIZ - ftp_msg_data.app_length);
  11276.                         continue;
  11277.                     }
  11278.                 }
  11279. #endif /* FTP_KRB4 */
  11280. #ifdef FTP_GSSAPI
  11281.                 else if (strcmp(auth_type, "GSSAPI") == 0) {
  11282.                     gss_buffer_desc xmit_buf, msg_buf;
  11283.                     OM_uint32 maj_stat, min_stat;
  11284.                     int conf_state;
  11285.                     xmit_buf.value = ibuf;
  11286.                     xmit_buf.length = len;
  11287.                     /* decrypt/verify the message */
  11288.                     conf_state = safe;
  11289.                     maj_stat = gss_unseal(&min_stat, gcontext,
  11290.                                           &xmit_buf, &msg_buf,
  11291.                                           &conf_state, NULL);
  11292.                     if (maj_stat != GSS_S_COMPLETE) {
  11293.                         user_gss_error(maj_stat, min_stat,
  11294.                                        "failed unsealing reply");
  11295.                         n = '5';
  11296.                     } else {
  11297.                         memcpy(ibuf, msg_buf.value, msg_buf.length);
  11298.                         ckstrncpy(&ibuf[msg_buf.length], "\r\n",
  11299.                                   FTP_BUFSIZ-msg_buf.length);
  11300.                         gss_release_buffer(&min_stat,&msg_buf);
  11301.                         if (ftp_deb)
  11302.                           printf("%c:", safe ? 'S' : 'P');
  11303.                         continue;
  11304.                     }
  11305.                 }
  11306. #endif /* FTP_GSSAPI */
  11307.                 /* Other auth types go here... */
  11308.             }
  11309.         } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
  11310.                    !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
  11311. #ifdef NOCSETS
  11312.             printf("%c",c);
  11313. #else
  11314.             if (xlate) {
  11315.                 xlatec(0,c,rcs,lcs);
  11316.             } else {
  11317.                 printf("%c",c);
  11318.             }
  11319. #endif /* NOCSETS */
  11320.             fflush (stdout);
  11321.         }
  11322.         if (continuation && ftpcode != originalcode) {
  11323.             if (originalcode == 0)
  11324.               originalcode = ftpcode;
  11325.             continue;
  11326.         }
  11327.         *cp = '\0';
  11328.         if (n != '1')
  11329.           cpend = 0;
  11330.         signal(SIGINT,oldintr);
  11331.         if (ftpcode == 421 || originalcode == 421) {
  11332.         lostpeer();
  11333.         if (!xquiet && !ftp_deb)
  11334.           printf("%s\n",reply_buf);
  11335.         }
  11336.         if ((cancelfile != 0) &&
  11337. #ifndef ULTRIX3
  11338.             /* Ultrix 3.0 cc objects violently to this clause */
  11339.             (oldintr != cmdcancel) &&
  11340. #endif /* ULTRIX3 */
  11341.             (oldintr != SIG_IGN)) {
  11342.             if (oldintr)
  11343.               (*oldintr)(SIGINT);
  11344.         }
  11345.         if (reply_parse) {
  11346.             *reply_ptr = '\0';
  11347.             if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
  11348.                 reply_parse = reply_ptr + strlen(reply_parse);
  11349.                 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
  11350.                   *reply_ptr = '\0';
  11351.             } else
  11352.               reply_parse = reply_ptr;
  11353.         }
  11354.         while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
  11355.           *cp-- = NUL;
  11356.         debug(F111,"ftp getreply",ftp_reply_str,n - '0');
  11357.         return(n - '0');
  11358.     } /* for (;;) */
  11359. }
  11360.  
  11361. #ifdef BSDSELECT
  11362. static int
  11363. #ifdef CK_ANSIC
  11364. empty(fd_set * mask, int sec)
  11365. #else
  11366. empty(mask, sec) fd_set * mask; int sec;
  11367. #endif /* CK_ANSIC */
  11368. {
  11369.     struct timeval t;
  11370.     t.tv_sec = (long) sec;
  11371.     t.tv_usec = 0L;
  11372.     debug(F100,"ftp empty calling select...","",0);
  11373. #ifdef INTSELECT
  11374.     x = select(32, (int *)mask, NULL, NULL, &t);
  11375. #else
  11376.     x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
  11377. #endif /* INTSELECT */
  11378.     debug(F101,"ftp empty select","",x);
  11379.     return(x);
  11380. }
  11381. #else /* BSDSELECT */
  11382. #ifdef IBMSELECT
  11383. static int
  11384. empty(mask, cnt, sec) int * mask, sec;
  11385.                       int   cnt;
  11386. {
  11387.     return(select(mask,cnt,0,0,sec*1000));
  11388. }
  11389. #endif /* IBMSELECT */
  11390. #endif /* BSDSELECT */
  11391.  
  11392. static sigtype
  11393. cancelsend(sig) int sig; {
  11394.     havesigint++;
  11395.     cancelgroup++;
  11396.     cancelfile = 0;
  11397.     printf(" Canceled...\n");
  11398.     secure_getc(0,1);            /* Initialize net input buffers */
  11399.     debug(F100,"ftp cancelsend caught SIGINT ","",0);
  11400.     fflush(stdout);
  11401. #ifndef OS2
  11402.     longjmp(sendcancel, 1);
  11403. #else
  11404.     PostCtrlCSem();
  11405. #endif /* OS2 */
  11406. }
  11407.  
  11408. static VOID
  11409. #ifdef CK_ANSIC
  11410. secure_error(char *fmt, ...)
  11411. #else
  11412. /* VARARGS1 */
  11413. secure_error(fmt, p1, p2, p3, p4, p5)
  11414.    char *fmt; int p1, p2, p3, p4, p5;
  11415. #endif /* CK_ANSIC */
  11416. {
  11417. #ifdef CK_ANSIC
  11418.     va_list ap;
  11419.  
  11420.     va_start(ap, fmt);
  11421.     vfprintf(stderr, fmt, ap);
  11422.     va_end(ap);
  11423. #else
  11424.     fprintf(stderr, fmt, p1, p2, p3, p4, p5);
  11425. #endif
  11426.     fprintf(stderr, "\n");
  11427. }
  11428.  
  11429. /*
  11430.  * Internal form of settype; changes current type in use with server
  11431.  * without changing our notion of the type for data transfers.
  11432.  * Used to change to and from ascii for listings.
  11433.  */
  11434. static VOID
  11435. changetype(newtype, show) int newtype, show; {
  11436.     int rc;
  11437.     char * s;
  11438.  
  11439.     if ((newtype == curtype) && typesent++)
  11440.       return;
  11441.     switch (newtype) {
  11442.       case FTT_ASC:
  11443.         s = "A";
  11444.         break;
  11445.       case FTT_BIN:
  11446.         s = "I";
  11447.         break;
  11448.       case FTT_TEN:
  11449.         s = "L 8";
  11450.         break;
  11451.       default:
  11452.         s = "I";
  11453.         break;
  11454.     }
  11455.     rc = ftpcmd("TYPE",s,-1,-1,show);
  11456.     if (rc == REPLY_COMPLETE)
  11457.       curtype = newtype;
  11458. }
  11459.  
  11460. /* PUT a file.  Returns -1 on error, 0 on success, 1 if file skipped */
  11461.  
  11462. static VOID
  11463. #ifdef CK_ANSIC
  11464. doftpsend(void * threadinfo)
  11465. #else
  11466. doftpsend(threadinfo) VOID * threadinfo;
  11467. #endif
  11468. {
  11469. #ifdef NTSIG
  11470.     if (threadinfo) {                   /* Thread local storage... */
  11471.         TlsSetValue(TlsIndex,threadinfo);
  11472.         debug(F100, "doftpsend called with threadinfo block","", 0);
  11473.     } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
  11474. #endif /* NTSIG */
  11475. #ifdef CK_LOGIN
  11476. #ifdef IKSD
  11477. #ifdef NT
  11478.     if (inserver)
  11479.       setntcreds();
  11480. #endif /* NT */
  11481. #endif /* IKSD */
  11482. #endif /* CK_LOGIN */
  11483.  
  11484.     if (initconn()) {
  11485. #ifndef NOHTTP
  11486.         int y = -1;
  11487.         /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
  11488.  
  11489.        /*  If the connection failed and we are using an HTTP Proxy
  11490.         *  and the reason for the failure was an authentication
  11491.         *  error, then we need to give the user to ability to
  11492.         *  enter a username and password, just like a browser.
  11493.         *
  11494.         *  I tried to do all of this within the netopen() call
  11495.         *  but it is much too much work.
  11496.         */
  11497.         while (y != 0 && tcp_http_proxy != NULL ) {
  11498.  
  11499.             if (tcp_http_proxy_errno == 401 ||
  11500.                  tcp_http_proxy_errno == 407 ) {
  11501.                 char uid[UIDBUFLEN];
  11502.                 char pwd[PWDSIZ];
  11503.                 struct txtbox tb[2];
  11504.                 int ok;
  11505.  
  11506.                 tb[0].t_buf = uid;
  11507.                 tb[0].t_len = UIDBUFLEN;
  11508.                 tb[0].t_lbl = "Proxy Userid: ";
  11509.                 tb[0].t_dflt = NULL;
  11510.                 tb[0].t_echo = 1;
  11511.                 tb[1].t_buf = pwd;
  11512.                 tb[1].t_len = 256;
  11513.                 tb[1].t_lbl = "Proxy Passphrase: ";
  11514.                 tb[1].t_dflt = NULL;
  11515.                 tb[1].t_echo = 2;
  11516.  
  11517.                 ok = uq_mtxt("Proxy Server Authentication Required\n",
  11518.                               NULL, 2, tb);
  11519.                 if (ok && uid[0]) {
  11520.                     char * proxy_user, * proxy_pwd;
  11521.  
  11522.                     proxy_user = tcp_http_proxy_user;
  11523.                     proxy_pwd  = tcp_http_proxy_pwd;
  11524.  
  11525.                     tcp_http_proxy_user = uid;
  11526.                     tcp_http_proxy_pwd = pwd;
  11527.  
  11528.                     y = initconn();
  11529.  
  11530.                     debug(F101,"doftpsend","initconn",y);
  11531.                     memset(pwd,0,PWDSIZ);
  11532.                     tcp_http_proxy_user = proxy_user;
  11533.                     tcp_http_proxy_pwd = proxy_pwd;
  11534.                 } else
  11535.                     break;
  11536.             } else
  11537.                 break;
  11538.         }
  11539.  
  11540.         if ( y != 0 ) {
  11541. #endif /* NOHTTP */
  11542.             signal(SIGINT, ftpsnd.oldintr);
  11543. #ifdef SIGPIPE
  11544.             if (ftpsnd.oldintp)
  11545.               signal(SIGPIPE, ftpsnd.oldintp);
  11546. #endif /* SIGPIPE */
  11547.             ftpcode = -1;
  11548.             zclose(ZIFILE);
  11549.             ftpsndret = -1;
  11550. #ifdef NTSIG
  11551.             ckThreadEnd(threadinfo);
  11552. #endif /* NTSIG */
  11553.             return;
  11554. #ifndef NOHTTP
  11555.         }
  11556. #endif /* NOHTTP */
  11557.     }
  11558.     ftpsndret = 0;
  11559. #ifdef NTSIG
  11560.      ckThreadEnd(threadinfo);
  11561. #endif /* NTSIG */
  11562. }
  11563.  
  11564. static VOID
  11565. #ifdef CK_ANSIC
  11566. failftpsend(void * threadinfo)
  11567. #else
  11568. failftpsend(threadinfo) VOID * threadinfo;
  11569. #endif /* CK_ANSIC */
  11570. {
  11571. #ifdef NTSIG
  11572.     if (threadinfo) {                   /* Thread local storage... */
  11573.         TlsSetValue(TlsIndex,threadinfo);
  11574.         debug(F100, "docmdfile called with threadinfo block","", 0);
  11575.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  11576. #endif /* NTSIG */
  11577. #ifdef CK_LOGIN
  11578. #ifdef IKSD
  11579. #ifdef NT
  11580.     if (inserver)
  11581.       setntcreds();
  11582. #endif /* NT */
  11583. #endif /* IKSD */
  11584. #endif /* CK_LOGIN */
  11585.  
  11586.     while (cpend) {
  11587.         ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
  11588.         debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
  11589.     }
  11590.     if (data >= 0) {
  11591. #ifdef CK_SSL
  11592.         if (ssl_ftp_data_active_flag) {
  11593.             SSL_shutdown(ssl_ftp_data_con);
  11594.             SSL_free(ssl_ftp_data_con);
  11595.             ssl_ftp_data_active_flag = 0;
  11596.             ssl_ftp_data_con = NULL;
  11597.         }
  11598. #endif /* CK_SSL */
  11599. #ifdef TCPIPLIB
  11600.         socket_close(data);
  11601. #else /* TCPIPLIB */
  11602. #ifdef USE_SHUTDOWN
  11603.         shutdown(data, 1+1);
  11604. #endif /* USE_SHUTDOWN */
  11605.         close(data);
  11606. #endif /* TCPIPLIB */
  11607.         data = -1;
  11608.         globaldin = -1;
  11609.     }
  11610.     if (ftpsnd.oldintr)
  11611.         signal(SIGINT,ftpsnd.oldintr);
  11612. #ifdef SIGPIPE
  11613.     if (ftpsnd.oldintp)
  11614.         signal(SIGPIPE,ftpsnd.oldintp);
  11615. #endif /* SIGPIPE */
  11616.     ftpcode = -1;
  11617. #ifndef OS2
  11618.     /* TEST ME IN K95 */
  11619.     if (havesigint) {
  11620.     havesigint = 0;
  11621.     debug(F100,"ftp failftpsend chain to trap()...","",0);
  11622.     if (ftpsnd.oldintr != SIG_IGN)
  11623.       (*ftpsnd.oldintr)(SIGINT);
  11624.     /* NOTREACHED (I hope!) */
  11625.     debug(F100,"ftp failftpsend return from trap()...","",0);
  11626.     }
  11627. #endif /* OS2 */
  11628. }
  11629.  
  11630. static VOID
  11631. #ifdef CK_ANSIC
  11632. failftpsend2(void * threadinfo)
  11633. #else
  11634. failftpsend2(threadinfo) VOID * threadinfo;
  11635. #endif /* CK_ANSIC */
  11636. {
  11637. #ifdef NTSIG
  11638.     if (threadinfo) {                   /* Thread local storage... */
  11639.         TlsSetValue(TlsIndex,threadinfo);
  11640.         debug(F100, "docmdfile called with threadinfo block","", 0);
  11641.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  11642. #endif /* NTSIG */
  11643. #ifdef CK_LOGIN
  11644. #ifdef IKSD
  11645. #ifdef NT
  11646.     if (inserver)
  11647.       setntcreds();
  11648. #endif /* NT */
  11649. #endif /* IKSD */
  11650. #endif /* CK_LOGIN */
  11651.  
  11652.     debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
  11653.     tfc += ffc;
  11654. #ifdef GFTIMER
  11655.     fpfsecs = gftimer();
  11656. #endif /* GFTIMER */
  11657.     zclose(ZIFILE);
  11658. #ifdef PIPESEND
  11659.     if (sndfilter)
  11660.       pipesend = 0;
  11661. #endif /* PIPESEND */
  11662.     signal(SIGINT, ftpsnd.oldintr);
  11663. #ifdef SIGPIPE
  11664.     if (ftpsnd.oldintp)
  11665.       signal(SIGPIPE, ftpsnd.oldintp);
  11666. #endif /* SIGPIPE */
  11667.     if (!cpend) {
  11668.         ftpcode = -1;
  11669.         ftpsndret = -1;
  11670. #ifdef NTSIG
  11671.         ckThreadEnd(threadinfo);
  11672. #endif /* NTSIG */
  11673.         return;
  11674.     }
  11675.     if (data >= 0) {
  11676. #ifdef CK_SSL
  11677.         if (ssl_ftp_data_active_flag) {
  11678.             SSL_shutdown(ssl_ftp_data_con);
  11679.             SSL_free(ssl_ftp_data_con);
  11680.             ssl_ftp_data_active_flag = 0;
  11681.             ssl_ftp_data_con = NULL;
  11682.         }
  11683. #endif /* CK_SSL */
  11684. #ifdef TCPIPLIB
  11685.         socket_close(data);
  11686. #else /* TCPIPLIB */
  11687. #ifdef USE_SHUTDOWN
  11688.         shutdown(data, 1+1);
  11689. #endif /* USE_SHUTDOWN */
  11690.         close(data);
  11691. #endif /* TCPIPLIB */
  11692.         data = -1;
  11693.         globaldin = -1;
  11694.     }
  11695.     if (dout) {
  11696. #ifdef TCPIPLIB
  11697.         socket_close(dout);
  11698. #else /* TCPIPLIB */
  11699. #ifdef USE_SHUTDOWN
  11700.         shutdown(dout, 1+1);
  11701. #endif /* USE_SHUTDOWN */
  11702.         close(dout);
  11703. #endif /* TCPIPLIB */
  11704.     }
  11705.     ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
  11706.     ftpcode = -1;
  11707.     ftpsndret = -1;
  11708.  
  11709. #ifndef OS2
  11710.     /* TEST ME IN K95 */
  11711.     if (havesigint) {
  11712.     havesigint = 0;
  11713.     debug(F100,"ftp failftpsend2 chain to trap()...","",0);
  11714.     if (ftpsnd.oldintr != SIG_IGN)
  11715.       (*ftpsnd.oldintr)(SIGINT);
  11716.     /* NOTREACHED (I hope!) */
  11717.     debug(F100,"ftp failftpsend2 return from trap()...","",0);
  11718.     }
  11719. #endif /* OS2 */
  11720. }
  11721.  
  11722. static VOID
  11723. #ifdef CK_ANSIC
  11724. doftpsend2(void * threadinfo)
  11725. #else
  11726. doftpsend2(threadinfo) VOID * threadinfo;
  11727. #endif
  11728. {
  11729.     register int c, d = 0;
  11730.     int n, t, x, notafile, unique = 0;
  11731.     char *buf, *bufp;
  11732.     
  11733. #ifdef NTSIG
  11734.     if (threadinfo) {                   /* Thread local storage... */
  11735.         TlsSetValue(TlsIndex,threadinfo);
  11736.         debug(F100, "doftpsend2 called with threadinfo block","", 0);
  11737.     } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
  11738. #endif /* NTSIG */
  11739. #ifdef CK_LOGIN
  11740. #ifdef IKSD
  11741. #ifdef NT
  11742.     if (inserver)
  11743.       setntcreds();
  11744. #endif /* NT */
  11745. #endif /* IKSD */
  11746. #endif /* CK_LOGIN */
  11747.  
  11748.     buf = ftpsndbuf;            /* (not on stack) */
  11749.  
  11750.     unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
  11751.     notafile = sndarray || pipesend;
  11752.  
  11753. #ifdef FTP_RESTART
  11754.     if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
  11755.         char * p;
  11756.         changetype(FTT_BIN,0);          /* Change to binary */
  11757.  
  11758.         /* Ask for remote file's size */
  11759.         x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
  11760.  
  11761.         if (x == REPLY_COMPLETE) {      /* Have ftpsnd.reply */
  11762.             p = &ftp_reply_str[4];      /* Parse it */
  11763.             while (isdigit(*p)) {
  11764.                 sendstart = sendstart * 10 + (int)(*p - '0');
  11765.                 p++;
  11766.             }
  11767.             if (*p && *p != CR) {       /* Bad number */
  11768.                 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
  11769.                 sendstart = (CK_OFF_T)0;
  11770.             } else if (sendstart > fsize) { /* Remote file bigger than local */
  11771.                 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
  11772.                 sendstart = (CK_OFF_T)0;
  11773.             }
  11774.         /* Local is newer */
  11775.             debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
  11776.             if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
  11777.                 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
  11778.                 sendstart = (CK_OFF_T)0; /* Send the whole file */
  11779.             }
  11780.         }
  11781.         changetype(ftp_typ,0);          /* Change back to appropriate type */
  11782.         if (sendstart > (CK_OFF_T)0) {    /* Still restarting? */
  11783.             if (sendstart == fsize) {   /* Same size - no need to send */
  11784.                 debug(F111,"doftpsend2 /restart SKIP",
  11785.               ckfstoa(fsize),sendstart);
  11786.                 zclose(ZIFILE);
  11787.                 ftpsndret = SKP_RES;
  11788. #ifdef NTSIG
  11789.                 ckThreadEnd(threadinfo);
  11790. #endif /* NTSIG */
  11791.                 return;
  11792.             }
  11793.             errno = 0;                  /* Restart needed, seek to the spot */
  11794.             if (zfseek((long)sendstart) < 0) {
  11795.                 debug(F111,"doftpsend2 zfseek fails",
  11796.               ftpsnd.local,sendstart);
  11797.                 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
  11798.                 sendstart = 0;
  11799.                 zclose(ZIFILE);
  11800.                 ftpsndret = -1;
  11801. #ifdef NTSIG
  11802.                 ckThreadEnd(threadinfo);
  11803. #endif /* NTSIG */
  11804.                 return;
  11805.             }
  11806. #ifdef COMMENT
  11807.             debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
  11808.             x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
  11809.             if (x != REPLY_CONTINUE) {
  11810.                 sendstart = 0;
  11811.                 zclose(ZIFILE);
  11812.                 ftpsndret = -1;
  11813. #ifdef NTSIG
  11814.                 ckThreadEnd(threadinfo);
  11815. #endif /* NTSIG */
  11816.                 return;
  11817.             } else {
  11818.                 ftpsnd.cmd = "STOR";
  11819.             }
  11820. #else
  11821.             sendmode = SM_RESEND;
  11822.             ftpsnd.cmd = "APPE";
  11823. #endif /* COMMENT */
  11824.             /* sendstart = (CK_OFF_T)0; */
  11825.         }
  11826.     }
  11827. #endif /* FTP_RESTART */
  11828.  
  11829.     if (unique && !stouarg)        /* If we know STOU accepts no arg */
  11830.       ftpsnd.remote = NULL;        /* don't include one. */
  11831.  
  11832.     x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
  11833.     debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
  11834.     debug(F101,"doftpsend2 ftpcmd","",x);
  11835.  
  11836.     if (x != REPLY_PRELIM && unique) {
  11837.     /*
  11838.       RFC959 says STOU does not take an argument.  But every FTP server
  11839.       I've encountered but one accepts the arg and constructs the unique
  11840.       name from it, which is better than making up a totally random name
  11841.       for the file, which is what RFC959 calls for.  Especially because
  11842.       there is no way for the client to find out the name chosen by the
  11843.       server.  So we try STOU with the argument first, which works with
  11844.       most servers, and if it fails we retry it without the arg, for
  11845.       the benefit of the one picky server that is not "liberal in what
  11846.       it accepts" UNLESS the first STOU got a 502 code ("not implemented")
  11847.       which means STOU is not accepted, period.
  11848.     */
  11849.     if ((x == 5) && stouarg && (ftpcode != 502)) {
  11850.         x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm); 
  11851.         if (x == REPLY_PRELIM)    /* If accepted */
  11852.           stouarg = 0;        /* flag no STOU arg for this server */
  11853.     }
  11854.     }
  11855.     if (x != REPLY_PRELIM) {
  11856.         signal(SIGINT, ftpsnd.oldintr);
  11857. #ifdef SIGPIPE
  11858.         if (ftpsnd.oldintp)
  11859.           signal(SIGPIPE, ftpsnd.oldintp);
  11860. #endif /* SIGPIPE */
  11861.     debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
  11862.         zclose(ZIFILE);
  11863. #ifdef PIPESEND
  11864.         if (sndfilter)
  11865.           pipesend = 0;
  11866. #endif /* PIPESEND */
  11867.         ftpsndret = -1;
  11868. #ifdef NTSIG
  11869.         ckThreadEnd(threadinfo);
  11870. #endif /* NTSIG */
  11871.         return;
  11872.     }
  11873.     debug(F100,"doftpsend2 getting data connection...","",0);
  11874.     dout = dataconn(ftpsnd.lmode);             /* Get data connection */
  11875.     debug(F101,"doftpsend2 dataconn","",dout);
  11876.     if (dout == -1) {
  11877.         failftpsend2(threadinfo);
  11878. #ifdef NTSIG
  11879.         ckThreadEnd(threadinfo);
  11880. #endif /* NTSIG */
  11881.         return;
  11882.     }
  11883.     /* Initialize per-file stats */
  11884.     ffc = (CK_OFF_T)0;            /* Character counter */
  11885.     cps = oldcps = 0L;                  /* Thruput */
  11886.     n = 0;
  11887. #ifdef GFTIMER
  11888.     rftimer();                          /* reset f.p. timer */
  11889. #endif /* GFTIMER */
  11890.  
  11891. #ifdef SIGPIPE
  11892.     ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
  11893. #endif /* SIGPIPE */
  11894.     debug(F101,"doftpsend2 curtype","",curtype);
  11895.     switch (curtype) {
  11896.       case FTT_BIN:                     /* Binary mode */
  11897.       case FTT_TEN:
  11898.         errno = d = 0;
  11899. #ifdef VMS
  11900.     /*
  11901.       This is because VMS zxin() is C-Library fread() 
  11902.           but the file was opened with zopeni(), which is RMS.
  11903.     */
  11904.     while (((c = zminchar()) > -1) && !cancelfile) {
  11905.         ffc++;
  11906.         if (zzout(dout,c) < 0)
  11907.           break;
  11908.     }
  11909. #else  /* VMS */
  11910.         while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
  11911.             ftpsnd.bytes += n;
  11912.             ffc += n;
  11913.             debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
  11914.             ckhexdump("doftpsend2 zxin",buf,16);
  11915. #ifdef CK_SSL
  11916.             if (ssl_ftp_data_active_flag) {
  11917.                 for (bufp = buf; n > 0; n -= d, bufp += d) {
  11918.                     if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
  11919.                       break;
  11920.                     spackets++;
  11921.                     pktnum++;
  11922.                     if (fdispla != XYFD_B) {
  11923.                         spktl = d;
  11924.                         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
  11925.                     }
  11926.                 }
  11927.             } else {
  11928. #endif /* CK_SSL */
  11929.                 for (bufp = buf; n > 0; n -= d, bufp += d) {
  11930.                     if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
  11931.                         || iscanceled())
  11932.                       break;
  11933.                     spackets++;
  11934.                     pktnum++;
  11935.                     if (fdispla != XYFD_B) {
  11936.                         spktl = d;
  11937.                         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
  11938.                     }
  11939.                 }
  11940. #ifdef CK_SSL
  11941.             }
  11942. #endif /* CK_SSL */
  11943.             if (d <= 0)
  11944.               break;
  11945.         }
  11946. #endif    /* VMS */
  11947.  
  11948.     debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
  11949.         if (n < 0)
  11950.           fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
  11951.         if (d < 0 || (d = secure_flush(dout)) < 0) {
  11952.             if (d == -1 && errno && errno != EPIPE)
  11953.               perror("netout");
  11954.             ftpsnd.bytes = -1;
  11955.         }
  11956.         break;
  11957.  
  11958.       case FTT_ASC:                     /* Text mode */
  11959. #ifndef NOCSETS
  11960.         if (ftpsnd.xlate) {             /* With translation */
  11961.             initxlate(ftpsnd.incs,ftpsnd.outcs);
  11962.             while (!cancelfile) {
  11963.                 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
  11964.                 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
  11965.             }
  11966.         } else {
  11967. #endif /* NOCSETS */
  11968.             /* Text mode, no translation */
  11969.             while (((c = zminchar()) > -1) && !cancelfile) {
  11970.                 ffc++;
  11971.         if (xxout(c) < 0)
  11972.           break;
  11973.             }
  11974.             d = 0;
  11975. #ifndef NOCSETS
  11976.         }
  11977. #endif /* NOCSETS */
  11978.         if (dout == -1 || (d = secure_flush(dout)) < 0) {
  11979.             if (d == -1 && errno && errno != EPIPE)
  11980.               perror("netout");
  11981.             ftpsnd.bytes = -1;
  11982.         }
  11983.         break;
  11984.     }
  11985.     tfc += ffc;                         /* Total file chars */
  11986. #ifdef GFTIMER
  11987.     fpfsecs = gftimer();
  11988. #endif /* GFTIMER */
  11989.     zclose(ZIFILE);                     /* Close input file */
  11990. #ifdef PIPESEND
  11991.     if (sndfilter)                      /* Undo this (it's per file) */
  11992.       pipesend = 0;
  11993. #endif /* PIPESEND */
  11994.  
  11995. #ifdef CK_SSL
  11996.         if (ssl_ftp_data_active_flag) {
  11997.             SSL_shutdown(ssl_ftp_data_con);
  11998.             SSL_free(ssl_ftp_data_con);
  11999.             ssl_ftp_data_active_flag = 0;
  12000.             ssl_ftp_data_con = NULL;
  12001.         }
  12002. #endif /* CK_SSL */
  12003.  
  12004. #ifdef TCPIPLIB
  12005.     socket_close(dout);                 /* Close data connection */
  12006. #else /* TCPIPLIB */
  12007. #ifdef USE_SHUTDOWN
  12008.     shutdown(dout, 1+1);
  12009. #endif /* USE_SHUTDOWN */
  12010.     close(dout);
  12011. #endif /* TCPIPLIB */
  12012.     ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
  12013.     signal(SIGINT, ftpsnd.oldintr);            /* Put back interrupts */
  12014. #ifdef SIGPIPE
  12015.     if (ftpsnd.oldintp)
  12016.       signal(SIGPIPE, ftpsnd.oldintp);
  12017. #endif /* SIGPIPE */
  12018.     if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
  12019.         debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
  12020.         ftpsndret = -1;
  12021. #ifdef NTSIG
  12022.         ckThreadEnd(threadinfo);
  12023. #endif /* NTSIG */
  12024.         return;
  12025.     } else if (cancelfile) {
  12026.         debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
  12027.         ftpsndret = -1;
  12028. #ifdef NTSIG
  12029.         ckThreadEnd(threadinfo);
  12030. #endif /* NTSIG */
  12031.         return;
  12032.     }
  12033.     debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
  12034.     ftpsndret = 0;
  12035. #ifdef NTSIG
  12036.      ckThreadEnd(threadinfo);
  12037. #endif /* NTSIG */
  12038. }
  12039.  
  12040. static int
  12041. sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
  12042.     char *cmd, *local, *remote; int xlate, incs, outcs, restart;
  12043. {
  12044.     if (!remote) remote = "";           /* Check args */
  12045.     if (!*remote) remote = local;
  12046.     if (!local) local = "";
  12047.     if (!*local) return(-1);
  12048.     if (!cmd) cmd = "";
  12049.     if (!*cmd) cmd = "STOR";
  12050.  
  12051.     debug(F111,"ftp sendrequest restart",local,restart);
  12052.  
  12053.     nout = 0;                           /* Init output buffer count */
  12054.     ftpsnd.bytes = 0;                   /* File input byte count */
  12055.     dout = -1;
  12056.  
  12057. #ifdef FTP_PROXY
  12058.     if (proxy) {
  12059.         proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
  12060.         return(0);
  12061.     }
  12062. #endif /* FTP_PROXY */
  12063.  
  12064.     changetype(ftp_typ,0);              /* Change type for this file */
  12065.  
  12066.     ftpsnd.oldintr = NULL;        /* Set up interrupt handler */
  12067.     ftpsnd.oldintp = NULL;
  12068.     ftpsnd.restart = restart;
  12069.     ftpsnd.xlate = xlate;
  12070.     ftpsnd.lmode = "wb";
  12071.  
  12072. #ifdef PIPESEND                         /* Use Kermit API for file i/o... */
  12073.     if (sndfilter) {
  12074.         char * p = NULL, * q;
  12075. #ifndef NOSPL
  12076.         int n = CKMAXPATH;
  12077.         if (cmd_quoting && (p = (char *) malloc(n + 1))) {
  12078.             q = p;
  12079.             debug(F110,"sendrequest pipesend filter",sndfilter,0);
  12080.             zzstring(sndfilter,&p,&n);
  12081.             debug(F111,"sendrequest pipename",q,n);
  12082.             if (n <= 0) {
  12083.                 printf("?Sorry, send filter + filename too long, %d max.\n",
  12084.                        CKMAXPATH
  12085.                        );
  12086.                 free(q);
  12087.                 return(-1);
  12088.             }
  12089.             ckstrncpy(filnam,q,CKMAXPATH+1);
  12090.             free(q);
  12091.             local = filnam;
  12092.         }
  12093. #endif /* NOSPL */
  12094.     }
  12095.  
  12096.     if (sndfilter)                      /* If sending thru a filter */
  12097.       pipesend = 1;                     /* set this for open and i/o */
  12098. #endif /* PIPESEND */
  12099.     
  12100. #ifdef VMS
  12101.     debug(F101,"XXX before openi binary","",binary);
  12102.     debug(F101,"XXX before openi ftp_typ","",ftp_typ);
  12103. #endif    /* VMS */
  12104.  
  12105.     if (openi(local) == 0)        /* Try to open the input file */
  12106.       return(-1);
  12107.  
  12108. #ifdef VMS
  12109.     debug(F101,"XXX after openi binary","",binary);
  12110.     debug(F101,"XXX after openi ftp_typ","",ftp_typ);
  12111.     if (!forcetype) {
  12112.     if (binary != ftp_typ) {    /* VMS zopeni() sets binary */
  12113.         debug(F101,"XXX changing type","",binary);
  12114.         doftptyp(binary);
  12115.         debug(F101,"XXX after doftptyp","",ftp_typ);
  12116.  
  12117.         /* **** */
  12118.         if (displa && fdispla) {    /* Update file type display */
  12119.         ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
  12120.         }
  12121.     }
  12122.     }
  12123. #endif    /* VMS */
  12124.     ftpsndret = 0;
  12125.     ftpsnd.incs = incs;
  12126.     ftpsnd.outcs = outcs;
  12127.     ftpsnd.cmd = cmd;
  12128.     ftpsnd.local = local;
  12129.     ftpsnd.remote = remote;
  12130.     ftpsnd.oldintr = signal(SIGINT, cancelsend);
  12131.     havesigint = 0;
  12132.  
  12133.     if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
  12134.       return(-1);
  12135.     if (ftpsndret < 0)
  12136.       return(-1);
  12137.     if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
  12138.       return(-1);
  12139.  
  12140.     return(ftpsndret);
  12141. }
  12142.  
  12143. static sigtype
  12144. cancelrecv(sig) int sig; {
  12145.     havesigint++;
  12146.     cancelfile = 0;
  12147.     cancelgroup++;
  12148.     secure_getc(0,1);            /* Initialize net input buffers */
  12149.     printf(" Canceling...\n");
  12150.     debug(F100,"ftp cancelrecv caught SIGINT","",0);
  12151.     fflush(stdout);
  12152.     if (fp_nml) {
  12153.         if (fp_nml != stdout)
  12154.           fclose(fp_nml);
  12155.         fp_nml = NULL;
  12156.     }
  12157. #ifndef OS2
  12158.     longjmp(recvcancel, 1);
  12159. #else
  12160.     PostCtrlCSem();
  12161. #endif /* OS2 */
  12162. }
  12163.  
  12164. /* Argumentless front-end for secure_getc() */
  12165.  
  12166. static int
  12167. netgetc() {
  12168.     return(secure_getc(globaldin,0));
  12169. }
  12170.  
  12171. /* Returns -1 on failure, 0 on success, 1 if file skipped */
  12172.  
  12173. /*
  12174.   Sets ftpcode < 0 on failure if failure reason is not server reply code:
  12175.     -1: interrupted by user.
  12176.     -2: error opening or writing output file (reason in errno).
  12177.     -3: failure to make data connection.
  12178.     -4: network read error (reason in errno).
  12179. */
  12180.  
  12181. struct xx_ftprecv {
  12182.     int reply;
  12183.     int fcs;
  12184.     int rcs;
  12185.     int recover;
  12186.     int xlate;
  12187.     int din;
  12188.     int is_retr;
  12189.     sig_t oldintr, oldintp;
  12190.     char * cmd;
  12191.     char * local;
  12192.     char * remote;
  12193.     char * lmode;
  12194.     char * pipename;
  12195.     int    tcrflag;
  12196.     CK_OFF_T localsize;
  12197. };
  12198. static struct xx_ftprecv ftprecv;
  12199.  
  12200. static int ftprecvret = 0;
  12201.  
  12202. static VOID
  12203. #ifdef CK_ANSIC
  12204. failftprecv(VOID * threadinfo)
  12205. #else
  12206. failftprecv(threadinfo) VOID * threadinfo;
  12207. #endif /* CK_ANSIC */
  12208. {
  12209. #ifdef NTSIG
  12210.     if (threadinfo) {                   /* Thread local storage... */
  12211.         TlsSetValue(TlsIndex,threadinfo);
  12212.         debug(F100, "docmdfile called with threadinfo block","", 0);
  12213.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  12214. #endif /* NTSIG */
  12215.  
  12216. #ifdef CK_LOGIN
  12217. #ifdef IKSD
  12218. #ifdef NT
  12219.     if (inserver)
  12220.       setntcreds();
  12221. #endif /* NT */
  12222. #endif /* IKSD */
  12223. #endif /* CK_LOGIN */
  12224.  
  12225.     while (cpend) {
  12226.         ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
  12227.     }
  12228.     if (data >= 0) {
  12229. #ifdef CK_SSL
  12230.         if (ssl_ftp_data_active_flag) {
  12231.             SSL_shutdown(ssl_ftp_data_con);
  12232.             SSL_free(ssl_ftp_data_con);
  12233.             ssl_ftp_data_active_flag = 0;
  12234.             ssl_ftp_data_con = NULL;
  12235.         }
  12236. #endif /* CK_SSL */
  12237. #ifdef TCPIPLIB
  12238.         socket_close(data);
  12239. #else /* TCPIPLIB */
  12240. #ifdef USE_SHUTDOWN
  12241.         shutdown(data, 1+1);
  12242. #endif /* USE_SHUTDOWN */
  12243.         close(data);
  12244. #endif /* TCPIPLIB */
  12245.         data = -1;
  12246.         globaldin = -1;
  12247.     }
  12248.     if (ftprecv.oldintr)
  12249.       signal(SIGINT, ftprecv.oldintr);
  12250.     ftpcode = -1;
  12251.     ftprecvret = -1;
  12252.  
  12253. #ifndef OS2
  12254.     /* TEST ME IN K95 */
  12255.     if (havesigint) {
  12256.     havesigint = 0;
  12257.     debug(F100,"ftp failftprecv chain to trap()...","",0);
  12258.     if (ftprecv.oldintr != SIG_IGN)
  12259.       (*ftprecv.oldintr)(SIGINT);
  12260.     /* NOTREACHED (I hope!) */
  12261.     debug(F100,"ftp failftprecv return from trap()...","",0);
  12262.     }
  12263. #endif /* OS2 */
  12264.     return;
  12265. }
  12266.  
  12267. static VOID
  12268. #ifdef CK_ANSIC
  12269. doftprecv(VOID * threadinfo)
  12270. #else
  12271. doftprecv(threadinfo) VOID * threadinfo;
  12272. #endif /* CK_ANSIC */
  12273. {
  12274. #ifdef NTSIG
  12275.     if (threadinfo) {                   /* Thread local storage... */
  12276.         TlsSetValue(TlsIndex,threadinfo);
  12277.         debug(F100, "docmdfile called with threadinfo block","", 0);
  12278.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  12279. #endif /* NTSIG */
  12280. #ifdef CK_LOGIN
  12281. #ifdef IKSD
  12282. #ifdef NT
  12283.     if (inserver)
  12284.       setntcreds();
  12285. #endif /* NT */
  12286. #endif /* IKSD */
  12287. #endif /* CK_LOGIN */
  12288.  
  12289. #ifndef COMMENT
  12290.     if (!out2screen && !ftprecv.pipename) {
  12291.     int x;
  12292.     char * local;
  12293.     local = ftprecv.local;
  12294.     x = zchko(local);
  12295.         if (x < 0) {
  12296.             if ((!dpyactive || ftp_deb))
  12297.               fprintf(stderr,
  12298.               "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
  12299.             signal(SIGINT, ftprecv.oldintr);
  12300.             ftpcode = -2;
  12301.             ftprecvret = -1;
  12302. #ifdef NTSIG
  12303.             ckThreadEnd(threadinfo);
  12304. #endif /* NTSIG */
  12305.             return;
  12306.         }
  12307.     }
  12308. #endif /* COMMENT */
  12309.     changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
  12310.     if (initconn()) {                   /* Initialize the data connection */
  12311.         signal(SIGINT, ftprecv.oldintr);
  12312.         ftpcode = -1;
  12313.         ftprecvret = -3;
  12314. #ifdef NTSIG
  12315.         ckThreadEnd(threadinfo);
  12316. #endif /* NTSIG */
  12317.         return;
  12318.     }
  12319.     secure_getc(0,1);            /* Initialize net input buffers */
  12320.     ftprecvret = 0;
  12321.  
  12322. #ifdef NTSIG
  12323.     ckThreadEnd(threadinfo);
  12324. #endif /* NTSIG */
  12325. }
  12326.  
  12327. static VOID
  12328. #ifdef CK_ANSIC
  12329. failftprecv2(VOID * threadinfo)
  12330. #else
  12331. failftprecv2(threadinfo) VOID * threadinfo;
  12332. #endif /* CK_ANSIC */
  12333. {
  12334. #ifdef NTSIG
  12335.     if (threadinfo) {                   /* Thread local storage... */
  12336.         TlsSetValue(TlsIndex,threadinfo);
  12337.         debug(F100, "docmdfile called with threadinfo block","", 0);
  12338.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  12339. #endif /* NTSIG */
  12340. #ifdef CK_LOGIN
  12341. #ifdef IKSD
  12342. #ifdef NT
  12343.     if (inserver)
  12344.       setntcreds();
  12345. #endif /* NT */
  12346. #endif /* IKSD */
  12347. #endif /* CK_LOGIN */
  12348.  
  12349.     /* Cancel using RFC959 recommended IP,SYNC sequence  */
  12350.  
  12351.     debug(F100,"ftp recvrequest CANCEL","",0);
  12352. #ifdef GFTIMER
  12353.     fpfsecs = gftimer();
  12354. #endif /* GFTIMER */
  12355. #ifdef SIGPIPE
  12356.     if (ftprecv.oldintp)
  12357.       signal(SIGPIPE, ftprecv.oldintr);
  12358. #endif /* SIGPIPE */
  12359.     signal(SIGINT, SIG_IGN);
  12360.     if (!cpend) {
  12361.         ftpcode = -1;
  12362.         signal(SIGINT, ftprecv.oldintr);
  12363.         ftprecvret = -1;
  12364. #ifdef NTSIG
  12365.         ckThreadEnd(threadinfo);
  12366. #endif /* NTSIG */
  12367.         return;
  12368.     }
  12369.     cancel_remote(ftprecv.din);
  12370.  
  12371. #ifdef FTP_TIMEOUT
  12372.     if (ftp_timed_out && out2screen && !quiet)
  12373.       printf("\n?Timed out.\n");
  12374. #endif    /* FTP_TIMEOUT */
  12375.  
  12376.     if (ftpcode > -1)
  12377.       ftpcode = -1;
  12378.     if (data >= 0) {
  12379. #ifdef CK_SSL
  12380.         if (ssl_ftp_data_active_flag) {
  12381.             SSL_shutdown(ssl_ftp_data_con);
  12382.             SSL_free(ssl_ftp_data_con);
  12383.             ssl_ftp_data_active_flag = 0;
  12384.             ssl_ftp_data_con = NULL;
  12385.         }
  12386. #endif /* CK_SSL */
  12387. #ifdef TCPIPLIB
  12388.         socket_close(data);
  12389. #else /* TCPIPLIB */
  12390. #ifdef USE_SHUTDOWN
  12391.         shutdown(data, 1+1);
  12392. #endif /* USE_SHUTDOWN */
  12393.         close(data);
  12394. #endif /* TCPIPLIB */
  12395.         data = -1;
  12396.         globaldin = -1;
  12397.     }
  12398.     if (!out2screen) {
  12399.     int x = 0;
  12400.     debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
  12401.     zclose(ZOFILE);
  12402.     switch (keep) {            /* which is... */
  12403.       case SET_AUTO:        /* AUTO */
  12404.         if (curtype == FTT_ASC)    /* Delete file if TYPE A. */
  12405.           x = 1;
  12406.         break;
  12407.       case SET_OFF:            /* DISCARD */
  12408.         x = 1;            /* Delete file, period. */
  12409.         break;
  12410.       default:            /* KEEP */
  12411.         break;
  12412.     }
  12413.     if (x) {
  12414.         x = zdelet(ftprecv.local);
  12415.         debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
  12416.     }
  12417.     }
  12418.     if (ftprecv.din) {
  12419. #ifdef TCPIPLIB
  12420.         socket_close(ftprecv.din);
  12421. #else /* TCPIPLIB */
  12422. #ifdef USE_SHUTDOWN
  12423.         shutdown(ftprecv.din, 1+1);
  12424. #endif /* USE_SHUTDOWN */
  12425.         close(ftprecv.din);
  12426. #endif /* TCPIPLIB */
  12427.     }
  12428.     signal(SIGINT, ftprecv.oldintr);
  12429.     ftprecvret = -1;
  12430.  
  12431.     if (havesigint) {
  12432.     havesigint = 0;
  12433.     debug(F100,"FTP failftprecv2 chain to trap()...","",0);
  12434. #ifdef OS2
  12435.         debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
  12436.         PostCtrlCSem();
  12437. #else /* OS2 */
  12438.     if (ftprecv.oldintr != SIG_IGN)
  12439.       (*ftprecv.oldintr)(SIGINT);
  12440.     /* NOTREACHED (I hope!) */
  12441.     debug(F100,"ftp failftprecv2 return from trap()...","",0);
  12442. #endif /* OS2 */
  12443.     }
  12444. }
  12445.  
  12446. static VOID
  12447. #ifdef CK_ANSIC
  12448. doftprecv2(VOID * threadinfo)
  12449. #else
  12450. doftprecv2(threadinfo) VOID * threadinfo;
  12451. #endif /* CK_ANSIC */
  12452. {
  12453.     register int c, d;
  12454.     CK_OFF_T bytes = (CK_OFF_T)0;
  12455.     int bare_lfs = 0;
  12456.     int blksize = 0;
  12457.     ULONG start = 0L, stop;
  12458.     char * p;
  12459.     static char * rcvbuf = NULL;
  12460.     static int rcvbufsiz = 0;
  12461. #ifdef CK_URL
  12462.     char newname[CKMAXPATH+1];        /* For file dialog */
  12463. #endif /* CK_URL */
  12464.     extern int adl_ask;
  12465.  
  12466. #ifdef FTP_TIMEOUT
  12467.     ftp_timed_out = 0;
  12468. #endif    /* FTP_TIMEOUT */
  12469.  
  12470.     ftprecv.din = -1;
  12471. #ifdef NTSIG
  12472.     if (threadinfo) {                   /* Thread local storage... */
  12473.         TlsSetValue(TlsIndex,threadinfo);
  12474.         debug(F100, "docmdfile called with threadinfo block","", 0);
  12475.     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
  12476. #endif /* NTSIG */
  12477. #ifdef CK_LOGIN
  12478. #ifdef IKSD
  12479. #ifdef NT
  12480.     if (inserver)
  12481.       setntcreds();
  12482. #endif /* NT */
  12483. #endif /* IKSD */
  12484. #endif /* CK_LOGIN */
  12485.  
  12486.     if (ftprecv.recover) {                      /* Initiate recovery */
  12487.         x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
  12488.         debug(F111,"ftp reply","REST",x);
  12489.         if (x == REPLY_CONTINUE) {
  12490.             ftprecv.lmode = "ab";
  12491.             rs_len = ftprecv.localsize;
  12492.         } else {
  12493.             ftprecv.recover = 0;
  12494.         }
  12495.     }
  12496.     /* IMPORTANT: No FTP commands can come between REST and RETR! */
  12497.  
  12498.     debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
  12499.  
  12500.     /* Send the command and get reply */
  12501.     debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
  12502.     debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
  12503.  
  12504.     if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
  12505.     != REPLY_PRELIM) {
  12506.         signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
  12507.         ftprecvret = -1;        /* ftpcode is set by ftpcmd() */
  12508. #ifdef NTSIG
  12509.         ckThreadEnd(threadinfo);
  12510. #endif /* NTSIG */
  12511.         return;
  12512.     }
  12513.     ftprecv.din = dataconn("r");        /* Good reply, open data connection */
  12514.     globaldin = ftprecv.din;            /* Global copy of file descriptor */
  12515.     if (ftprecv.din == -1) {            /* Check for failure */
  12516.         ftpcode = -3;                   /* Code for no data connection */
  12517.         ftprecvret = -1;
  12518. #ifdef NTSIG
  12519.         ckThreadEnd(threadinfo);
  12520. #endif /* NTSIG */
  12521.         return;
  12522.     }
  12523. #ifdef CK_URL
  12524.     /* In K95 GUI put up a file box */
  12525.     if (haveurl && g_url.pth && adl_ask    ) { /* Downloading from a URL */
  12526.     int x;
  12527.     char * preface =
  12528. "\r\nIncoming file from FTP server...\r\n\
  12529. Please confirm output file specification or supply an alternative:";
  12530.  
  12531.     x = uq_file(preface,        /* K95 GUI: Put up file box. */
  12532.             NULL,
  12533.             4,
  12534.             NULL,
  12535.             ftprecv.local ? ftprecv.local : ftprecv.remote,
  12536.             newname,
  12537.             CKMAXPATH+1
  12538.             );
  12539.     if (x > 0) {
  12540.         ftprecv.local = newname;    /* Substitute user's file name */
  12541.         if (x == 2)            /* And append if user said to */
  12542.           ftprecv.lmode = "ab";
  12543.     }
  12544.     }
  12545. #endif /* CK_URL */
  12546.     x = 1;                              /* Output file open OK? */
  12547.     if (ftprecv.pipename) {        /* Command */
  12548.         x = zxcmd(ZOFILE,ftprecv.pipename);
  12549.         debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
  12550.     } else if (!out2screen) {           /* File */
  12551.         struct filinfo xx;
  12552.         xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
  12553.         xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
  12554.     /* Append or New */
  12555.         xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
  12556.         x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
  12557.         debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
  12558.     }
  12559.     if (x < 1) {                        /* Failure to open output file */
  12560.         if ((!dpyactive || ftp_deb))
  12561.           fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
  12562.         ftprecvret = -1;
  12563. #ifdef NTSIG
  12564.         ckThreadEnd(threadinfo);
  12565. #endif /* NTSIG */
  12566.         return;
  12567.     }
  12568.     blksize = FTP_BUFSIZ;               /* Allocate input buffer */
  12569.  
  12570.     debug(F101,"ftp recvrequest blksize","",blksize);
  12571.     debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
  12572.  
  12573.     if (rcvbufsiz < blksize) {          /* if necessary */
  12574.         if (rcvbuf) {
  12575.             free(rcvbuf);
  12576.             rcvbuf = NULL;
  12577.         }
  12578.         rcvbuf = (char *)malloc((unsigned)blksize);
  12579.         if (!rcvbuf) {
  12580.         debug(F100,"ftp get rcvbuf malloc failed","",0);
  12581.             ftpcode = -2;
  12582. #ifdef ENOMEM
  12583.             errno = ENOMEM;
  12584. #endif /* ENOMEM */
  12585.             if ((!dpyactive || ftp_deb))
  12586.               perror("malloc");
  12587.             rcvbufsiz = 0;
  12588.             ftprecvret = -1;
  12589. #ifdef NTSIG
  12590.             ckThreadEnd(threadinfo);
  12591. #endif /* NTSIG */
  12592.             return;
  12593.         }
  12594.     debug(F101,"ftp get rcvbuf malloc ok","",blksize);
  12595.         rcvbufsiz = blksize;
  12596.     }
  12597.     debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
  12598.  
  12599.     ffc = (CK_OFF_T)0;            /* Character counter */
  12600.     cps = oldcps = 0L;                  /* Thruput */
  12601.     start = gmstimer();                 /* Start time (msecs) */
  12602. #ifdef GFTIMER
  12603.     rftimer();                          /* Start time (float) */
  12604. #endif /* GFTIMER */
  12605.  
  12606.     debug(F111,"ftp get type",ftprecv.local,curtype);
  12607.     debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
  12608.     switch (curtype) {
  12609.       case FTT_BIN:                     /* Binary mode */
  12610.       case FTT_TEN:                     /* TENEX mode */
  12611.         d = 0;
  12612.         while (1) {
  12613.             errno = 0;
  12614.             c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
  12615.             if (cancelfile) {
  12616.                 failftprecv2(threadinfo);
  12617. #ifdef NTSIG
  12618.                 ckThreadEnd(threadinfo);
  12619. #endif /* NTSIG */
  12620.                 return;
  12621.             }
  12622.             if (c < 1)
  12623.               break;
  12624. #ifdef printf                           /* (What if it isn't?) */
  12625.             if (out2screen && !ftprecv.pipename) {
  12626.                 int i;
  12627.                 for (i = 0; i < c; i++)
  12628.                   printf("%c",rcvbuf[i]);
  12629.             } else
  12630. #endif /* printf */
  12631.               {
  12632.                 register int i;
  12633.                 i = 0;
  12634.                 errno = 0;
  12635.                 while (i < c) {
  12636.                     if (zmchout(rcvbuf[i++]) < 0) {
  12637.                         d = i;
  12638.                         break;
  12639.                     }
  12640.                 }
  12641.             }
  12642.             bytes += c;
  12643.             ffc += c;
  12644.         }
  12645. #ifdef FTP_TIMEOUT
  12646.     if (c == -3) {
  12647.             debug(F100,"ftp recvrequest timeout","",0); 
  12648.             bytes = (CK_OFF_T)-1;
  12649.         ftp_timed_out = 1;
  12650.         ftpcode = -3;
  12651.     } else
  12652. #endif    /* FTP_TIMEOUT */
  12653.         if (c < 0) {
  12654.             debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
  12655.             if (c == -1 && errno != EPIPE)
  12656.               if ((!dpyactive || ftp_deb))
  12657.                 perror("netin");
  12658.             bytes = (CK_OFF_T)-1;
  12659.             ftpcode = -4;
  12660.         }
  12661.         if (d < c) {
  12662.             ftpcode = -2;
  12663.             if ((!dpyactive || ftp_deb)) {
  12664.                 char * p;
  12665.                 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
  12666.                 if (d < 0)
  12667.                   fprintf(stderr,
  12668.               "local(3): %s: %s\n", ftprecv.local, ck_errstr());
  12669.                 else
  12670.                   fprintf(stderr,
  12671.               "%s: short write\n", ftprecv.local);
  12672.             }
  12673.         }
  12674.         break;
  12675.  
  12676.       case FTT_ASC:                     /* Text mode */
  12677.     debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
  12678. #ifndef NOCSETS
  12679.         if (ftprecv.xlate) {
  12680.             int t;
  12681. #ifdef CK_ANSIC
  12682.             int (*fn)(char);
  12683. #else
  12684.             int (*fn)();
  12685. #endif /* CK_ANSIC */
  12686.             debug(F110,"ftp recvrequest (data)","initxlate",0);
  12687.             initxlate(ftprecv.rcs,ftprecv.fcs);         /* (From,To) */
  12688.             if (ftprecv.pipename) {
  12689.                 fn = pipeout;
  12690.                 debug(F110,"ftp recvrequest ASCII","pipeout",0);
  12691.             } else {
  12692.                 fn = out2screen ? scrnout : putfil;
  12693.                 debug(F110,"ftp recvrequest ASCII",
  12694.                       out2screen ? "scrnout" : "putfil",0);
  12695.             }
  12696.             while (1) {
  12697.         /* Get byte from net */
  12698.                 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
  12699.                 if (cancelfile) {
  12700.                     failftprecv2(threadinfo);
  12701. #ifdef NTSIG
  12702.                     ckThreadEnd(threadinfo);
  12703. #endif /* NTSIG */
  12704.                     return;
  12705.                 }
  12706.                 if (c0 < 0)
  12707.                   break;
  12708.         /* Second byte from net */
  12709.                 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
  12710.                 if (cancelfile) {
  12711.                     failftprecv2(threadinfo);
  12712. #ifdef NTSIG
  12713.                     ckThreadEnd(threadinfo);
  12714. #endif /* NTSIG */
  12715.                     return;
  12716.                 }
  12717.                 if (c1 < 0)
  12718.                   break;
  12719. #ifdef COMMENT
  12720.         /* K95: Check whether we need this */
  12721.         if (fileorder > 0)    /* Little Endian */
  12722.           bytswap(&c0,&c1);    /* swap bytes*/
  12723. #endif /* COMMENT */
  12724.  
  12725. #ifdef OS2
  12726.                 if ( out2screen &&            /* we're translating to UCS-2 */ 
  12727.                      !k95stdout && !inserver) /* for the real screen... */     
  12728.                 {
  12729.                     union {
  12730.                         USHORT ucs2;
  12731.                         UCHAR  bytes[2];
  12732.                     } output;
  12733.  
  12734.                     output.bytes[0] = c1;
  12735.                     output.bytes[1] = c0;
  12736.  
  12737.                     VscrnWrtUCS2StrAtt(VCMD,
  12738.                                        &output.ucs2,
  12739.                                        1,
  12740.                                        wherey[VCMD],
  12741.                                        wherex[VCMD],
  12742.                                        &colorcmd
  12743.                                        );
  12744.  
  12745.                 } else 
  12746. #endif /* OS2 */
  12747.                 {
  12748.                     if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
  12749.                     if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
  12750.                 }
  12751.             }
  12752.         } else {
  12753. #endif /* NOCSETS */
  12754.             while (1) {
  12755.                 c = secure_getc(ftprecv.din,0);
  12756.                 if (cancelfile
  12757. #ifdef FTP_TIMEOUT
  12758.             || ftp_timed_out
  12759. #endif    /* FTP_TIMEOUT */
  12760.             ) {
  12761.                     failftprecv2(threadinfo);
  12762. #ifdef NTSIG
  12763.                     ckThreadEnd(threadinfo);
  12764. #endif /* NTSIG */
  12765.                     return;
  12766.                 }
  12767.                 if (c < 0 || c == EOF)
  12768.                   break;
  12769. #ifdef UNIX
  12770.         /* Record format conversion for Unix */
  12771.         /* SKIP THIS FOR WINDOWS! */
  12772.                 if (c == '\n')
  12773.                   bare_lfs++;
  12774.                 while (c == '\r') {
  12775.                     bytes++;
  12776.                     if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
  12777.             ftprecv.tcrflag) {
  12778.                         if (cancelfile) {
  12779.                             failftprecv2(threadinfo);
  12780. #ifdef NTSIG
  12781.                             ckThreadEnd(threadinfo);
  12782. #endif /* NTSIG */
  12783.                             return;
  12784.                         }
  12785.                         if (c < 0 || c == EOF)
  12786.                           goto break2;
  12787.                         if (c == '\0') {
  12788.                             bytes++;
  12789.                             goto contin2;
  12790.                         }
  12791.                     }
  12792.                 }
  12793.                 if (c < 0)
  12794.                   break;
  12795. #endif /* UNX */
  12796.  
  12797.                 if (out2screen && !ftprecv.pipename)
  12798. #ifdef printf
  12799.                   printf("%c",(char)c);
  12800. #else
  12801.                   putchar((char)c);
  12802. #endif /* printf */
  12803.                 else
  12804.                   if ((d = zmchout(c)) < 0)
  12805.                     break;
  12806.                 bytes++;
  12807.                 ffc++;
  12808.               contin2:
  12809.                 ;
  12810.             }
  12811.           break2:
  12812.             if (bare_lfs && (!dpyactive || ftp_deb)) {
  12813.                 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
  12814.                        bare_lfs);
  12815.                 printf("File might not have transferred correctly.\n");
  12816.             }
  12817.             if (ftprecv.din == -1) {
  12818.                 bytes = (CK_OFF_T)-1;
  12819.             }
  12820.             if (c == -2)
  12821.               bytes = (CK_OFF_T)-1;
  12822.             break;
  12823. #ifndef NOCSETS
  12824.         }
  12825. #endif /* NOCSETS */
  12826.     }
  12827.     if (ftprecv.pipename || !out2screen) {
  12828.     zclose(ZOFILE);            /* Close the file */
  12829.     debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
  12830.     if (ftpcode < 0) {        /* If download failed */
  12831.         int x = 0;
  12832.         switch (keep) {        /* which is... */
  12833.           case SET_AUTO:        /* AUTO */
  12834.         if (curtype == FTT_ASC) /* Delete file if TYPE A. */
  12835.           x = 1;
  12836.         break;
  12837.           case SET_OFF:        /* DISCARD */
  12838.         x = 1;            /* Delete file, period. */
  12839.         break;
  12840.           default:            /* KEEP */
  12841.         break;
  12842.         }
  12843.         if (x) {
  12844.         x = zdelet(ftprecv.local);
  12845.         debug(F111,"ftp get delete incomplete",ftprecv.local,x);
  12846.         }
  12847.     }
  12848.     }
  12849.     signal(SIGINT, ftprecv.oldintr);
  12850. #ifdef SIGPIPE
  12851.     if (ftprecv.oldintp)
  12852.       signal(SIGPIPE, ftprecv.oldintp);
  12853. #endif /* SIGPIPE */
  12854.     stop = gmstimer();
  12855. #ifdef GFTIMER
  12856.     fpfsecs = gftimer();
  12857. #endif /* GFTIMER */
  12858.     tfc += ffc;
  12859.  
  12860. #ifdef TCPIPLIB
  12861.     socket_close(ftprecv.din);
  12862. #else /* TCPIPLIB */
  12863. #ifdef USE_SHUTDOWN
  12864.     shutdown(ftprecv.din, 1+1);
  12865. #endif /* USE_SHUTDOWN */
  12866.     close(ftprecv.din);
  12867. #endif /* TCPIPLIB */
  12868.     ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
  12869.     ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT || 
  12870.                    ftprecv.reply == REPLY_ERROR) ? -1 : 0);
  12871. #ifdef NTSIG
  12872.      ckThreadEnd(threadinfo);
  12873. #endif /* NTSIG */
  12874. }
  12875.  
  12876. static int
  12877. recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
  12878.             xlate, fcs, rcs)
  12879.     char *cmd, *local, *remote, *lmode, *pipename;
  12880.     int printnames, recover, xlate, fcs, rcs;
  12881. {
  12882. #ifdef NT
  12883.     struct _stat stbuf;
  12884. #else /* NT */
  12885.     struct stat stbuf;
  12886. #endif /* NT */
  12887.  
  12888. #ifdef DEBUG
  12889.     if (deblog) {
  12890.         debug(F111,"ftp recvrequest cmd",cmd,recover);
  12891.         debug(F110,"ftp recvrequest local ",local,0);
  12892.         debug(F111,"ftp recvrequest remote",remote,ftp_typ);
  12893.         debug(F110,"ftp recvrequest pipename ",pipename,0);
  12894.         debug(F101,"ftp recvrequest xlate","",xlate);
  12895.         debug(F101,"ftp recvrequest fcs","",fcs);
  12896.         debug(F101,"ftp recvrequest rcs","",rcs);
  12897.     }
  12898. #endif /* DEBUG */
  12899.  
  12900.     ftprecv.localsize = (CK_OFF_T)0;
  12901.  
  12902.     if (remfile) {                      /* See remcfm(), remtxt() */
  12903.         if (rempipe) {
  12904.             pipename = remdest;
  12905.         } else {
  12906.             local = remdest;
  12907.             if (remappd) lmode = "ab";
  12908.         }
  12909.     }
  12910.     out2screen = 0;
  12911.     if (!cmd) cmd = "";                 /* Core dump prevention */
  12912.     if (!remote) remote = "";
  12913.     if (!lmode) lmode = "";
  12914.  
  12915.     if (pipename) {                     /* No recovery for pipes. */
  12916.         recover = 0;
  12917.         if (!local)
  12918.           local = pipename;
  12919.     } else {
  12920.         if (!local)                     /* Output to screen? */
  12921.           local = "-";
  12922.         out2screen = !strcmp(local,"-");
  12923.     }
  12924.     debug(F101,"ftp recvrequest out2screen","",out2screen);
  12925.  
  12926. #ifdef OS2
  12927.     if ( ftp_xla && out2screen && !k95stdout && !inserver )
  12928.         fcs = FC_UCS2;
  12929. #endif /* OS2 */
  12930.  
  12931.     if (out2screen)                     /* No recovery to screen */
  12932.       recover = 0;
  12933.     if (!ftp_typ)                       /* No recovery in text mode */
  12934.       recover = 0;
  12935.     ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
  12936.  
  12937.     if (!ftprecv.is_retr)               /* No recovery except for RETRieve */
  12938.       recover = 0;
  12939.  
  12940. #ifdef COMMENT
  12941.     if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
  12942.         if (recursive && ckstrchr(local,'/')) {
  12943.         
  12944.         }
  12945.     }
  12946. #endif /* COMMENT */
  12947.  
  12948.     ftprecv.localsize = (CK_OFF_T)0;    /* Local file size */
  12949.     rs_len = (CK_OFF_T)0;        /* Recovery point */
  12950.  
  12951.     debug(F101,"ftp recvrequest recover","",recover);
  12952.     if (recover) {                      /* Recovering... */
  12953.         if (stat(local, &stbuf) < 0) {  /* Can't stat local file */
  12954.         debug(F101,"ftp recvrequest recover stat failed","",errno);
  12955.             recover = 0;                /* So cancel recovery */
  12956.         } else {                        /* Have local file info */
  12957.             ftprecv.localsize = stbuf.st_size;  /* Get size */
  12958.         /* Remote file smaller than local */
  12959.             if (fsize < ftprecv.localsize) {
  12960.         debug(F101,"ftp recvrequest recover remote smaller","",fsize);
  12961.                 recover = 0;            /* Recovery can't work */
  12962.             } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
  12963.                 debug(F111,"ftp recvrequest recover equal size",
  12964.               remote,ftprecv.localsize);
  12965.                 return(1);
  12966.             }
  12967. #ifdef COMMENT
  12968. /*
  12969.   The problem here is that the original partial file never got its date
  12970.   set, either because FTP DATES was OFF, or because the partial file was
  12971.   downloaded by some other program that doesn't set local file dates, or
  12972.   because Kermit only sets the file's date when the download was complete
  12973.   and successful.  In all these cases, the local file has a later time
  12974.   than the remote.
  12975. */
  12976.             if (recover) {              /* Remote is bigger */
  12977.                 x = chkmodtime(local,remote,0); /* Check file dates */
  12978.                 debug(F111,"ftp recvrequest chkmodtime",remote,x);
  12979.                 if (x != 1)        /* Dates must be equal! */
  12980.                   recover = 0;          /* If not, get whole file */
  12981.             }
  12982. #endif /* COMMENT */
  12983.         }
  12984.         debug(F111,"ftp recvrequest recover",remote,recover);
  12985.     }
  12986.  
  12987. #ifdef FTP_PROXY
  12988.     if (proxy && ftprecv.is_retr)
  12989.       return(proxtrans(cmd, local ? local : remote, remote));
  12990. #endif /* FTP_PROXY */
  12991.  
  12992.     ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
  12993.  
  12994.     ftprecv.reply = 0;
  12995.     ftprecv.fcs = fcs;
  12996.     ftprecv.rcs = rcs;
  12997.     ftprecv.recover = recover;
  12998.     ftprecv.xlate = xlate;
  12999.     ftprecv.cmd = cmd;
  13000.     ftprecv.local = local;
  13001.     ftprecv.remote = remote;
  13002.     ftprecv.lmode = lmode;
  13003.     ftprecv.pipename = pipename;
  13004.     ftprecv.oldintp = NULL;
  13005.     ftpcode = 0;
  13006.  
  13007.     havesigint = 0;
  13008.     ftprecv.oldintr = signal(SIGINT, cancelrecv);
  13009.     if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
  13010.       return -1;
  13011.  
  13012. #ifdef FTP_TIMEOUT
  13013.     debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
  13014.     debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
  13015.     if (ftp_timed_out)
  13016.       ftprecvret = -1;
  13017. #endif    /* FTP_TIMEOUT */
  13018.  
  13019.     if (ftprecvret < 0)
  13020.       return -1;
  13021.  
  13022.     if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
  13023.       return -1;
  13024.     return ftprecvret;
  13025. }
  13026.  
  13027. /*
  13028.  * Need to start a listen on the data channel before we send the command,
  13029.  * otherwise the server's connect may fail.
  13030.  */
  13031. static int
  13032. initconn() {
  13033.     register char *p, *a;
  13034.     int result, tmpno = 0;
  13035.     int on = 1;
  13036.     GSOCKNAME_T len;
  13037.  
  13038. #ifndef NO_PASSIVE_MODE
  13039.     int a1,a2,a3,a4,p1,p2;
  13040.  
  13041.     if (passivemode) {
  13042.         data = socket(AF_INET, SOCK_STREAM, 0);
  13043.         globaldin = data;
  13044.         if (data < 0) {
  13045.             perror("ftp: socket");
  13046.             return(-1);
  13047.         }
  13048.         if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
  13049.             printf("Passive mode refused\n");
  13050.             passivemode = 0;
  13051.             return(initconn());
  13052.         }
  13053. /*
  13054.   Now we have a string of comma-separated one-byte unsigned integer values,
  13055.   The first four are the an IP address.  The fifth is the MSB of the port
  13056.   number, the sixth is the LSB.  From that we can make a sockaddr_in.
  13057. */
  13058.         if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
  13059.             printf("Passive mode address scan failure\n");
  13060.             return(-1);
  13061.         };
  13062. #ifndef NOHTTP
  13063.         if (tcp_http_proxy) {
  13064. #ifdef OS2
  13065.             char * agent = "Kermit 95"; /* Default user agent */
  13066. #else
  13067.             char * agent = "C-Kermit";
  13068. #endif /* OS2 */
  13069.             register struct hostent *hp = 0;
  13070.             struct servent *destsp;
  13071.             char host[512], *p, *q;
  13072. #ifdef IP_TOS
  13073. #ifdef IPTOS_THROUGHPUT
  13074.             int tos;
  13075. #endif /* IPTOS_THROUGHPUT */
  13076. #endif /* IP_TOS */
  13077.             int s;
  13078. #ifdef DEBUG
  13079.             extern int debtim;
  13080.             int xdebtim;
  13081.             xdebtim = debtim;
  13082.             debtim = 1;
  13083. #endif /* DEBUG */
  13084.  
  13085.             ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
  13086.                       ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
  13087.                       NULL,NULL,NULL
  13088.                       );
  13089.             memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
  13090.             for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
  13091.               *q = *p;
  13092.             *q = '\0';
  13093.  
  13094.             hisctladdr.sin_addr.s_addr = inet_addr(host);
  13095.             if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
  13096.         {
  13097.                 debug(F110,"initconn A",host,0);
  13098.                 hisctladdr.sin_family = AF_INET;
  13099.             } else {
  13100.                 debug(F110,"initconn B",host,0);
  13101.                 hp = gethostbyname(host);
  13102. #ifdef HADDRLIST
  13103.                 hp = ck_copyhostent(hp); /* make safe copy that won't change */
  13104. #endif /* HADDRLIST */
  13105.                 if (hp == NULL) {
  13106.                     fprintf(stderr, "ftp: %s: Unknown host\n", host);
  13107.                     ftpcode = -1;
  13108. #ifdef DEBUG
  13109.                     debtim = xdebtim;
  13110. #endif /* DEBUG */
  13111.                     return(0);
  13112.                 }
  13113.                 hisctladdr.sin_family = hp->h_addrtype;
  13114. #ifdef HADDRLIST
  13115.                 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
  13116.                        sizeof(hisctladdr.sin_addr));
  13117. #else /* HADDRLIST */
  13118.                 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
  13119.                        sizeof(hisctladdr.sin_addr));
  13120. #endif /* HADDRLIST */
  13121.             }
  13122.             data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  13123.             debug(F101,"initconn socket","",data);
  13124.             if (data < 0) {
  13125.                 perror("ftp: socket");
  13126.                 ftpcode = -1;
  13127. #ifdef DEBUG
  13128.                 debtim = xdebtim;
  13129. #endif /* DEBUG */
  13130.                 return(0);
  13131.             }
  13132.             if (*p == ':')
  13133.               p++;
  13134.             else
  13135.               p = "http";
  13136.  
  13137.             destsp = getservbyname(p,"tcp");
  13138.             if (destsp)
  13139.               hisctladdr.sin_port = destsp->s_port;
  13140.             else if (p)
  13141.               hisctladdr.sin_port = htons(atoi(p));
  13142.             else
  13143.               hisctladdr.sin_port = htons(80);
  13144.             errno = 0;
  13145. #ifdef HADDRLIST
  13146.             debug(F100,"initconn HADDRLIST","",0);
  13147.             while
  13148. #else
  13149.             debug(F100,"initconn no HADDRLIST","",0);
  13150.             if
  13151. #endif /* HADDRLIST */
  13152.               (connect(data, (struct sockaddr *)&hisctladdr,
  13153.                        sizeof (hisctladdr)) < 0) {
  13154.                   debug(F101,"initconn connect failed","",errno);
  13155. #ifdef HADDRLIST
  13156.                   if (hp && hp->h_addr_list[1]) {
  13157.                       int oerrno = errno;
  13158.  
  13159.                       fprintf(stderr,
  13160.                               "ftp: connect to address %s: ",
  13161.                               inet_ntoa(hisctladdr.sin_addr)
  13162.                               );
  13163.                       errno = oerrno;
  13164.                       perror((char *)0);
  13165.                       hp->h_addr_list++;
  13166.                       memcpy((char *)&hisctladdr.sin_addr,
  13167.                              hp->h_addr_list[0],
  13168.                              sizeof(hisctladdr.sin_addr));
  13169.                       fprintf(stdout, "Trying %s...\n",
  13170.                               inet_ntoa(hisctladdr.sin_addr));
  13171. #ifdef TCPIPLIB
  13172.                       socket_close(data);
  13173. #else /* TCPIPLIB */
  13174.                       close(data);
  13175. #endif /* TCPIPLIB */
  13176.                       data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  13177.                       if (data < 0) {
  13178.                           perror("ftp: socket");
  13179.                           ftpcode = -1;
  13180. #ifdef DEBUG
  13181.                           debtim = xdebtim;
  13182. #endif /* DEBUG */
  13183.                           return(0);
  13184.                       }
  13185.                       continue;
  13186.                   }
  13187. #endif /* HADDRLIST */
  13188.                   perror("ftp: connect");
  13189.                   ftpcode = -1;
  13190.                   goto bad;
  13191.               }
  13192.             if (http_connect(data,
  13193.                              tcp_http_proxy_agent ?
  13194.                    tcp_http_proxy_agent :
  13195.                      agent,
  13196.                  NULL,
  13197.                              tcp_http_proxy_user,
  13198.                              tcp_http_proxy_pwd,
  13199.                              0,
  13200.                              proxyhost
  13201.                              ) < 0) {
  13202. #ifdef TCPIPLIB
  13203.                 socket_close(data);
  13204. #else /* TCPIPLIB */
  13205.                 close(data);
  13206. #endif /* TCPIPLIB */
  13207.                 perror("ftp: connect");
  13208.                 ftpcode = -1;
  13209.                 goto bad;
  13210.             }
  13211.         } else
  13212. #endif /* NOHTTP */
  13213.         {
  13214.             data_addr.sin_family = AF_INET;
  13215.             data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
  13216.             data_addr.sin_port = htons((p1<<8)|p2);
  13217.  
  13218.             if (connect(data,
  13219.                         (struct sockaddr *)&data_addr,
  13220.                         sizeof(data_addr)) < 0
  13221.                 ) {
  13222.                 perror("ftp: connect");
  13223.                 return(-1);
  13224.             }
  13225.         }
  13226.         debug(F100,"initconn connect ok","",0);
  13227. #ifdef IP_TOS
  13228. #ifdef IPTOS_THROUGHPUT
  13229.         on = IPTOS_THROUGHPUT;
  13230.         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  13231.           perror("ftp: setsockopt TOS (ignored)");
  13232. #endif /* IPTOS_THROUGHPUT */
  13233. #endif /* IP_TOS */
  13234.         memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
  13235.         return(0);
  13236.     }
  13237. #endif /* NO_PASSIVE_MODE */
  13238.  
  13239.   noport:
  13240.     memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
  13241.     if (sendport)
  13242.       data_addr.sin_port = 0;   /* let system pick one */
  13243.     if (data != -1) {
  13244. #ifdef TCPIPLIB
  13245.         socket_close(data);
  13246. #else /* TCPIPLIB */
  13247. #ifdef USE_SHUTDOWN
  13248.         shutdown(data, 1+1);
  13249. #endif /* USE_SHUTDOWN */
  13250.         close(data);
  13251. #endif /* TCPIPLIB */
  13252.     }
  13253.     data = socket(AF_INET, SOCK_STREAM, 0);
  13254.     globaldin = data;
  13255.     if (data < 0) {
  13256.         perror("ftp: socket");
  13257.         if (tmpno)
  13258.           sendport = 1;
  13259.         return(-1);
  13260.     }
  13261.     if (!sendport) {
  13262.         if (setsockopt(data,
  13263.                        SOL_SOCKET,
  13264.                        SO_REUSEADDR,
  13265.                        (char *)&on,
  13266.                        sizeof (on)
  13267.                        ) < 0
  13268.             ) {
  13269.             perror("ftp: setsockopt (reuse address)");
  13270.             goto bad;
  13271.         }
  13272.     }
  13273.     if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
  13274.         perror("ftp: bind");
  13275.         goto bad;
  13276.     }
  13277.     len = sizeof (data_addr);
  13278.     if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
  13279.         perror("ftp: getsockname");
  13280.         goto bad;
  13281.     }
  13282.     if (listen(data, 1) < 0) {
  13283.         perror("ftp: listen");
  13284.         goto bad;
  13285.     }
  13286.     if (sendport) {
  13287.         a = (char *)&data_addr.sin_addr;
  13288.         p = (char *)&data_addr.sin_port;
  13289.         ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
  13290.                   UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
  13291.                   UC(p[0]),",", UC(p[1]));
  13292.         result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
  13293.         if (result == REPLY_ERROR && sendport) {
  13294.             sendport = 0;
  13295.             tmpno = 1;
  13296.             goto noport;
  13297.         }
  13298.         return(result != REPLY_COMPLETE);
  13299.     }
  13300.     if (tmpno)
  13301.       sendport = 1;
  13302. #ifdef IP_TOS
  13303. #ifdef IPTOS_THROUGHPUT
  13304.     on = IPTOS_THROUGHPUT;
  13305.     if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
  13306.       perror("ftp: setsockopt TOS (ignored)");
  13307. #endif
  13308. #endif
  13309.     return(0);
  13310.   bad:
  13311. #ifdef TCPIPLIB
  13312.     socket_close(data);
  13313. #else /* TCPIPLIB */
  13314. #ifdef USE_SHUTDOWN
  13315.     shutdown(data, 1+1);
  13316. #endif /* USE_SHUTDOWN */
  13317.     close(data);
  13318. #endif /* TCPIPLIB */
  13319.     data = -1;
  13320.     globaldin = data;
  13321.     if (tmpno)
  13322.       sendport = 1;
  13323.     return(-1);
  13324. }
  13325.  
  13326. #ifdef CK_SSL
  13327. static int
  13328. ssl_dataconn() {
  13329.     if (ssl_ftp_data_con!=NULL) {       /* Do SSL */
  13330.         SSL_free(ssl_ftp_data_con);
  13331.         ssl_ftp_data_con=NULL;
  13332.     }
  13333.     ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
  13334.  
  13335.     SSL_set_fd(ssl_ftp_data_con,data);
  13336.     SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
  13337.  
  13338.     SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
  13339.  
  13340.     if (ssl_debug_flag) {
  13341.         fprintf(stderr,"=>START SSL connect on DATA\n");
  13342.         fflush(stderr);
  13343.     }
  13344.     if (SSL_connect(ssl_ftp_data_con) <= 0) {
  13345.         static char errbuf[1024];
  13346.         ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
  13347.                   ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
  13348.         fprintf(stderr,"%s\n", errbuf);
  13349.         fflush(stderr);
  13350. #ifdef TCPIPLIB
  13351.         socket_close(data);
  13352. #else /* TCPIPLIB */
  13353. #ifdef USE_SHUTDOWN
  13354.         shutdown(data, 1+1);
  13355. #endif /* USE_SHUTDOWN */
  13356.         close(data);
  13357. #endif /* TCPIPLIB */
  13358.         data = -1;
  13359.         globaldin = data;
  13360.         return(-1);
  13361.     } else {
  13362.         ssl_ftp_data_active_flag=1;
  13363.  
  13364.         if (!ssl_certsok_flag && !tls_is_krb5(2)) {
  13365.             char *subject = ssl_get_subject_name(ssl_ftp_data_con);
  13366.  
  13367.             if (!subject) {
  13368.                 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
  13369.                     debug(F110,"dataconn","[SSL _- FAILED]",0);
  13370.  
  13371.                     ssl_ftp_data_active_flag = 0;
  13372. #ifdef TCPIPLIB
  13373.                     socket_close(data);
  13374. #else /* TCPIPLIB */
  13375. #ifdef USE_SHUTDOWN
  13376.                     shutdown(data, 1+1);
  13377. #endif /* USE_SHUTDOWN */
  13378.                     close(data);
  13379. #endif /* TCPIPLIB */
  13380.                     data = -1;
  13381.                     globaldin = data;
  13382.                     return(-1);
  13383.                 } else {
  13384.                     if (!out2screen && displa && fdispla) {
  13385.                         ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
  13386.                         /* fdispla = XYFD_B; */
  13387.                     }
  13388.  
  13389.                     if (uq_ok(
  13390.           "Warning: Server didn't provide a certificate on data connection\n",
  13391.                                "Continue with file transfer? (Y/N)",
  13392.                               3,NULL,0) <= 0) {
  13393.                         debug(F110, "dataconn","[SSL - FAILED]",0);
  13394.                         ssl_ftp_data_active_flag = 0;
  13395. #ifdef TCPIPLIB
  13396.                         socket_close(data);
  13397. #else /* TCPIPLIB */
  13398. #ifdef USE_SHUTDOWN
  13399.                         shutdown(data, 1+1);
  13400. #endif /* USE_SHUTDOWN */
  13401.                         close(data);
  13402. #endif /* TCPIPLIB */
  13403.                         data = -1;
  13404.                         globaldin = data;
  13405.                         return(-1);
  13406.                     }
  13407.                 }
  13408.             } else {
  13409.                 if (!out2screen && displa && fdispla == XYFD_C) {
  13410.                     ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
  13411.                     /* fdispla = XYFD_B; */
  13412.                 }
  13413.  
  13414.                 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
  13415.                     debug(F110,"dataconn","[SSL - FAILED]",0);
  13416.                     ssl_ftp_data_active_flag = 0;
  13417. #ifdef TCPIPLIB
  13418.                     socket_close(data);
  13419. #else /* TCPIPLIB */
  13420. #ifdef USE_SHUTDOWN
  13421.                     shutdown(data, 1+1);
  13422. #endif /* USE_SHUTDOWN */
  13423.                     close(data);
  13424. #endif /* TCPIPLIB */
  13425.                     data = -1;
  13426.                     globaldin = data;
  13427.                     return(-1);
  13428.                 }
  13429.             }
  13430.         }
  13431.         debug(F110,"dataconn","[SSL - OK]",0);
  13432. #ifdef COMMENT
  13433.         /* This messes up the full screen file transfer display */
  13434.         ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
  13435. #endif /* COMMENT */
  13436.     }
  13437.     if (ssl_debug_flag) {
  13438.         fprintf(stderr,"=>DONE SSL connect on DATA\n");
  13439.         fflush(stderr);
  13440.     }
  13441.     return(data);
  13442. }
  13443. #endif /* CK_SSL */
  13444.  
  13445. static int
  13446. dataconn(lmode) char *lmode; {
  13447.     int s;
  13448. #ifdef IP_TOS
  13449.     int tos;
  13450. #endif /* IP_TOS */
  13451. #ifdef UCX50
  13452.     static u_int fromlen;
  13453. #else
  13454.     static SOCKOPT_T fromlen;
  13455. #endif /* UCX50 */
  13456.  
  13457.     fromlen = sizeof(hisdataaddr);
  13458.  
  13459. #ifndef NO_PASSIVE_MODE
  13460.     if (passivemode) {
  13461. #ifdef CK_SSL
  13462.         ssl_ftp_data_active_flag=0;
  13463.         if (ssl_ftp_active_flag &&
  13464.             (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
  13465.           return(ssl_dataconn());
  13466. #endif /* CK_SSL */
  13467.         return(data);
  13468.     }
  13469. #endif /* NO_PASSIVE_MODE */
  13470.  
  13471.     s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
  13472.     if (s < 0) {
  13473.         perror("ftp: accept");
  13474. #ifdef TCPIPLIB
  13475.         socket_close(data);
  13476. #else /* TCPIPLIB */
  13477. #ifdef USE_SHUTDOWN
  13478.         shutdown(data, 1+1);
  13479. #endif /* USE_SHUTDOWN */
  13480.         close(data);
  13481. #endif /* TCPIPLIB */
  13482.         data = -1;
  13483.         globaldin = data;
  13484.         return(-1);
  13485.     }
  13486. #ifdef TCPIPLIB
  13487.     socket_close(data);
  13488. #else /* TCPIPLIB */
  13489. #ifdef USE_SHUTDOWN
  13490.     shutdown(data, 1+1);
  13491. #endif /* USE_SHUTDOWN */
  13492.     close(data);
  13493. #endif /* TCPIPLIB */
  13494.     data = s;
  13495.     globaldin = data;
  13496. #ifdef IP_TOS
  13497. #ifdef IPTOS_THROUGHPUT
  13498.     tos = IPTOS_THROUGHPUT;
  13499.     if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  13500.       perror("ftp: setsockopt TOS (ignored)");
  13501. #endif /* IPTOS_THROUGHPUT */
  13502. #endif /* IP_TOS */
  13503.  
  13504. #ifdef CK_SSL
  13505.     ssl_ftp_data_active_flag=0;
  13506.     if (ssl_ftp_active_flag &&
  13507.         (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
  13508.       return(ssl_dataconn());
  13509. #endif /* CK_SSL */
  13510.     return(data);
  13511. }
  13512.  
  13513. #ifdef FTP_PROXY
  13514. static sigtype
  13515. pscancel(sig) int sig; {
  13516.     cancelfile++;
  13517. }
  13518.  
  13519. static VOID
  13520. pswitch(flag) int flag; {
  13521.     extern int proxy;
  13522.     sig_t oldintr;
  13523.     static struct comvars {
  13524.         int connect;
  13525.         char name[MAXHOSTNAMELEN];
  13526.         struct sockaddr_in mctl;
  13527.         struct sockaddr_in hctl;
  13528.         FILE *in;
  13529.         FILE *out;
  13530.         int tpe;
  13531.         int curtpe;
  13532.         int cpnd;
  13533.         int sunqe;
  13534.         int runqe;
  13535.         int mcse;
  13536.         int ntflg;
  13537.         char nti[17];
  13538.         char nto[17];
  13539.         int mapflg;
  13540.         char mi[CKMAXPATH];
  13541.         char mo[CKMAXPATH];
  13542.         char *authtype;
  13543.         int clvl;
  13544.         int dlvl;
  13545. #ifdef FTP_KRB4
  13546.         des_cblock session;
  13547.         des_key_schedule ftp_sched;
  13548. #endif /* FTP_KRB4 */
  13549. #ifdef FTP_GSSAPI
  13550.         gss_ctx_id_t gcontext;
  13551. #endif /* GSSAPI */
  13552.     } proxstruct, tmpstruct;
  13553.     struct comvars *ip, *op;
  13554.  
  13555.     cancelfile = 0;
  13556.     oldintr = signal(SIGINT, pscancel);
  13557.     if (flag) {
  13558.         if (proxy)
  13559.           return;
  13560.         ip = &tmpstruct;
  13561.         op = &proxstruct;
  13562.         proxy++;
  13563.     } else {
  13564.         if (!proxy)
  13565.           return;
  13566.         ip = &proxstruct;
  13567.         op = &tmpstruct;
  13568.         proxy = 0;
  13569.     }
  13570.     ip->connect = connected;
  13571.     connected = op->connect;
  13572.     if (ftp_host) {
  13573.         strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
  13574.         ip->name[MAXHOSTNAMELEN - 1] = '\0';
  13575.         ip->name[strlen(ip->name)] = '\0';
  13576.     } else
  13577.       ip->name[0] = 0;
  13578.     ftp_host = op->name;
  13579.     ip->hctl = hisctladdr;
  13580.     hisctladdr = op->hctl;
  13581.     ip->mctl = myctladdr;
  13582.     myctladdr = op->mctl;
  13583.     ip->in = csocket;
  13584.     csocket = op->in;
  13585.     ip->out = csocket;
  13586.     csocket = op->out;
  13587.     ip->tpe = ftp_typ;
  13588.     ftp_typ = op->tpe;
  13589.     ip->curtpe = curtype;
  13590.     curtype = op->curtpe;
  13591.     ip->cpnd = cpend;
  13592.     cpend = op->cpnd;
  13593.     ip->sunqe = ftp_usn;
  13594.     ftp_usn = op->sunqe;
  13595.     ip->mcse = mcase;
  13596.     mcase = op->mcse;
  13597.     ip->ntflg = ntflag;
  13598.     ntflag = op->ntflg;
  13599.     strncpy(ip->nti, ntin, 16);
  13600.     (ip->nti)[strlen(ip->nti)] = '\0';
  13601.     strcpy(ntin, op->nti);
  13602.     strncpy(ip->nto, ntout, 16);
  13603.     (ip->nto)[strlen(ip->nto)] = '\0';
  13604.     strcpy(ntout, op->nto);
  13605.     ip->mapflg = mapflag;
  13606.     mapflag = op->mapflg;
  13607.     strncpy(ip->mi, mapin, CKMAXPATH - 1);
  13608.     (ip->mi)[strlen(ip->mi)] = '\0';
  13609.     strcpy(mapin, op->mi);
  13610.     strncpy(ip->mo, mapout, CKMAXPATH - 1);
  13611.     (ip->mo)[strlen(ip->mo)] = '\0';
  13612.     strcpy(mapout, op->mo);
  13613.     ip->authtype = auth_type;
  13614.     auth_type = op->authtype;
  13615.     ip->clvl = ftp_cpl;
  13616.     ftp_cpl = op->clvl;
  13617.     ip->dlvl = ftp_dpl;
  13618.     ftp_dpl = op->dlvl;
  13619.     if (!ftp_cpl)
  13620.       ftp_cpl = FPL_CLR;
  13621.     if (!ftp_dpl)
  13622.       ftp_dpl = FPL_CLR;
  13623. #ifdef FTP_KRB4
  13624.     memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
  13625.     memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
  13626.     memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
  13627.     memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
  13628. #endif /* FTP_KRB4 */
  13629. #ifdef FTP_GSSAPI
  13630.     ip->gcontext = gcontext;
  13631.     gcontext = op->gcontext;
  13632. #endif /* GSSAPI */
  13633.     signal(SIGINT, oldintr);
  13634.     if (cancelfile) {
  13635.         cancelfile = 0;
  13636.         debug(F101,"pswitch cancelfile B","",cancelfile);
  13637.         (*oldintr)(SIGINT);
  13638.     }
  13639. }
  13640.  
  13641. static sigtype
  13642. cancelpt(sig) int sig; {
  13643.     printf("\n");
  13644.     fflush(stdout);
  13645.     ptabflg++;
  13646.     cancelfile = 0;
  13647. #ifndef OS2
  13648.     longjmp(ptcancel, 1);
  13649. #else
  13650.     PostCtrlCSem();
  13651. #endif /* OS2 */
  13652. }
  13653.  
  13654. void
  13655. proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
  13656.     sig_t oldintr;
  13657.     int secndflag = 0, prox_type, nfnd;
  13658.     char *cmd2;
  13659. #ifdef BSDSELECT
  13660.     fd_set mask;
  13661. #endif /* BSDSELECT */
  13662.     sigtype cancelpt();
  13663.  
  13664.     if (strcmp(cmd, "RETR"))
  13665.       cmd2 = "RETR";
  13666.     else
  13667.       cmd2 = unique ? "STOU" : "STOR";
  13668.     if ((prox_type = type) == 0) {
  13669.         if (servertype == SYS_UNIX && unix_proxy)
  13670.           prox_type = FTT_BIN;
  13671.         else
  13672.           prox_type = FTT_ASC;
  13673.     }
  13674.     if (curtype != prox_type)
  13675.       changetype(prox_type, 1);
  13676.     if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
  13677.         printf("Proxy server does not support third party transfers.\n");
  13678.         return;
  13679.     }
  13680.     pswitch(0);
  13681.     if (!connected) {
  13682.         printf("No primary connection\n");
  13683.         pswitch(1);
  13684.         ftpcode = -1;
  13685.         return;
  13686.     }
  13687.     if (curtype != prox_type)
  13688.       changetype(prox_type, 1);
  13689.  
  13690.     if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
  13691.         pswitch(1);
  13692.         return;
  13693.     }
  13694.  
  13695.     /* Replace with calls to cc_execute() */
  13696.     if (setjmp(ptcancel))
  13697.       goto cancel;
  13698.     oldintr = signal(SIGINT, cancelpt);
  13699.     if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
  13700.         signal(SIGINT, oldintr);
  13701.         pswitch(1);
  13702.         return;
  13703.     }
  13704.     sleep(2000);
  13705.     pswitch(1);
  13706.     secndflag++;
  13707.     if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
  13708.       goto cancel;
  13709.     ptflag++;
  13710.     getreply(0,-1,-1,ftp_vbm,0);
  13711.     pswitch(0);
  13712.     getreply(0,-1,-1,ftp_vbm,0);
  13713.     signal(SIGINT, oldintr);
  13714.     pswitch(1);
  13715.     ptflag = 0;
  13716.     return;
  13717.  
  13718.   cancel:
  13719.     signal(SIGINT, SIG_IGN);
  13720.     ptflag = 0;
  13721.     if (strcmp(cmd, "RETR") && !proxy)
  13722.       pswitch(1);
  13723.     else if (!strcmp(cmd, "RETR") && proxy)
  13724.       pswitch(0);
  13725.     if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
  13726.         if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
  13727.             pswitch(0);
  13728.             if (cpend)
  13729.               cancel_remote(0);
  13730.         }
  13731.         pswitch(1);
  13732.         if (ptabflg)
  13733.           ftpcode = -1;
  13734.         signal(SIGINT, oldintr);
  13735.         return;
  13736.     }
  13737.     if (cpend)
  13738.       cancel_remote(0);
  13739.     pswitch(!proxy);
  13740.     if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
  13741.         if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
  13742.             pswitch(0);
  13743.             if (cpend)
  13744.               cancel_remote(0);
  13745.             pswitch(1);
  13746.             if (ptabflg)
  13747.               ftpcode = -1;
  13748.             signal(SIGINT, oldintr);
  13749.             return;
  13750.         }
  13751.     }
  13752.     if (cpend)
  13753.       cancel_remote(0);
  13754.     pswitch(!proxy);
  13755.     if (cpend) {
  13756. #ifdef BSDSELECT
  13757.         FD_ZERO(&mask);
  13758.         FD_SET(csocket, &mask);
  13759.         if ((nfnd = empty(&mask, 10)) <= 0) {
  13760.             if (nfnd < 0) {
  13761.                 perror("cancel");
  13762.             }
  13763.             if (ptabflg)
  13764.               ftpcode = -1;
  13765.             lostpeer();
  13766.         }
  13767. #else /* BSDSELECT */
  13768. #ifdef IBMSELECT
  13769.         if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
  13770.             if (nfnd < 0) {
  13771.                 perror("cancel");
  13772.             }
  13773.             if (ptabflg)
  13774.               ftpcode = -1;
  13775.             lostpeer();
  13776.         }
  13777. #endif /* IBMSELECT */
  13778. #endif /* BSDSELECT */
  13779.         getreply(0,-1,-1,ftp_vbm,0);
  13780.         getreply(0,-1,-1,ftp_vbm,0);
  13781.     }
  13782.     if (proxy)
  13783.       pswitch(0);
  13784.     pswitch(1);
  13785.     if (ptabflg)
  13786.       ftpcode = -1;
  13787.     signal(SIGINT, oldintr);
  13788. }
  13789. #endif /* FTP_PROXY */
  13790.  
  13791. #ifdef FTP_SECURITY
  13792. #ifdef FTP_GSSAPI
  13793.  
  13794. #ifdef COMMENT
  13795. /* ck_gss_mech_krb5 is not declared anywhere */
  13796. struct {
  13797.     CONST gss_OID_desc * CONST * mech_type;
  13798.     char *service_name;
  13799. } gss_trials[] = {
  13800.     { &ck_gss_mech_krb5, "ftp" },
  13801.     { &ck_gss_mech_krb5, "host" },
  13802. };
  13803. #else
  13804. /* This matches what is declared above */
  13805. struct {
  13806.     CONST gss_OID_desc * CONST * mech_type;
  13807.     char *service_name;
  13808. } gss_trials[] = {
  13809.     { &gss_mech_krb5, "ftp" },
  13810.     { &gss_mech_krb5, "host" },
  13811. };
  13812. #endif    /* COMMENT */
  13813.  
  13814.  
  13815. int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
  13816. #endif /* FTP_GSSAPI */
  13817.  
  13818. static int
  13819. ftp_auth() {
  13820.     extern int setsafe();
  13821.     int j = 0, n;
  13822. #ifdef FTP_KRB4
  13823.     char *service, inst[INST_SZ];
  13824.     ULONG cksum;
  13825.     ULONG checksum = (ULONG) getpid();
  13826.     CHAR out_buf[FTP_BUFSIZ];
  13827.     int i;
  13828. #else /* FTP_KRB4 */
  13829. #ifdef FTP_GSSAPI
  13830.     CHAR out_buf[FTP_BUFSIZ];
  13831.     int i;
  13832. #endif /* FTP_GSSAPI */
  13833. #endif /* FTP_KRB4 */
  13834.  
  13835.     if (ssl_ftp_proxy)                  /* Do not allow AUTH over SSL proxy */
  13836.         return(0);
  13837.  
  13838.     if (auth_type)
  13839.       return(1);                        /* auth already succeeded */
  13840.  
  13841.     /* Try each auth type as specified by the end user */
  13842.     for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
  13843. #ifdef FTP_GSSAPI
  13844.         if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
  13845.             n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
  13846.             if (n == REPLY_CONTINUE) {
  13847.                 OM_uint32 maj_stat, min_stat;
  13848.                 gss_name_t target_name;
  13849.                 gss_buffer_desc send_tok, recv_tok, *token_ptr;
  13850.                 char stbuf[FTP_BUFSIZ];
  13851.                 int comcode, trial;
  13852.                 struct gss_channel_bindings_struct chan;
  13853.                 char * realm = NULL;
  13854.                 char tgt[256];
  13855.  
  13856.                 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */
  13857.                 chan.initiator_address.length = 4;
  13858.                 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
  13859.                 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
  13860.                 chan.acceptor_address.length = 4;
  13861.                 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
  13862.                 chan.application_data.length = 0;
  13863.                 chan.application_data.value = 0;
  13864.  
  13865.                 if (!quiet)
  13866.                   printf("GSSAPI accepted as authentication type\n");
  13867.  
  13868.                 realm = ck_krb5_realmofhost(ftp_user_host);
  13869.                 if (realm) {
  13870.                     ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
  13871.                     debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
  13872.                     if ( krb5_autoget &&
  13873.                          !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
  13874.                             (ck_krb5_is_tgt_valid() > 0)) )
  13875.                         ck_krb5_autoget_TGT(realm);
  13876.                 }
  13877.  
  13878.                 /* Blob from gss-client */
  13879.                 for (trial = 0; trial < n_gss_trials; trial++) {
  13880.                     /* ftp@hostname first, the host@hostname */
  13881.                     /* the V5 GSSAPI binding canonicalizes this for us... */
  13882.                     ckmakmsg(stbuf,FTP_BUFSIZ,
  13883.                              gss_trials[trial].service_name,
  13884.                              "@",
  13885.                              ftp_user_host,
  13886.                              NULL
  13887.                              );
  13888.                     if (ftp_deb)
  13889.                       fprintf(stderr,
  13890.                               "Authenticating to <%s>...\n", stbuf);
  13891.                     send_tok.value = stbuf;
  13892.                     send_tok.length = strlen(stbuf);
  13893.                     maj_stat = gss_import_name(&min_stat, &send_tok,
  13894.                                                gss_nt_service_name,
  13895.                                                &target_name
  13896.                                                );
  13897.                     if (maj_stat != GSS_S_COMPLETE) {
  13898.                         user_gss_error(maj_stat, min_stat, "parsing name");
  13899.                         secure_error("name parsed <%s>\n", stbuf);
  13900.                         continue;
  13901.                     }
  13902.                     token_ptr = GSS_C_NO_BUFFER;
  13903.                     gcontext = GSS_C_NO_CONTEXT; /* structure copy */
  13904.  
  13905.                     do {
  13906.                         if (ftp_deb)
  13907.                           fprintf(stderr, "calling gss_init_sec_context\n");
  13908.                         maj_stat =
  13909.                           gss_init_sec_context(&min_stat,
  13910.                                                GSS_C_NO_CREDENTIAL,
  13911.                                                &gcontext,
  13912.                                                target_name,
  13913.                                                (gss_OID) *
  13914.                                                  gss_trials[trial].mech_type,
  13915.                                                GSS_C_MUTUAL_FLAG |
  13916.                                                GSS_C_REPLAY_FLAG |
  13917.                                                (ftp_cfw ?
  13918.                                                 GSS_C_DELEG_FLAG : 0),
  13919.                                                0,
  13920.                                                 /* channel bindings */
  13921.                                                 (krb5_d_no_addresses ?
  13922.                                                   GSS_C_NO_CHANNEL_BINDINGS :
  13923.                                                   &chan),
  13924.                                                 token_ptr,
  13925.                                                NULL,    /* ignore mech type */
  13926.                                                &send_tok,
  13927.                                                NULL,    /* ignore ret_flags */
  13928.                                                NULL
  13929.                                                );       /* ignore time_rec */
  13930.  
  13931.                         if (maj_stat != GSS_S_COMPLETE &&
  13932.                             maj_stat != GSS_S_CONTINUE_NEEDED) {
  13933.                             if (trial == n_gss_trials-1)
  13934.                               user_gss_error(maj_stat,
  13935.                                              min_stat,
  13936.                                              "initializing context"
  13937.                                              );
  13938.                             gss_release_name(&min_stat, &target_name);
  13939.                             /* maybe we missed on the service name */
  13940.                             goto outer_loop;
  13941.                         }
  13942.                         if (send_tok.length != 0) {
  13943.                             int len;
  13944.                             reply_parse = "ADAT="; /* for ftpcmd() later */
  13945.                             len = FTP_BUFSIZ;
  13946.                             kerror =
  13947.                               radix_encode(send_tok.value,
  13948.                                            out_buf,
  13949.                                            send_tok.length,
  13950.                                            &len,
  13951.                                            RADIX_ENCODE
  13952.                                            );
  13953.                             if (kerror)  {
  13954.                                 fprintf(stderr,
  13955.                                         "Base 64 encoding failed: %s\n",
  13956.                                         radix_error(kerror)
  13957.                                         );
  13958.                                 goto gss_complete_loop;
  13959.                             }
  13960.                             comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
  13961.                             if (comcode != REPLY_COMPLETE
  13962.                                 && comcode != REPLY_CONTINUE /* (335) */
  13963.                                 ) {
  13964.                                 if (trial == n_gss_trials-1) {
  13965.                                     fprintf(stderr, "GSSAPI ADAT failed\n");
  13966.                                     /* force out of loop */
  13967.                                     maj_stat = GSS_S_FAILURE;
  13968.                                 }
  13969.                                 /*
  13970.                                   Backoff to the v1 gssapi is still possible.
  13971.                                   Send a new AUTH command.  If that fails,
  13972.                                   terminate the loop.
  13973.                                 */
  13974.                                 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
  13975.                                     != REPLY_CONTINUE) {
  13976.                                     fprintf(stderr,
  13977.                                 "GSSAPI ADAT failed, AUTH restart failed\n");
  13978.                                     /* force out of loop */
  13979.                                     maj_stat = GSS_S_FAILURE;
  13980.                                 }
  13981.                                 goto outer_loop;
  13982.                             }
  13983.                             if (!reply_parse) {
  13984.                                 fprintf(stderr,
  13985.                               "No authentication data received from server\n");
  13986.                                 if (maj_stat == GSS_S_COMPLETE) {
  13987.                                     fprintf(stderr,
  13988.                                             "...but no more was needed\n");
  13989.                                     goto gss_complete_loop;
  13990.                                 } else {
  13991.                                     user_gss_error(maj_stat,
  13992.                                                    min_stat,
  13993.                                                    "no reply, huh?"
  13994.                                                    );
  13995.                                     goto gss_complete_loop;
  13996.                                 }
  13997.                             }
  13998.                             len = FTP_BUFSIZ;
  13999.                             kerror = radix_encode(reply_parse,out_buf,i,&len,
  14000.                                                   RADIX_DECODE);
  14001.                             if (kerror) {
  14002.                                 fprintf(stderr,
  14003.                                         "Base 64 decoding failed: %s\n",
  14004.                                         radix_error(kerror));
  14005.                                 goto gss_complete_loop;
  14006.                             }
  14007.  
  14008.                             /* everything worked */
  14009.                             token_ptr = &recv_tok;
  14010.                             recv_tok.value = out_buf;
  14011.                             recv_tok.length = len;
  14012.                             continue;
  14013.  
  14014.                             /* get out of loop clean */
  14015.                           gss_complete_loop:
  14016.                             trial = n_gss_trials-1;
  14017.                             gss_release_buffer(&min_stat, &send_tok);
  14018.                             gss_release_name(&min_stat, &target_name);
  14019.                             goto outer_loop;
  14020.                         }
  14021.                     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
  14022.  
  14023.                   outer_loop:
  14024.                     if (maj_stat == GSS_S_COMPLETE)
  14025.                       break;
  14026.                 }
  14027.                 if (maj_stat == GSS_S_COMPLETE) {
  14028.                     printf("GSSAPI authentication succeeded\n");
  14029.                     reply_parse = NULL;
  14030.                     auth_type = "GSSAPI";
  14031.                     return(1);
  14032.                 } else {
  14033.                     fprintf(stderr, "GSSAPI authentication failed\n");
  14034.                     reply_parse = NULL;
  14035.                 }
  14036.             } else {
  14037.                 if (ftp_deb)
  14038.                 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
  14039.                 if (ftpcode == 500 || ftpcode == 502)
  14040.                     return(0);
  14041.             }
  14042.         }
  14043. #endif /* FTP_GSSAPI */
  14044. #ifdef FTP_SRP
  14045.         if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
  14046.             if (srp_ftp_auth(ftp_user_host,NULL,NULL))
  14047.               return(1);
  14048.             else if (ftpcode == 500 || ftpcode == 502)
  14049.               return(0);
  14050.         }
  14051. #endif /* FTP_SRP */
  14052. #ifdef FTP_KRB4
  14053.         if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
  14054.             n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
  14055.             if (n == REPLY_CONTINUE) {
  14056.                 char tgt[4*REALM_SZ+1];
  14057.                 int rc;
  14058.  
  14059.                 if (!quiet)
  14060.                   printf("KERBEROS_V4 accepted as authentication type\n");
  14061.                 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
  14062.                 ckstrncpy(ftp_realm,
  14063.                           (char *)ck_krb4_realmofhost(ftp_user_host),
  14064.                           REALM_SZ
  14065.                           );
  14066.  
  14067.                 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
  14068.                 rc = ck_krb4_tkt_isvalid(tgt);
  14069.  
  14070.                 if (rc <= 0 && krb4_autoget)
  14071.                   ck_krb4_autoget_TGT(ftp_realm);
  14072.  
  14073.                 service = "ftp";
  14074.                 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
  14075.                 if (kerror == KDC_PR_UNKNOWN) {
  14076.                     service = "rcmd";
  14077.                     kerror = krb_mk_req(&ftp_tkt,
  14078.                                         service,
  14079.                                         inst,
  14080.                                         ftp_realm,
  14081.                                         checksum
  14082.                                         );
  14083.                 }
  14084.                 if (kerror)
  14085.                   fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
  14086.                           krb_get_err_text(kerror));
  14087.                 if (!kerror) {
  14088.                     kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
  14089.                     if (kerror)
  14090.                       fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
  14091.                               krb_get_err_text(kerror));
  14092.                 }
  14093.                 if (!kerror) {
  14094.                     int rc;
  14095.                     rc = des_key_sched(ftp_cred.session, ftp_sched);
  14096.                     if (rc == -1) {
  14097.                        printf("?Invalid DES key specified in credentials\r\n");
  14098.                        debug(F110,"ftp_auth",
  14099.                              "invalid DES Key specified in credentials",0);
  14100.                     } else if ( rc == -2 ) {
  14101.                         printf("?Weak DES key specified in credentials\r\n");
  14102.                         debug(F110,"ftp_auth",
  14103.                               "weak DES Key specified in credentials",0);
  14104.                     } else if ( rc != 0 ) {
  14105.                         printf("?DES Key Schedule not set by credentials\r\n");
  14106.                         debug(F110,"ftp_auth",
  14107.                               "DES Key Schedule not set by credentials",0);
  14108.                     }
  14109.                     reply_parse = "ADAT=";
  14110.                     i = FTP_BUFSIZ;
  14111.                     kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
  14112.                                           &i, RADIX_ENCODE);
  14113.                     if (kerror) {
  14114.                         fprintf(stderr, "Base 64 encoding failed: %s\n",
  14115.                                 radix_error(kerror));
  14116.                         goto krb4_err;
  14117.                     }
  14118.                     if (i > FTP_BUFSIZ - 6)
  14119.                       printf("?ADAT data too long\n");
  14120.                     if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
  14121.                         REPLY_COMPLETE) {
  14122.                         fprintf(stderr, "Kerberos V4 authentication failed\n");
  14123.                         goto krb4_err;
  14124.                     }
  14125.                     if (!reply_parse) {
  14126.                         fprintf(stderr,
  14127.                              "No authentication data received from server\n");
  14128.                         goto krb4_err;
  14129.                     }
  14130.                     i = sizeof(out_buf);
  14131.                     kerror =
  14132.                       radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
  14133.                     if (kerror) {
  14134.                         fprintf(stderr, "Base 64 decoding failed: %s\n",
  14135.                                 radix_error(kerror));
  14136.                         goto krb4_err;
  14137.                     }
  14138.                     kerror = krb_rd_safe(out_buf, i,
  14139. #ifdef KRB524
  14140.                                          ftp_cred.session,
  14141. #else /* KRB524 */
  14142.                                          &ftp_cred.session,
  14143. #endif /* KRB524 */
  14144.                                          &hisctladdr,
  14145.                                          &myctladdr,
  14146.                                          &ftp_msg_data
  14147.                                          );
  14148.                     if (kerror) {
  14149.                         fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
  14150.                                 krb_get_err_text(kerror));
  14151.                         goto krb4_err;
  14152.                     }
  14153.  
  14154.                     /* fetch the (modified) checksum */
  14155.                     memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
  14156.                     if (ntohl(cksum) == checksum + 1) {
  14157.                         if (ftp_vbm)
  14158.                           printf("Kerberos V4 authentication succeeded\n");
  14159.                         reply_parse = NULL;
  14160.                         auth_type = "KERBEROS_V4";
  14161.                         return(1);
  14162.                     } else
  14163.                       fprintf(stderr,
  14164.                               "Kerberos V4 mutual authentication failed\n");
  14165.                   krb4_err:
  14166.                     reply_parse = NULL;
  14167.                 }
  14168.             } else {
  14169.                 if (ftp_deb)
  14170.           fprintf(stderr,
  14171.                       "KERBEROS_V4 rejected as an authentication type\n");
  14172.                 if (ftpcode == 500 || ftpcode == 502)
  14173.                     return(0);
  14174.             }
  14175.         }
  14176. #endif /* FTP_KRB4 */
  14177. #ifdef CK_SSL
  14178.         if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
  14179. #ifdef FTPHOST
  14180.             if (!hostcmd) {
  14181.                 ftpcmd("HOST",ftp_user_host,0,0,0);
  14182.                 hostcmd = 1;
  14183.             }
  14184. #endif /* FTPHOST */
  14185.             n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
  14186.             if (n != REPLY_COMPLETE)
  14187.               n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
  14188.             if (n == REPLY_COMPLETE) {
  14189.                 if (!quiet)
  14190.                   printf("TLS accepted as authentication type\n");
  14191.  
  14192.                 auth_type = "TLS";
  14193.                 ssl_auth();
  14194.                 if (ssl_ftp_active_flag ) {
  14195.                     ftp_dpl = FPL_CLR;
  14196.                     ftp_cpl = FPL_PRV;
  14197.                     return(1);
  14198.                 } else {
  14199.                     fprintf(stderr,"TLS authentication failed\n");
  14200.                     auth_type = NULL;
  14201. #ifdef TCPIPLIB
  14202.                     socket_close(csocket);
  14203. #else /* TCPIPLIB */
  14204. #ifdef USE_SHUTDOWN
  14205.                     shutdown(csocket, 1+1);
  14206. #endif /* USE_SHUTDOWN */
  14207.                     close(csocket);
  14208. #endif /* TCPIPLIB */
  14209.                     csocket = -1;
  14210.                     if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
  14211.                       return(0);
  14212.                 }
  14213.             } else {
  14214.                 if (ftp_deb)
  14215.           fprintf(stderr,"TLS rejected as an authentication type\n");
  14216.                 if (ftpcode == 500 || ftpcode == 502)
  14217.                     return(0);
  14218.             }
  14219.         }
  14220.         if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
  14221. #ifdef FTPHOST
  14222.             if (!hostcmd) {
  14223.                 ftpcmd("HOST",ftp_user_host,0,0,0);
  14224.                 hostcmd = 1;
  14225.             }
  14226. #endif /* FTPHOST */
  14227.             n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
  14228.             if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
  14229.                 if (!quiet)
  14230.                   printf("SSL accepted as authentication type\n");
  14231.                 auth_type = "SSL";
  14232.                 ssl_auth();
  14233.                 if (ssl_ftp_active_flag) {
  14234.                     ftp_dpl = FPL_PRV;
  14235.                     ftp_cpl = FPL_PRV;
  14236.                     setprotbuf(1<<20);
  14237.                     return(1);
  14238.                 } else {
  14239.                     fprintf(stderr,"SSL authentication failed\n");
  14240.                     auth_type = NULL;
  14241. #ifdef TCPIPLIB
  14242.                     socket_close(csocket);
  14243. #else /* TCPIPLIB */
  14244. #ifdef USE_SHUTDOWN
  14245.                     shutdown(csocket, 1+1);
  14246. #endif /* USE_SHUTDOWN */
  14247.                     close(csocket);
  14248. #endif /* TCPIPLIB */
  14249.                     csocket = -1;
  14250.                     if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
  14251.                       return(0);
  14252.                 }
  14253.         } else {
  14254.                 if (ftp_deb)
  14255.           fprintf(stderr, "SSL rejected as an authentication type\n");
  14256.                 if (ftpcode == 500 || ftpcode == 502)
  14257.           return(0);
  14258.             }
  14259.         }
  14260. #endif /* CK_SSL */
  14261.         /* Other auth types go here ... */
  14262.     } /* for (j;;) */
  14263.     return(0);
  14264. }
  14265. #endif /* FTP_SECURITY */
  14266.  
  14267. static int
  14268. #ifdef CK_ANSIC
  14269. setprotbuf(unsigned int size)
  14270. #else
  14271. setprotbuf(size) unsigned int size;
  14272. #endif /* CK_ANSIC */
  14273. /* setprotbuf */ {
  14274.     if (ucbuf)
  14275.       free(ucbuf);
  14276.     ucbuf = NULL;
  14277.     ucbufsiz = 0;
  14278.     actualbuf = size;
  14279.     while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
  14280.         if (actualbuf)
  14281.           actualbuf /= 2;
  14282.         else
  14283.           return(0);
  14284.     }
  14285.     ucbufsiz = actualbuf - FUDGE_FACTOR;
  14286.     debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
  14287.     if (ucbufsiz < 128) {
  14288.         printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
  14289.     } else if (ucbufsiz < 0) {
  14290.         printf("ERROR: ucbuf allocation failure\n");
  14291.         return(-1);
  14292.     }
  14293.     maxbuf = actualbuf;
  14294.     return(1);
  14295. }
  14296.  
  14297. static int
  14298. #ifdef CK_ANSIC
  14299. setpbsz(unsigned int size)
  14300. #else
  14301. setpbsz(size) unsigned int size;
  14302. #endif /* CK_ANSIC */
  14303. /* setpbsz */ {
  14304.     if (!setprotbuf(size)) {
  14305.         perror("?Error while trying to malloc PROT buffer:");
  14306. #ifdef FTP_SRP
  14307.         srp_reset();
  14308. #endif /* FTP_SRP */
  14309.         ftpclose();
  14310.         return(-1);
  14311.     }
  14312.     reply_parse = "PBSZ=";
  14313.     ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
  14314. #ifdef CK_SSL
  14315.              ssl_ftp_active_flag ? "0" :
  14316. #endif /* CK_SSL */
  14317.              ckuitoa(actualbuf),NULL,NULL);
  14318.     if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
  14319.         if (connected) {
  14320.             printf("?Unable to negotiate PROT buffer size with FTP server\n");
  14321.             ftpclose();
  14322.         }
  14323.         return(-1);
  14324.     }
  14325.     if (reply_parse) {
  14326.         if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
  14327.           maxbuf = actualbuf;
  14328.     } else
  14329.       maxbuf = actualbuf;
  14330.     ucbufsiz = maxbuf - FUDGE_FACTOR;
  14331.     debug(F101,"setpbsz ucbufsiz","",ucbufsiz);    
  14332.     reply_parse = NULL;
  14333.     return(0);
  14334. }
  14335.  
  14336. static VOID
  14337. cancel_remote(din) int din; {
  14338.     CHAR buf[FTP_BUFSIZ];
  14339.     int x, nfnd;
  14340. #ifdef BSDSELECT
  14341.     fd_set mask;
  14342. #endif /* BSDSELECT */
  14343. #ifdef IBMSELECT
  14344.     int fds[2], fdcnt = 0;
  14345. #endif /* IBMSELECT */
  14346. #ifdef DEBUG
  14347.     extern int debtim;
  14348.     int xdebtim;
  14349.     xdebtim = debtim;
  14350.     debtim = 1;
  14351. #endif /* DEBUG */
  14352.     debug(F100,"ftp cancel_remote entry","",0);
  14353. #ifdef CK_SSL
  14354.     if (ssl_ftp_active_flag) {
  14355.         /*
  14356.          * Send Telnet IP, Telnet DM but do so inline and within the
  14357.          * TLS channel
  14358.          */
  14359.         int count, error;
  14360.  
  14361.         buf[0] = IAC;
  14362.         buf[1] = TN_IP;
  14363.         buf[2] = IAC;
  14364.         buf[3] = TN_DM;
  14365.         buf[4] = NUL;
  14366.  
  14367.         count = SSL_write(ssl_ftp_con, buf, 4);
  14368.         debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
  14369.         error = SSL_get_error(ssl_ftp_con,count);
  14370.         debug(F111,"ftp cancel_remote","SSL_get_error()",error);
  14371.         switch (error) {
  14372.           case SSL_ERROR_NONE:
  14373.             break;
  14374.           case SSL_ERROR_WANT_WRITE:
  14375.           case SSL_ERROR_WANT_READ:
  14376.           case SSL_ERROR_SYSCALL:
  14377. #ifdef NT
  14378.             {
  14379.                 int gle = GetLastError();
  14380.             }
  14381. #endif /* NT */
  14382.           case SSL_ERROR_WANT_X509_LOOKUP:
  14383.           case SSL_ERROR_SSL:
  14384.           case SSL_ERROR_ZERO_RETURN:
  14385.           default:
  14386.             lostpeer();
  14387.             return;
  14388.         }
  14389.     } else
  14390. #endif /* CK_SSL */
  14391.     {
  14392.         /*
  14393.          * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
  14394.          * after urgent byte rather than before as is protocol now.
  14395.          */
  14396.         buf[0] = IAC;
  14397.         buf[1] = TN_IP;
  14398.         buf[2] = IAC;
  14399.         buf[3] = NUL;
  14400.         if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
  14401.           perror("cancel");
  14402.         debug(F101,"ftp cancel_remote send 1","",x);
  14403.         buf[0] = TN_DM;
  14404.         x = send(csocket,(SENDARG2TYPE)buf,1,0);
  14405.         debug(F101,"ftp cancel_remote send 2","",x);
  14406.     }
  14407.     x = scommand("ABOR");
  14408.     debug(F101,"ftp cancel_remote scommand","",x);
  14409. #ifdef BSDSELECT
  14410.     FD_ZERO(&mask);
  14411.     FD_SET(csocket, &mask);
  14412.     if (din) {
  14413.         FD_SET(din, &mask);
  14414.     }
  14415.     nfnd = empty(&mask, 10);
  14416.     debug(F101,"ftp cancel_remote empty","",nfnd);
  14417.     if ((nfnd) <= 0) {
  14418.         if (nfnd < 0) {
  14419.             perror("cancel");
  14420.         }
  14421. #ifdef FTP_PROXY
  14422.         if (ptabflg)
  14423.           ftpcode = -1;
  14424. #endif /* FTP_PROXY */
  14425.         lostpeer();
  14426.     }
  14427.     debug(F110,"ftp cancel_remote","D",0);
  14428.     if (din && FD_ISSET(din, &mask)) {
  14429.         /* Security: No threat associated with this read. */
  14430.         /* But you can't simply read the TLS data stream  */
  14431. #ifdef CK_SSL
  14432.         if (ssl_ftp_data_active_flag) {
  14433.             int count, error;
  14434.             while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
  14435.                     /* LOOP */ ;
  14436.         } else
  14437. #endif /* CK_SSL */
  14438.         {
  14439.             while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
  14440.                 /* LOOP */ ;
  14441.         }
  14442.     }
  14443.     debug(F110,"ftp cancel_remote","E",0);
  14444. #else /* BSDSELECT */
  14445. #ifdef IBMSELECT
  14446.     fds[0] = csocket;
  14447.     fdcnt++;
  14448.     if (din) {
  14449.         fds[1] = din;
  14450.         fdcnt++;
  14451.     }
  14452.     nfnd = empty(fds, fdcnt, 10);
  14453.     debug(F101,"ftp cancel_remote empty","",nfnd);
  14454.     if ((nfnd) <= 0) {
  14455.         if (nfnd < 0) {
  14456.             perror("cancel");
  14457.         }
  14458. #ifdef FTP_PROXY
  14459.         if (ptabflg)
  14460.           ftpcode = -1;
  14461. #endif /* FTP_PROXY */
  14462.         lostpeer();
  14463.     }
  14464.     debug(F110,"ftp cancel_remote","D",0);
  14465.     if (din && select(&din, 1,0,0,1) ) {
  14466. #ifdef CK_SSL
  14467.         if (ssl_ftp_data_active_flag) {
  14468.             int count, error;
  14469.             while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
  14470.                     /* LOOP */ ;
  14471.         } else
  14472. #endif /* CK_SSL */
  14473.         {
  14474.             while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
  14475.                 /* LOOP */ ;
  14476.         }
  14477.     }
  14478.     debug(F110,"ftp cancel_remote","E",0);
  14479. #else /* IBMSELECT */
  14480.     Some form of select is required.
  14481. #endif /* IBMSELECT */
  14482. #endif /* BSDSELECT */
  14483.     if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
  14484.         debug(F110,"ftp cancel_remote","F",0);
  14485.         /* 552 needed for NIC style cancel */
  14486.         getreply(0,-1,-1,ftp_vbm,0);
  14487.         debug(F110,"ftp cancel_remote","G",0);
  14488.     }
  14489.     debug(F110,"ftp cancel_remote","H",0);
  14490.     getreply(0,-1,-1,ftp_vbm,0);
  14491.     debug(F110,"ftp cancel_remote","I",0);
  14492. #ifdef DEBUG
  14493.     debtim = xdebtim;
  14494. #endif /* DEBUG */
  14495. }
  14496.  
  14497. static int
  14498. fts_dpl(x) int x; {
  14499.     if (!auth_type
  14500. #ifdef OS2
  14501.          || !ck_crypt_is_installed()
  14502. #endif /* OS2 */
  14503.          ) {
  14504.         switch ( x ) {
  14505.           case FPL_PRV:
  14506.             printf("?Cannot set protection level to PRIVATE\n");
  14507.             return(0);
  14508.           case FPL_SAF:
  14509.             printf("?Cannot set protection level to SAFE\n");
  14510.             return(0);
  14511.         }
  14512.         ftp_dpl = x;
  14513.         return(1);
  14514.     }
  14515.  
  14516. #ifdef CK_SSL
  14517.     if (x == FPL_SAF &&
  14518.         (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
  14519.         printf("Cannot set protection level to safe\n");
  14520.         return(0);
  14521.     }
  14522. #endif /* CK_SSL */
  14523.     /* Start with a PBSZ of 1 meg */
  14524.     if (x != FPL_CLR) {
  14525.         if (setpbsz(DEFAULT_PBSZ) < 0)
  14526.           return(0);
  14527.     }
  14528.     y = ftpcmd(x == FPL_CLR ? "PROT C" :
  14529.                (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
  14530.     if (y == REPLY_COMPLETE) {
  14531.         ftp_dpl = x;
  14532.         return(1);
  14533.     }
  14534.     return(0);
  14535. }
  14536.  
  14537. static int
  14538. fts_cpl(x) int x; {
  14539.     if (!auth_type 
  14540. #ifdef OS2
  14541.          || !ck_crypt_is_installed()
  14542. #endif /* OS2 */
  14543.          ) {
  14544.         switch ( x ) {
  14545.           case FPL_PRV:
  14546.             printf("?Cannot set protection level to PRIVATE\n");
  14547.             return(0);
  14548.           case FPL_SAF:
  14549.             printf("?Cannot set protection level to SAFE\n");
  14550.             return(0);
  14551.         }
  14552.         ftp_cpl = x;
  14553.         return(1);
  14554.     }
  14555.     if (x == FPL_CLR) {
  14556.         y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
  14557.         if (y == REPLY_COMPLETE) {
  14558.             ftp_cpl = x;
  14559.             return(1);
  14560.         }
  14561.         return(0);
  14562.     }
  14563.     ftp_cpl = x;
  14564.     return(1);
  14565. }
  14566.  
  14567. #ifdef FTP_GSSAPI
  14568. static VOID
  14569. user_gss_error(maj_stat, min_stat, s)
  14570.     OM_uint32 maj_stat, min_stat;
  14571.     char *s;
  14572. {
  14573.     /* a lot of work just to report the error */
  14574.     OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
  14575.     gss_buffer_desc msg;
  14576.     msg_ctx = 0;
  14577.     while (!msg_ctx) {
  14578.         gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
  14579.                                        GSS_C_GSS_CODE,
  14580.                                        GSS_C_NULL_OID,
  14581.                                        &msg_ctx,
  14582.                                        &msg
  14583.                                        );
  14584.         if ((gmaj_stat == GSS_S_COMPLETE)||
  14585.             (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
  14586.             fprintf(stderr, "GSSAPI error major: %s\n",
  14587.                     (char*)msg.value);
  14588.             gss_release_buffer(&gmin_stat, &msg);
  14589.         }
  14590.         if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
  14591.           break;
  14592.     }
  14593.     msg_ctx = 0;
  14594.     while (!msg_ctx) {
  14595.         gmaj_stat = gss_display_status(&gmin_stat, min_stat,
  14596.                                        GSS_C_MECH_CODE,
  14597.                                        GSS_C_NULL_OID,
  14598.                                        &msg_ctx,
  14599.                                        &msg
  14600.                                        );
  14601.         if ((gmaj_stat == GSS_S_COMPLETE)||
  14602.             (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
  14603.             fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
  14604.             gss_release_buffer(&gmin_stat, &msg);
  14605.         }
  14606.         if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
  14607.           break;
  14608.     }
  14609.     fprintf(stderr, "GSSAPI error: %s\n", s);
  14610. }
  14611. #endif /* FTP_GSSAPI */
  14612.  
  14613. #ifndef NOMHHOST
  14614. #ifdef datageneral
  14615. #define NOMHHOST
  14616. #else
  14617. #ifdef HPUX5WINTCP
  14618. #define NOMHHOST
  14619. #endif /* HPUX5WINTCP */
  14620. #endif /* datageneral */
  14621. #endif /* NOMHHOST */
  14622.  
  14623. #ifdef INADDRX
  14624. static struct in_addr inaddrx;
  14625. #endif /* INADDRX */
  14626.  
  14627. static char *
  14628. ftp_hookup(host, port, tls) char * host; int port; int tls; {
  14629.     register struct hostent *hp = 0;
  14630. #ifdef IP_TOS
  14631. #ifdef IPTOS_THROUGHPUT
  14632.     int tos;
  14633. #endif /* IPTOS_THROUGHPUT */
  14634. #endif /* IP_TOS */
  14635.     int s;
  14636.     GSOCKNAME_T len;
  14637.     static char hostnamebuf[MAXHOSTNAMELEN];
  14638.     char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
  14639.     int  cport;
  14640. #ifdef DEBUG
  14641.     extern int debtim;
  14642.     int xdebtim;
  14643.     xdebtim = debtim;
  14644.     debtim = 1;
  14645. #endif /* DEBUG */
  14646.  
  14647.     debug(F111,"ftp_hookup",host,port);
  14648.  
  14649. #ifndef NOHTTP
  14650.     if (tcp_http_proxy) {
  14651.         struct servent *destsp;
  14652.         char *p, *q;
  14653.  
  14654.         ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
  14655.         for (p = tcp_http_proxy, q = hostname;
  14656.              *p != '\0' && *p != ':';
  14657.              p++, q++
  14658.              )
  14659.           *q = *p;
  14660.         *q = '\0';
  14661.  
  14662.         if (*p == ':')
  14663.           p++;
  14664.         else
  14665.           p = "http";
  14666.  
  14667.         destsp = getservbyname(p,"tcp");
  14668.         if (destsp)
  14669.           cport = ntohs(destsp->s_port);
  14670.         else if (p) {
  14671.           cport = atoi(p);
  14672.         } else
  14673.           cport = 80;
  14674.     } else
  14675. #endif /* NOHTTP */
  14676.     {
  14677.         ckstrncpy(hostname,host,MAXHOSTNAMELEN);
  14678.         cport = port;
  14679.     }
  14680.     memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
  14681.     hisctladdr.sin_addr.s_addr = inet_addr(host);
  14682.     if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
  14683.     {
  14684.         debug(F110,"ftp hookup A",hostname,0);
  14685.         hisctladdr.sin_family = AF_INET;
  14686.         ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
  14687.     } else {
  14688.         debug(F110,"ftp hookup B",hostname,0);
  14689.         hp = gethostbyname(hostname);
  14690. #ifdef HADDRLIST
  14691.         hp = ck_copyhostent(hp);        /* make safe copy that won't change */
  14692. #endif /* HADDRLIST */
  14693.         if (hp == NULL) {
  14694.             fprintf(stderr, "ftp: %s: Unknown host\n", host);
  14695.             ftpcode = -1;
  14696. #ifdef DEBUG
  14697.             debtim = xdebtim;
  14698. #endif /* DEBUG */
  14699.             return((char *) 0);
  14700.         }
  14701.         hisctladdr.sin_family = hp->h_addrtype;
  14702. #ifdef HADDRLIST
  14703.         memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
  14704.                sizeof(hisctladdr.sin_addr));
  14705. #else /* HADDRLIST */
  14706.         memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
  14707.                sizeof(hisctladdr.sin_addr));
  14708. #endif /* HADDRLIST */
  14709.         ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
  14710.     }
  14711.     debug(F110,"ftp hookup C",hostnamebuf,0);
  14712.     ftp_host = hostnamebuf;
  14713.     s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  14714.     debug(F101,"ftp hookup socket","",s);
  14715.     if (s < 0) {
  14716.         perror("ftp: socket");
  14717.         ftpcode = -1;
  14718. #ifdef DEBUG
  14719.         debtim = xdebtim;
  14720. #endif /* DEBUG */
  14721.         return(0);
  14722.     }
  14723.     hisctladdr.sin_port = htons(cport);
  14724.     errno = 0;
  14725.  
  14726. #ifdef COMMENT
  14727.   printf("hisctladdr=%d\n",sizeof(hisctladdr));
  14728.   printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
  14729.   printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
  14730.   printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
  14731. #endif    /* COMMENT */
  14732.  
  14733. #ifdef HADDRLIST
  14734.     debug(F100,"ftp hookup HADDRLIST","",0);
  14735.     while
  14736. #else
  14737.     debug(F100,"ftp hookup no HADDRLIST","",0);
  14738.     if
  14739. #endif /* HADDRLIST */
  14740.       (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
  14741.           debug(F101,"ftp hookup connect failed","",errno);
  14742. #ifdef HADDRLIST
  14743.           if (hp && hp->h_addr_list[1]) {
  14744.               int oerrno = errno;
  14745.  
  14746.               fprintf(stderr, "ftp: connect to address %s: ",
  14747.                       inet_ntoa(hisctladdr.sin_addr));
  14748.               errno = oerrno;
  14749.               perror((char *) 0);
  14750.               hp->h_addr_list++;
  14751.               memcpy((char *)&hisctladdr.sin_addr,
  14752.                      hp->h_addr_list[0],
  14753.                      sizeof(hisctladdr.sin_addr));
  14754.               fprintf(stdout, "Trying %s...\n",
  14755.                       inet_ntoa(hisctladdr.sin_addr));
  14756. #ifdef TCPIPLIB
  14757.               socket_close(s);
  14758. #else /* TCPIPLIB */
  14759.               close(s);
  14760. #endif /* TCPIPLIB */
  14761.               s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
  14762.               if (s < 0) {
  14763.                   perror("ftp: socket");
  14764.                   ftpcode = -1;
  14765. #ifdef DEBUG
  14766.                   debtim = xdebtim;
  14767. #endif /* DEBUG */
  14768.                   return(0);
  14769.               }
  14770.               continue;
  14771.           }
  14772. #endif /* HADDRLIST */
  14773.           perror("ftp: connect");
  14774.           ftpcode = -1;
  14775.           goto bad;
  14776.       }
  14777.     debug(F100,"ftp hookup connect ok","",0);
  14778.  
  14779.     len = sizeof (myctladdr);
  14780.     errno = 0;
  14781.     if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
  14782.         debug(F101,"ftp hookup getsockname failed","",errno);
  14783.         perror("ftp: getsockname");
  14784.         ftpcode = -1;
  14785.         goto bad;
  14786.     }
  14787.     debug(F100,"ftp hookup getsockname ok","",0);
  14788.  
  14789. #ifndef NOHTTP
  14790.     if (tcp_http_proxy) {
  14791. #ifdef OS2
  14792.         char * agent = "Kermit 95";     /* Default user agent */
  14793. #else
  14794.         char * agent = "C-Kermit";
  14795. #endif /* OS2 */
  14796.  
  14797.         if (http_connect(s,agent,NULL,
  14798.                          tcp_http_proxy_user,
  14799.                          tcp_http_proxy_pwd,
  14800.                          0,
  14801.                          proxyhost
  14802.                          ) < 0) {
  14803.             char * foo = NULL;
  14804. #ifdef TCPIPLIB
  14805.             socket_close(s);
  14806. #else /* TCPIPLIB */
  14807.             close(s);
  14808. #endif /* TCPIPLIB */
  14809.  
  14810.             while (foo == NULL && tcp_http_proxy != NULL ) {
  14811.  
  14812.                 if (tcp_http_proxy_errno == 401 ||
  14813.                      tcp_http_proxy_errno == 407 ) {
  14814.                     char uid[UIDBUFLEN];
  14815.                     char pwd[PWDSIZ];
  14816.                     struct txtbox tb[2];
  14817.                     int ok;
  14818.  
  14819.                     tb[0].t_buf = uid;
  14820.                     tb[0].t_len = UIDBUFLEN;
  14821.                     tb[0].t_lbl = "Proxy Userid: ";
  14822.                     tb[0].t_dflt = NULL;
  14823.                     tb[0].t_echo = 1;
  14824.                     tb[1].t_buf = pwd;
  14825.                     tb[1].t_len = 256;
  14826.                     tb[1].t_lbl = "Proxy Passphrase: ";
  14827.                     tb[1].t_dflt = NULL;
  14828.                     tb[1].t_echo = 2;
  14829.  
  14830.                     ok = uq_mtxt("Proxy Server Authentication Required\n",
  14831.                                   NULL, 2, tb);
  14832.  
  14833.                     if (ok && uid[0]) {
  14834.                         char * proxy_user, * proxy_pwd;
  14835.  
  14836.                         proxy_user = tcp_http_proxy_user;
  14837.                         proxy_pwd  = tcp_http_proxy_pwd;
  14838.  
  14839.                         tcp_http_proxy_user = uid;
  14840.                         tcp_http_proxy_pwd = pwd;
  14841.  
  14842.                         foo = ftp_hookup(host, port, 0);
  14843.  
  14844.                         debug(F110,"ftp_hookup()",foo,0);
  14845.                         memset(pwd,0,PWDSIZ);
  14846.                         tcp_http_proxy_user = proxy_user;
  14847.                         tcp_http_proxy_pwd = proxy_pwd;
  14848.                     } else
  14849.                         break;
  14850.                 } else
  14851.                     break;
  14852.             }
  14853.             if (foo != NULL)
  14854.               return(foo);
  14855.             perror("ftp: connect");
  14856.             ftpcode = -1;
  14857.             goto bad;
  14858.         }
  14859.         ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
  14860.     }
  14861. #endif /* NOHTTP */
  14862.  
  14863.     csocket = s;
  14864.  
  14865. #ifdef CK_SSL
  14866.     if (tls) {
  14867.         /* FTP over SSL
  14868.          * If the connection is over an SSL proxy then the
  14869.          * auth_type will be NULL.  However, I'm not sure
  14870.          * whether we should protect the data channel in
  14871.          * that case or not.
  14872.          */
  14873.  
  14874.         debug(F100,"ftp hookup use_tls","",0);
  14875.         if (!ssl_auth()) {
  14876.             debug(F100,"ftp hookup ssl_auth failed","",0);
  14877.             auth_type = NULL;
  14878.             ftpcode = -1;
  14879.             csocket = -1;
  14880.             goto bad;
  14881.         }
  14882.         ssl_ftp_proxy = 1;
  14883.     }
  14884. #endif /* CK_SSL */
  14885.  
  14886. #ifdef IP_TOS
  14887. #ifdef IPTOS_LOWDELAY
  14888.     tos = IPTOS_LOWDELAY;
  14889.     if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
  14890.       perror("ftp: setsockopt TOS (ignored)");
  14891. #endif
  14892. #endif
  14893.     if (!quiet)
  14894.       printf("Connected to %s.\n", host);
  14895.  
  14896.     /* Read greeting from server */
  14897.     if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
  14898.         debug(F100,"ftp hookup bad reply","",0);
  14899. #ifdef TCPIPLIB
  14900.         socket_close(csocket);
  14901. #else /* TCPIPLIB */
  14902.         close(csocket);
  14903. #endif /* TCPIPLIB */
  14904.         ftpcode = -1;
  14905.         goto bad;
  14906.     }
  14907. #ifdef SO_OOBINLINE
  14908.     {
  14909.         int on = 1;
  14910.         errno = 0;
  14911.         if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
  14912.                sizeof(on)) < 0) {
  14913.             perror("ftp: setsockopt");
  14914.             debug(F101,"ftp hookup setsockopt failed","",errno);
  14915.         }
  14916. #ifdef DEBUG
  14917.         else
  14918.           debug(F100,"ftp hookup setsockopt ok","",0);
  14919. #endif /* DEBUG */
  14920.     }
  14921. #endif /* SO_OOBINLINE */
  14922.  
  14923. #ifdef DEBUG
  14924.     debtim = xdebtim;
  14925. #endif /* DEBUG */
  14926.     return(ftp_host);
  14927.  
  14928.   bad:
  14929.     debug(F100,"ftp hookup bad","",0);
  14930. #ifdef TCPIPLIB
  14931.     socket_close(s);
  14932. #else /* TCPIPLIB */
  14933.     close(s);
  14934. #endif /* TCPIPLIB */
  14935. #ifdef DEBUG
  14936.     debtim = xdebtim;
  14937. #endif /* DEBUG */
  14938.     csocket = -1;
  14939.     return((char *)0);
  14940. }
  14941.  
  14942. static VOID
  14943. ftp_init() {
  14944.     int i, n;
  14945.  
  14946.     /* The purpose of the initial REST 0 is not clear, but other FTP */
  14947.     /* clients do it.  In any case, failure of this command is not a */
  14948.     /* reliable indication that the server does not support Restart. */
  14949.  
  14950.     okrestart = 0;
  14951.     if (!noinit) {
  14952.         n = ftpcmd("REST 0",NULL,0,0,0);
  14953.         if (n == REPLY_COMPLETE)
  14954.           okrestart = 1;
  14955. #ifdef COMMENT
  14956.         else if (ftp_deb)
  14957.           printf("WARNING: Unable to restore file pointer.\n");
  14958. #endif /* COMMENT */
  14959.     }
  14960.     n = ftpcmd("SYST",NULL,0,0,0);      /* Get server system type */
  14961.     if (n == REPLY_COMPLETE) {
  14962.         register char *cp, c = NUL;
  14963.         cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
  14964.         if (cp == NULL)
  14965.           cp = ckstrchr(ftp_reply_str+4,'\r');
  14966.         if (cp) {
  14967.             if (cp[-1] == '.')
  14968.               cp--;
  14969.             c = *cp;                    /* Save this char */
  14970.             *cp = '\0';                 /* Replace it with NUL */
  14971.         }
  14972.         if (!quiet)
  14973.           printf("Remote system type is %s.\n",ftp_reply_str+4);
  14974.         ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
  14975.         if (cp)                         /* Put back saved char */
  14976.           *cp = c;
  14977.     }
  14978.     alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
  14979.  
  14980.     if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
  14981.     else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
  14982.     else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
  14983.     else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
  14984.     else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
  14985.     else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
  14986.     else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
  14987.  
  14988. #ifdef FTP_PROXY
  14989.     unix_proxy = 0;
  14990.     if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
  14991. #endif /* FTP_PROXY */
  14992.  
  14993.     if (ftp_cmdlin && ftp_xfermode == XMODE_M)
  14994.       ftp_typ = binary;                 /* Type given on command line */
  14995.     else                                /* Otherwise set it automatically */
  14996.       ftp_typ = alike ? FTT_BIN : FTT_ASC;
  14997.     changetype(ftp_typ,0);              /* Change to this type */
  14998.     g_ftp_typ = ftp_typ;                /* Make it the global type */
  14999.     if (!quiet)
  15000.       printf("Default transfer mode is %s\n",
  15001.              ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
  15002.              );
  15003.     for (i = 0; i < 16; i++)        /* Init server FEATure table */
  15004.       sfttab[i] = 0;
  15005.     if (!noinit) {
  15006.         n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
  15007. #ifdef COMMENT
  15008.         if (n != REPLY_COMPLETE)
  15009.           printf("WARNING: Server does not accept MODE S(TREAM)\n");
  15010. #endif /* COMMENT */
  15011.         n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
  15012. #ifdef COMMENT
  15013.         if (n != REPLY_COMPLETE)
  15014.           printf("WARNING: Server does not accept STRU F(ILE)\n");
  15015. #endif /* COMMENT */
  15016.     if (featok) {
  15017.         n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
  15018.         if (n == REPLY_COMPLETE) {
  15019.         debug(F101,"ftp_init FEAT","",sfttab[0]);
  15020.         if (deblog || ftp_deb) {
  15021.             int i;
  15022.             for (i = 1; i < 16 && i < nfeattab; i++) {
  15023.             debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
  15024.             if (ftp_deb)
  15025.               printf("  Server %s %s\n",
  15026.                  sfttab[i] ? "supports" : "does not support",
  15027.                  feattab[i].kwd
  15028.                  );
  15029.             }
  15030.             /* Deal with disabled MLST opts here if necessary */
  15031.             /* But why would it be? */
  15032.         }
  15033.         }
  15034.     }
  15035.     }
  15036. }
  15037.  
  15038. static int
  15039. ftp_login(host) char * host; {          /* (also called from ckuusy.c) */
  15040.     static char ftppass[PASSBUFSIZ]="";
  15041.     char tmp[PASSBUFSIZ];
  15042.     char *user = NULL, *pass = NULL, *acct = NULL;
  15043.     int n, aflag = 0;
  15044.     extern char uidbuf[];
  15045.     extern char pwbuf[];
  15046.     extern int  pwflg, pwcrypt;
  15047.  
  15048.     debug(F111,"ftp_login",ftp_logname,ftp_log);
  15049.  
  15050.     if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
  15051.       anonymous = 1;
  15052.     if (!ckstrcmp(ftp_logname,"ftp",-1,0))
  15053.       anonymous = 1;
  15054.  
  15055. #ifdef FTP_SRP
  15056.     if (auth_type && !strcmp(auth_type, "SRP")) {
  15057.         user = srp_user;
  15058.         pass = srp_pass;
  15059.         acct = srp_acct;
  15060.     } else
  15061. #endif /* FTP_SRP */
  15062.       if (anonymous) {
  15063.           user = "anonymous";
  15064.           if (ftp_tmp) {        /* They gave a password */
  15065.               pass = ftp_tmp;
  15066.           } else if (ftp_apw) {        /* SET FTP ANONYMOUS-PASSWORD */
  15067.           pass = ftp_apw;
  15068.       } else {            /* Supply user@host */
  15069.           ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
  15070.           pass = tmp;
  15071.           }
  15072.       debug(F110,"ftp anonymous",pass,0);
  15073.       } else {
  15074. #ifdef USE_RUSERPASS
  15075.           if (ruserpass(host, &user, &pass, &acct) < 0) {
  15076.               ftpcode = -1;
  15077.               return(0);
  15078.           }
  15079. #endif /* USE_RUSERPASS */
  15080.           if (ftp_logname) {
  15081.               user = ftp_logname;
  15082.               pass = ftp_tmp;
  15083.           } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
  15084.               user = uidbuf;
  15085.               if (ftp_tmp) {
  15086.                   pass = ftp_tmp;
  15087.               } else if (pwbuf[0] && pwflg) {
  15088.                   ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
  15089. #ifdef OS2
  15090.                   if ( pwcrypt )
  15091.                       ck_encrypt((char *)ftppass);
  15092. #endif /* OS2 */
  15093.                   pass = ftppass;
  15094.               }
  15095.           }
  15096.           acct = ftp_acc;
  15097.           while (user == NULL) {
  15098.               char *myname, prompt[PROMPTSIZ];
  15099.               int ok;
  15100.  
  15101.               myname = whoami();
  15102.               if (myname)
  15103.                 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
  15104.                           NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  15105.               else
  15106.                 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
  15107.               tmp[0] = '\0';
  15108.               
  15109.               ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
  15110.                           DEFAULT_UQ_TIMEOUT);
  15111.               if (!ok || *tmp == '\0')
  15112.                 user = myname;
  15113.               else
  15114.                 user = brstrip(tmp);
  15115.           }
  15116.       }
  15117.     n = ftpcmd("USER",user,-1,-1,ftp_vbm);
  15118.     if (n == REPLY_COMPLETE) {
  15119.         /* determine if we need to send a dummy password */
  15120.         if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
  15121.           ftpcmd("PASS dummy",NULL,0,0,1);
  15122.     } else if (n == REPLY_CONTINUE) {
  15123. #ifdef CK_ENCRYPTION
  15124.         int oldftp_cpl;
  15125. #endif /* CK_ENCRYPTION */
  15126.  
  15127.         if (pass == NULL) {
  15128.             int ok;
  15129.             setint();
  15130.             ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
  15131.                         DEFAULT_UQ_TIMEOUT);
  15132.             if (ok)
  15133.                 pass = brstrip(ftppass);
  15134.         }
  15135.  
  15136. #ifdef CK_ENCRYPTION
  15137.         oldftp_cpl = ftp_cpl;
  15138.         ftp_cpl = FPL_PRV;
  15139. #endif /* CK_ENCRYPTION */
  15140.         n = ftpcmd("PASS",pass,-1,-1,1);
  15141.         if (!anonymous && pass) {
  15142.             char * p = pass;
  15143.             while (*p++) *(p-1) = NUL;
  15144.             makestr(&ftp_tmp,NULL);
  15145.         }
  15146. #ifdef CK_ENCRYPTION
  15147.         /* level may have changed */
  15148.         if (ftp_cpl == FPL_PRV)
  15149.           ftp_cpl = oldftp_cpl;
  15150. #endif /* CK_ENCRYPTION */
  15151.     }
  15152.     if (n == REPLY_CONTINUE) {
  15153.         aflag++;
  15154.         if (acct == NULL) {
  15155.             static char ftpacct[80];
  15156.             int ok;
  15157.             setint();
  15158.             ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
  15159.                         DEFAULT_UQ_TIMEOUT);
  15160.             if (ok)
  15161.                 acct = brstrip(ftpacct);
  15162.         }
  15163.         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
  15164.     }
  15165.     if (n != REPLY_COMPLETE) {
  15166.         fprintf(stderr, "FTP login failed.\n");
  15167.         if (haveurl)
  15168.           doexit(BAD_EXIT,-1);
  15169.         return(0);
  15170.     }
  15171.     if (!aflag && acct != NULL) {
  15172.         ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
  15173.     }
  15174.     makestr(&ftp_logname,user);
  15175.     loggedin = 1;
  15176. #ifdef LOCUS
  15177.     /* Unprefixed file management commands go to server */
  15178.     if (autolocus && !ftp_cmdlin) {
  15179.     setlocus(0,1);
  15180.     }
  15181. #endif /* LOCUS */
  15182.     ftp_init();
  15183.  
  15184.     if (anonymous && !quiet) {
  15185.         printf(" Logged in as anonymous (%s)\n",pass);
  15186.         memset(pass, 0, strlen(pass));
  15187.     }
  15188.     if (ftp_rdir) {
  15189.         if (doftpcwd(ftp_rdir,-1) < 1)
  15190.           doexit(BAD_EXIT,-1);
  15191.     }
  15192.  
  15193. #ifdef FTP_PROXY
  15194.     if (proxy)
  15195.       return(1);
  15196. #endif /* FTP_PROXY */
  15197.     return(1);
  15198. }
  15199.  
  15200. static int
  15201. ftp_reset() {
  15202.     int rc;
  15203. #ifdef BSDSELECT
  15204.     int nfnd = 1;
  15205.     fd_set mask;
  15206.     FD_ZERO(&mask);
  15207.     while (nfnd > 0) {
  15208.         FD_SET(csocket, &mask);
  15209.         if ((nfnd = empty(&mask,0)) < 0) {
  15210.             perror("reset");
  15211.             ftpcode = -1;
  15212.             lostpeer();
  15213.             return(0);
  15214.         } else if (nfnd) {
  15215.             getreply(0,-1,-1,ftp_vbm,0);
  15216.         }
  15217.     }
  15218. #else /* BSDSELECT */
  15219. #ifdef IBMSELECT
  15220.     int nfnd = 1;
  15221.     while (nfnd > 0) {
  15222.         if ((nfnd = empty(&csocket,1,0)) < 0) {
  15223.             perror("reset");
  15224.             ftpcode = -1;
  15225.             lostpeer();
  15226.             return(0);
  15227.         } else if (nfnd) {
  15228.             getreply(0,-1,-1,ftp_vbm,0);
  15229.         }
  15230.     }
  15231. #endif /* IBMSELECT */
  15232. #endif /* BSDSELECT */
  15233.     rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
  15234.     if (rc > 0)
  15235.       loggedin = 0;
  15236.     return(rc);
  15237. }
  15238.  
  15239. static int
  15240. ftp_rename(from, to) char * from, * to; {
  15241.     int lcs = -1, rcs = -1;
  15242. #ifndef NOCSETS
  15243.     if (ftp_xla) {
  15244.         lcs = ftp_csl;
  15245.         if (lcs < 0) lcs = fcharset;
  15246.         rcs = ftp_csx;
  15247.         if (rcs < 0) rcs = ftp_csr;
  15248.     }
  15249. #endif /* NOCSETS */
  15250.     if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
  15251.         return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
  15252.     }
  15253.     return(0);                          /* Failure */
  15254. }
  15255.  
  15256. static int
  15257. ftp_umask(mask) char * mask; {
  15258.     int rc;
  15259.     rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
  15260.     return(rc);
  15261. }
  15262.  
  15263. static int
  15264. ftp_user(user,pass,acct) char * user, * pass, * acct; {
  15265.     int n = 0, aflag = 0;
  15266.     char pwd[PWDSIZ];
  15267.  
  15268.     if (!auth_type && ftp_aut) {
  15269. #ifdef FTP_SRP
  15270.         if (ck_srp_is_installed()) {
  15271.             if (srp_ftp_auth( NULL, user, pass)) {
  15272.                 makestr(&pass,srp_pass);
  15273.             }
  15274.         }
  15275. #endif /* FTP_SRP */
  15276.     }
  15277.     n = ftpcmd("USER",user,-1,-1,ftp_vbm);
  15278.     if (n == REPLY_COMPLETE)
  15279.       n = ftpcmd("PASS dummy",NULL,0,0,1);
  15280.     else if (n == REPLY_CONTINUE) {
  15281. #ifdef CK_ENCRYPTION
  15282.         int oldftp_cpl;
  15283. #endif /* CK_ENCRYPTION */
  15284.         if (pass == NULL || !pass[0]) {
  15285.             int ok;
  15286.             pwd[0] = '\0';
  15287.             setint();
  15288.             ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
  15289.                         DEFAULT_UQ_TIMEOUT);
  15290.             if (ok)
  15291.                 pass = brstrip(pwd);
  15292.         }
  15293.  
  15294. #ifdef CK_ENCRYPTION
  15295.         if ((oldftp_cpl = ftp_cpl) == PROT_S)
  15296.           ftp_cpl = PROT_P;
  15297. #endif /* CK_ENCRYPTION */
  15298.         n = ftpcmd("PASS",pass,-1,-1,1);
  15299.         memset(pass, 0, strlen(pass));
  15300. #ifdef CK_ENCRYPTION
  15301.         /* level may have changed */
  15302.         if (ftp_cpl == PROT_P)
  15303.           ftp_cpl = oldftp_cpl;
  15304. #endif /* CK_ENCRYPTION */
  15305.     }
  15306.     if (n == REPLY_CONTINUE) {
  15307.         if (acct == NULL || !acct[0]) {
  15308.             int ok;
  15309.             pwd[0] = '\0';
  15310.             setint();
  15311.             ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
  15312.                         DEFAULT_UQ_TIMEOUT);
  15313.             if (ok)
  15314.                 acct = pwd;
  15315.         }
  15316.         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
  15317.         aflag++;
  15318.     }
  15319.     if (n != REPLY_COMPLETE) {
  15320.         printf("Login failed.\n");
  15321.         return(0);
  15322.     }
  15323.     if (!aflag && acct != NULL && acct[0]) {
  15324.         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
  15325.     }
  15326.     if (n == REPLY_COMPLETE) {
  15327.         makestr(&ftp_logname,user);
  15328.         loggedin = 1;
  15329.         ftp_init();
  15330.         return(1);
  15331.     }
  15332.     return(0);
  15333. }
  15334.  
  15335. char *
  15336. ftp_authtype() {
  15337.     if (!connected)
  15338.       return("NULL");
  15339.     return(auth_type ? auth_type : "NULL");
  15340. }
  15341.  
  15342. char *
  15343. ftp_cpl_mode() {
  15344.     switch (ftp_cpl) {
  15345.       case FPL_CLR:
  15346.         return("clear");
  15347.       case FPL_SAF:
  15348.         return("safe");
  15349.       case FPL_PRV:
  15350.         return("private");
  15351.       case FPL_CON:
  15352.         return("confidential");
  15353.       default:
  15354.         return("(error)");
  15355.     }
  15356. }
  15357.  
  15358. char *
  15359. ftp_dpl_mode() {
  15360.     switch (ftp_dpl) {
  15361.       case FPL_CLR:
  15362.         return("clear");
  15363.       case FPL_SAF:
  15364.         return("safe");
  15365.       case FPL_PRV:
  15366.         return("private");
  15367.       case FPL_CON:
  15368.         return("confidential");
  15369.       default:
  15370.         return("(error)");
  15371.     }
  15372. }
  15373.  
  15374.  
  15375. /* remote_files() */
  15376. /*
  15377.    Returns next remote filename on success;
  15378.    NULL on error or no more files with global rfrc set to:
  15379.      -1: Bad argument
  15380.      -2: Server error response to NLST, e.g. file not found
  15381.      -3: No more files
  15382.      -9: Internal error
  15383. */
  15384. #define FTPNAMBUFLEN CKMAXPATH+1024
  15385.  
  15386. /* Check: ckmaxfiles CKMAXOPEN */
  15387.  
  15388. #define MLSDEPTH 128            /* Stack of open temp files */
  15389. static int mlsdepth = 0;        /* Temp file stack depth */
  15390. static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
  15391. static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
  15392.  
  15393. static VOID
  15394. mlsreset() {                /* Reset MGET temp-file stack */
  15395.     int i;
  15396.     for (i = 0; i <= mlsdepth; i++) {
  15397.     if (tmpfilptr[i]) {
  15398.         fclose(tmpfilptr[i]);
  15399.         tmpfilptr[i] = NULL;
  15400.         if (tmpfilnam[i]) {
  15401. #ifdef OS2
  15402.         unlink(tmpfilnam[i]);
  15403. #endif /* OS2 */
  15404.         free(tmpfilnam[i]);
  15405.         }
  15406.     }
  15407.     }
  15408.     mlsdepth = 0;
  15409. }
  15410.  
  15411. static CHAR *
  15412. #ifdef CK_ANSIC
  15413. remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
  15414. #else /* CK_ANSIC */
  15415. remote_files(new_query, arg, pattern, proxy_switch)
  15416.     int new_query;
  15417.     CHAR * arg;                /* That we send to the server */
  15418.     CHAR * pattern;            /* That we use locally */
  15419.     int proxy_switch;
  15420. #endif /* CK_ANSIC */
  15421. /* remote_files */ {
  15422.     static CHAR buf[FTPNAMBUFLEN];
  15423.     CHAR *cp, *whicharg;
  15424.     char * cdto = NULL;
  15425.     char * p;
  15426.     int i, x, forced = 0;
  15427.     int lcs = 0, rcs = 0, xlate = 0;
  15428.  
  15429.     debug(F101,"ftp remote_files new_query","",new_query);
  15430.     debug(F110,"ftp remote_files arg",arg,0);
  15431.     debug(F110,"ftp remote_files pattern",pattern,0);
  15432.  
  15433.     rfrc = -1;
  15434.     if (pattern)            /* Treat empty pattern same as NULL */
  15435.       if (!*pattern)
  15436.     pattern = NULL;
  15437.     if (arg)                /* Ditto for arg */
  15438.       if (!*arg)
  15439.     arg = NULL;
  15440.  
  15441.   again:
  15442.  
  15443.     if (new_query) {
  15444.         if (tmpfilptr[mlsdepth]) {
  15445.             fclose(tmpfilptr[mlsdepth]);
  15446.             tmpfilptr[mlsdepth] = NULL;
  15447. #ifdef OS2
  15448.             if (!ftp_deb && !deblog)
  15449.               unlink(tmpfilnam[mlsdepth]);
  15450. #endif /* OS2 */
  15451.         }
  15452.     }
  15453.     if (tmpfilptr[mlsdepth] == NULL) {
  15454.         extern char * tempdir;
  15455.         char * p;
  15456.         debug(F110,"ftp remote_files tempdir",tempdir,0);
  15457.         if (tempdir) {
  15458.             p = tempdir;
  15459.         } else {
  15460. #ifdef OS2
  15461. #ifdef NT
  15462.             p = getenv("K95TMP");
  15463. #else
  15464.             p = getenv("K2TMP");
  15465. #endif /* NT */
  15466.             if (!p)
  15467. #endif /* OS2 */
  15468.               p = getenv("CK_TMP");
  15469.             if (!p)
  15470.               p = getenv("TMPDIR");
  15471.             if (!p) p = getenv("TEMP");
  15472.             if (!p) p = getenv("TMP");
  15473. #ifdef OS2ORUNIX
  15474.             if (p) {
  15475.                 int len = strlen(p);
  15476.                 if (p[len-1] != '/'
  15477. #ifdef OS2
  15478.                     && p[len-1] != '\\'
  15479. #endif /* OS2 */
  15480.                      ) {
  15481.                     static char foo[CKMAXPATH];
  15482.                     ckstrncpy(foo,p,CKMAXPATH);
  15483.                     ckstrncat(foo,"/",CKMAXPATH);
  15484.                     p = foo;
  15485.                 }
  15486.             } else
  15487. #else /* OS2ORUNIX */
  15488.             if (!p)
  15489. #endif /* OS2ORUNIX */
  15490. #ifdef UNIX                             /* Systems that have a standard */
  15491.                 p = "/tmp/";            /* temporary directory... */
  15492. #else
  15493. #ifdef datageneral
  15494.             p = ":TMP:";
  15495. #else
  15496.             p = "";
  15497. #endif /* datageneral */
  15498. #endif /* UNIX */
  15499.         }
  15500.         debug(F110,"ftp remote_files p",p,0);
  15501.  
  15502.     /* Get temp file */
  15503.  
  15504.     if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
  15505.         ckmakmsg((char *)tmpfilnam[mlsdepth],
  15506.              CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
  15507.     } else {
  15508.         printf("?Malloc failure: remote_files()\n");
  15509.         return(NULL);
  15510.     }
  15511.  
  15512. #ifdef NT
  15513.     {
  15514.         char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
  15515.         if ( tmpfil )
  15516.         ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
  15517.     }
  15518. #else /* NT */
  15519. #ifdef MKTEMP
  15520. #ifdef MKSTEMP
  15521.     x = mkstemp((char *)tmpfilnam[mlsdepth]);
  15522.     if (x > -1) close(x);        /* We just want the name. */
  15523. #else
  15524.         mktemp((char *)tmpfilnam[mlsdepth]);
  15525. #endif /* MKSTEMP */
  15526.         /* if no mktmpnam() the name will just be "ckXXXXXX"... */
  15527. #endif /* MKTEMP */
  15528. #endif /* NT */
  15529.  
  15530.     debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
  15531.           tmpfilnam[mlsdepth],mlsdepth);
  15532.  
  15533. #ifdef FTP_PROXY
  15534.         if (proxy_switch) {
  15535.             pswitch(!proxy);
  15536.         }
  15537. #endif /* FTP_PROXY */
  15538.  
  15539.         debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
  15540.         debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
  15541.         debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
  15542.  
  15543. #ifndef NOCSETS
  15544.         xlate = ftp_xla;                /* SET FTP CHARACTER-SET-TRANSLATION */
  15545.         if (xlate) {                    /* ON? */
  15546.             lcs = ftp_csl;              /* Local charset */
  15547.             if (lcs < 0) lcs = fcharset;
  15548.             if (lcs < 0) xlate = 0;
  15549.         }
  15550.         if (xlate) {                    /* Still ON? */
  15551.             rcs = ftp_csx;              /* Remote (Server) charset */
  15552.             if (rcs < 0) rcs = ftp_csr;
  15553.             if (rcs < 0) xlate = 0;
  15554.         }
  15555. #endif /* NOCSETS */
  15556.  
  15557.     forced = mgetforced;        /* MGET method forced? */
  15558.     if (!forced || !mgetmethod)    /* Not forced... */
  15559.       mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
  15560.           SND_MLS :
  15561.           SND_NLS; 
  15562. /*                                           
  15563.   User's Command:                 Result:
  15564.     mget /nlst                     NLST (NULL)
  15565.     mget /nlst foo                 NLST foo
  15566.     mget /nlst *.txt               NLST *.txt 
  15567.     mget /nlst /match:*.txt        NLST (NULL)
  15568.     mget /nlst /match:*.txt  foo   NLST foo   
  15569.     mget /mlsd                     MLSD (NULL)
  15570.     mget /mlsd foo                 MLSD foo
  15571.     mget /mlsd *.txt               MLSD (NULL)
  15572.     mget /mlsd /match:*.txt        MLSD (NULL)
  15573.     mget /mlsd /match:*.txt  foo   MLSD foo
  15574. */
  15575.     x = -1;
  15576.     while (x < 0) {
  15577.         if (pattern) {        /* Don't simplify this! */
  15578.         whicharg = arg;
  15579.         } else if (mgetmethod == SND_MLS) {
  15580.         if (arg)
  15581.           whicharg = iswild((char *)arg) ? NULL : arg;
  15582.         else
  15583.           whicharg = NULL;
  15584.         } else {
  15585.         whicharg = arg;
  15586.         }
  15587.         debug(F110,"ftp remote_files mgetmethod",
  15588.           mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
  15589.         debug(F110,"ftp remote_files whicharg",whicharg,0);
  15590.  
  15591.         x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
  15592.                 (char *)tmpfilnam[mlsdepth],
  15593.                 (char *)whicharg,
  15594.                 "wb",
  15595.                 0,
  15596.                 0,
  15597.                 NULL,
  15598.                 xlate,
  15599.                 lcs,
  15600.                 rcs
  15601.                 );
  15602.         if (x < 0) {        /* Chosen method wasn't accepted */
  15603.         if (forced) {
  15604.             if (ftpcode > 500 && ftpcode < 505 && !quiet)
  15605.               printf("?%s: Not supported by server\n",
  15606.                  mgetmethod == SND_MLS ? "MLSD" : "NLST"
  15607.                  );
  15608.             rfrc = -2;        /* Fail */
  15609.             return(NULL);
  15610.         }
  15611.         /* Not forced - if MLSD failed, try NLST */
  15612.         if (mgetmethod == SND_MLS) {  /* Server lied about MLST */
  15613.             sfttab[SFT_MLST] = 0;     /* So disable it */
  15614.             mlstok = 0;              /* and */
  15615.             mgetmethod = SND_NLS;     /* try NLST */
  15616.             continue;
  15617.         }
  15618.         rfrc = -2;
  15619.         return(NULL);
  15620.         }
  15621.     }
  15622. #ifdef FTP_PROXY
  15623.         if (proxy_switch) {
  15624.             pswitch(!proxy);
  15625.         }
  15626. #endif /* FTP_PROXY */
  15627.         tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
  15628. #ifndef OS2
  15629.     if (tmpfilptr[mlsdepth]) {
  15630.         if (!ftp_deb && !deblog)
  15631.           unlink(tmpfilnam[mlsdepth]);
  15632.     }
  15633. #endif /* OS2 */
  15634.       notemp:
  15635.         if (!tmpfilptr[mlsdepth]) {
  15636.             debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
  15637.             if ((!dpyactive || ftp_deb))
  15638.               printf("?Can't find list of remote files, oops\n");
  15639.             rfrc = -9;
  15640.             return(NULL);
  15641.         }
  15642.     if (ftp_deb)
  15643.       printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
  15644.     }
  15645.     buf[0] = NUL;
  15646.     buf[FTPNAMBUFLEN-1] = NUL;
  15647.     buf[FTPNAMBUFLEN-2] = NUL;
  15648.  
  15649.     /* We have to redo all this because the first time was only for */
  15650.     /* for getting the file list, now it's for getting each file */
  15651.  
  15652.     if (arg && mgetmethod == SND_MLS) {    /* MLSD */
  15653.     if (!pattern && iswild((char *)arg)) {
  15654.         pattern = arg;        /* Wild arg is really a pattern */
  15655.         if (pattern)
  15656.           if (!*pattern)
  15657.         pattern = NULL;
  15658.         arg = NULL;            /* and not an arg */
  15659.     }
  15660.     if (new_query) {        /* Initial query? */
  15661.         cdto = (char *)arg;        /* (nonwild) arg given? */
  15662.         if (cdto)
  15663.           if (!*cdto)
  15664.         cdto = NULL;
  15665.         if (cdto)            /* If so, then CD to it */
  15666.           doftpcwd(cdto,0);
  15667.     }
  15668.     }
  15669.     new_query = 0;
  15670.  
  15671.     if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
  15672.         fclose(tmpfilptr[mlsdepth]);
  15673.         tmpfilptr[mlsdepth] = NULL;
  15674.  
  15675. #ifdef OS2
  15676.         if (!ftp_deb && !deblog)
  15677.           unlink(tmpfilnam[mlsdepth]);
  15678. #endif /* OS2 */
  15679.         if (ftp_deb && !deblog) {
  15680.             printf("(Temporary file %s NOT deleted)\n",
  15681.            (char *)tmpfilnam[mlsdepth]);
  15682.         }
  15683.     if (mlsdepth <= 0) {        /* EOF at depth 0 */
  15684.         rfrc = -3;            /* means we're done */
  15685.         return(NULL);
  15686.     }
  15687.     printf("POPPING(%d)...\n",mlsdepth-1); 
  15688.     if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
  15689.     mlsdepth--;
  15690.     doftpcdup();
  15691.     zchdir("..");            /* <-- Not portable */
  15692.     goto again;
  15693.     }
  15694.     if (buf[FTPNAMBUFLEN-1]) {
  15695.     printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
  15696.            FTPNAMBUFLEN
  15697.            );
  15698.     debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
  15699.     return(NULL);
  15700.     }
  15701.     /* debug(F110,"ftp remote_files buf 1",buf,0); */
  15702.     if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
  15703.       *cp = '\0';
  15704.     if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
  15705.       *cp = '\0';
  15706.     debug(F110,"ftp remote_files buf",buf,0);
  15707.     rfrc = 0;
  15708.  
  15709.     if (ftp_deb)
  15710.       printf("[%s]\n",(char *)buf);
  15711.  
  15712.     havesize = (CK_OFF_T)-1;        /* Initialize file facts... */
  15713.     havetype = 0;
  15714.     makestr(&havemdtm,NULL);
  15715.     p = (char *)buf;
  15716.  
  15717.     if (mgetmethod == SND_NLS) {    /* NLST... */
  15718.     if (pattern) {
  15719.         if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
  15720.           goto again;
  15721.     }
  15722.     } else {                /* MLSD... */
  15723.     p = parsefacts((char *)buf);
  15724.     switch (havetype) {
  15725.       case FTYP_FILE:        /* File: Get it if it matches */
  15726.         if (pattern) {
  15727.         if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
  15728.           goto again;
  15729.         }
  15730.         break;
  15731.       case FTYP_CDIR:        /* Current directory */
  15732.       case FTYP_PDIR:        /* Parent directory */
  15733.         goto again;            /* Skip */
  15734.       case FTYP_DIR:        /* (Sub)Directory */
  15735.         if (!recursive)        /* If not /RECURSIVE */
  15736.           goto again;        /* Skip */
  15737.         if (mlsdepth < MLSDEPTH) {
  15738.         char * p2 = NULL;
  15739.         mlsdepth++;
  15740.         printf("RECURSING [%s](%d)...\n",p,mlsdepth); 
  15741.         if (doftpcwd(p,0) > 0) {
  15742.             int x;
  15743.             if (!ckstrchr(p,'/')) {
  15744.             /* zmkdir() needs dirsep */
  15745.             if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
  15746.                 strcpy(p2,p);    /* SAFE */
  15747.                 strcat(p2,"/");    /* SAFE */
  15748.                 p = p2;
  15749.             }
  15750.             }
  15751. #ifdef NOMKDIR
  15752.             x = -1;
  15753. #else
  15754.             x = zmkdir(p);
  15755. #endif /* NOMKDIR */
  15756.             if (x > -1) {
  15757.             zchdir(p);
  15758.             p = (char *)remote_files(1,arg,pattern,0);
  15759.             if (p2) free(p2);
  15760.             } else {
  15761.             printf("?mkdir failed: [%s] Depth=%d\n",
  15762.                    p,
  15763.                    mlsdepth
  15764.                    );
  15765.             mlsreset();
  15766.             if (p2) free(p2);
  15767.             return(NULL);
  15768.             }
  15769.         } else {
  15770.             printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
  15771.             mlsreset();
  15772.             return(NULL);
  15773.         }
  15774.         } else {
  15775.         printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
  15776.                mlsdepth
  15777.                );
  15778.         mlsreset();
  15779.         return(NULL);
  15780.         }
  15781.     }
  15782.     }
  15783.  
  15784. #ifdef DEBUG
  15785.     if (deblog) {
  15786.     debug(F101,"remote_files havesize","",havesize);
  15787.     debug(F101,"remote_files havetype","",havetype);
  15788.     debug(F110,"remote_files havemdtm",havemdtm,0);    
  15789.     debug(F110,"remote_files name",p,0);    
  15790.     }
  15791. #endif /* DEBUG */
  15792.     return((CHAR *)p);
  15793. }
  15794.  
  15795. /* N O T  P O R T A B L E !!! */
  15796.  
  15797. #if (SIZEOF_SHORT == 4)
  15798. typedef unsigned short ftp_uint32;
  15799. typedef short ftp_int32;
  15800. #else
  15801. #if (SIZEOF_INT == 4)
  15802. typedef unsigned int ftp_uint32;
  15803. typedef int ftp_int32;
  15804. #else
  15805. #if (SIZEOF_LONG == 4)
  15806. typedef ULONG ftp_uint32;
  15807. typedef long ftp_int32;
  15808. #endif
  15809. #endif
  15810. #endif
  15811.  
  15812. /* Perhaps use these in general, certainly use them for GSSAPI */
  15813.  
  15814. #ifndef looping_write
  15815. #define ftp_int32 int
  15816. #define ftp_uint32 unsigned int
  15817. static int
  15818. looping_write(fd, buf, len)
  15819.     int fd;
  15820.     register CONST char *buf;
  15821.     int len;
  15822. {
  15823.     int cc;
  15824.     register int wrlen = len;
  15825.     do {
  15826.         cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
  15827.         if (cc < 0) {
  15828.             if (errno == EINTR)
  15829.               continue;
  15830.             return(cc);
  15831.         } else {
  15832.             buf += cc;
  15833.             wrlen -= cc;
  15834.         }
  15835.     } while (wrlen > 0);
  15836.     return(len);
  15837. }
  15838. #endif
  15839. #ifndef looping_read
  15840. static int
  15841. looping_read(fd, buf, len)
  15842.     int fd;
  15843.     register char *buf;
  15844.     register int len;
  15845. {
  15846.     int cc, len2 = 0;
  15847.  
  15848.     do {
  15849.         cc = recv(fd, (char *)buf, len,0);
  15850.         if (cc < 0) {
  15851.             if (errno == EINTR)
  15852.               continue;
  15853.             return(cc);                 /* errno is already set */
  15854.         } else if (cc == 0) {
  15855.             return(len2);
  15856.         } else {
  15857.             buf += cc;
  15858.             len2 += cc;
  15859.             len -= cc;
  15860.         }
  15861.     } while (len > 0);
  15862.     return(len2);
  15863. }
  15864. #endif /* looping_read */
  15865.  
  15866. #define ERR -2
  15867.  
  15868. #ifdef COMMENT
  15869. static
  15870. secure_putbyte(fd, c) int fd; CHAR c; {
  15871.     int ret;
  15872.  
  15873.     ucbuf[nout++] = c;
  15874.     if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
  15875.         nout = 0;
  15876.         if (!ftpissecure())
  15877.           ret = send(fd, (SENDARG2TYPE)ucbuf,
  15878.                      (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
  15879.         else
  15880.           ret = secure_putbuf(fd,
  15881.                               ucbuf,
  15882.                               (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
  15883.                               );
  15884.         return(ret?ret:c);
  15885.     }
  15886.     return(c);
  15887. }
  15888. #endif /* COMMENT */
  15889.  
  15890. /* returns:
  15891.  *       0  on success
  15892.  *      -1  on error (errno set)
  15893.  *      -2  on security error
  15894.  */
  15895. static int
  15896. secure_flush(fd) int fd; {
  15897.     int rc = 0;
  15898.     int len = 0;
  15899.  
  15900.     if (nout > 0) {
  15901.         len = nout;
  15902.         if (!ftpissecure()) {
  15903.             rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
  15904.             nout = 0;
  15905.             goto xflush;
  15906.         } else {
  15907.             rc = secure_putbuf(fd, ucbuf, nout);
  15908.             if (rc)
  15909.               goto xflush;
  15910.         }
  15911.     }
  15912.     rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
  15913.  
  15914.   xflush:
  15915.     if (rc > -1 && len > 0 && fdispla != XYFD_B) {
  15916.     spackets++;
  15917.         spktl = len;
  15918.         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
  15919.     }
  15920.     return(rc);
  15921. }
  15922.  
  15923. #ifdef COMMENT                          /* (not used) */
  15924. /* returns:
  15925.  *      c>=0  on success
  15926.  *      -1    on error
  15927.  *      -2    on security error
  15928.  */
  15929. static int
  15930. #ifdef CK_ANSIC
  15931. secure_putc(char c, int fd)
  15932. #else
  15933. secure_putc(c, fd) char c; int fd;
  15934. #endif /* CK_ANSIC */
  15935. /* secure_putc */ {
  15936.     return(secure_putbyte(fd, (CHAR) c));
  15937. }
  15938. #endif /* COMMENT */
  15939.  
  15940. /* returns:
  15941.  *      nbyte on success
  15942.  *      -1  on error (errno set)
  15943.  *      -2  on security error
  15944.  */
  15945. static int
  15946. #ifdef CK_ANSIC
  15947. secure_write(int fd, CHAR * buf, unsigned int nbyte)
  15948. #else
  15949. secure_write(fd, buf, nbyte)
  15950.     int fd;
  15951.     CHAR * buf;
  15952.     unsigned int nbyte;
  15953. #endif /* CK_ANSIC */
  15954. {
  15955.     int ret;
  15956.  
  15957. #ifdef FTP_TIMEOUT    
  15958.     ftp_timed_out = 0;
  15959.     if (check_data_connection(fd,1) < 0) {
  15960.     ftp_timed_out = 1;
  15961.     return(-3);
  15962.     }
  15963. #endif    /* FTP_TIMEOUT */
  15964.  
  15965.     if (!ftpissecure()) {
  15966.         if (nout > 0) {
  15967.             if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
  15968.               return(ret);
  15969.             nout = 0;
  15970.         }
  15971.         return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
  15972.     } else {
  15973.         int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
  15974.         int bsent = 0;
  15975.  
  15976.         while (bsent < nbyte) {
  15977.             int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
  15978.                         (ucbuflen - nout) : (nbyte - bsent));
  15979. #ifdef DEBUG
  15980.         if (deblog) {
  15981.         debug(F101,"secure_write ucbuflen","",ucbuflen);
  15982.         debug(F101,"secure_write ucbufsiz","",ucbufsiz);
  15983.         debug(F101,"secure_write bsent","",bsent);
  15984.         debug(F101,"secure_write b2cp","",b2cp);
  15985.         }
  15986. #endif /* DEBUG */
  15987.             memcpy(&ucbuf[nout],&buf[bsent],b2cp);
  15988.             nout += b2cp;
  15989.             bsent += b2cp;
  15990.  
  15991.             if (nout == ucbuflen) {
  15992.                 nout = 0;
  15993.                 ret = secure_putbuf(fd, ucbuf, ucbuflen);
  15994.                 if (ret < 0)
  15995.                   return(ret);
  15996.             }
  15997.         }
  15998.         return(bsent);
  15999.     }
  16000. }
  16001.  
  16002. /* returns:
  16003.  *       0  on success
  16004.  *      -1  on error (errno set)
  16005.  *      -2  on security error
  16006.  */
  16007. static int
  16008. #ifdef CK_ANSIC
  16009. secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
  16010. #else
  16011. secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
  16012. #endif /* CK_ANSIC */
  16013. {
  16014.     static char *outbuf = NULL;         /* output ciphertext */
  16015. #ifdef FTP_SECURITY
  16016.     static unsigned int bufsize = 0;    /* size of outbuf */
  16017. #endif /* FTP_SECURITY */
  16018.     ftp_int32 length   = 0;
  16019.     ftp_uint32 net_len = 0;
  16020.  
  16021.     /* Other auth types go here ... */
  16022. #ifdef CK_SSL
  16023.     if (ssl_ftp_data_active_flag) {
  16024.         int count, error;
  16025.  
  16026.         /* there is no need to send an empty buffer when using SSL/TLS */
  16027.         if ( nbyte == 0 )
  16028.       return(0);
  16029.  
  16030.         count = SSL_write(ssl_ftp_data_con, buf, nbyte);
  16031.         error = SSL_get_error(ssl_ftp_data_con,count);
  16032.         switch (error) {
  16033.           case SSL_ERROR_NONE:
  16034.             return(0);
  16035.           case SSL_ERROR_WANT_WRITE:
  16036.           case SSL_ERROR_WANT_READ:
  16037.           case SSL_ERROR_SYSCALL:
  16038. #ifdef NT
  16039.             {
  16040.                 int gle = GetLastError();
  16041.         if (gle == 0)
  16042.           return(0);
  16043.         debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
  16044.             }
  16045. #endif /* NT */
  16046.           case SSL_ERROR_WANT_X509_LOOKUP:
  16047.           case SSL_ERROR_SSL:
  16048.           case SSL_ERROR_ZERO_RETURN:
  16049.           default:
  16050.             SSL_shutdown(ssl_ftp_data_con);
  16051.             SSL_free(ssl_ftp_data_con);
  16052.             ssl_ftp_data_active_flag = 0;
  16053.             ssl_ftp_data_con = NULL;
  16054. #ifdef TCPIPLIB
  16055.             socket_close(data);
  16056. #else /* TCPIPLIB */
  16057. #ifdef USE_SHUTDOWN
  16058.             shutdown(data, 1+1);
  16059. #endif /* USE_SHUTDOWN */
  16060.             close(data);
  16061. #endif /* TCPIPLIB */
  16062.             data = -1;
  16063.             globaldin = data;
  16064.             return(-1);
  16065.         }
  16066.         return(-1);
  16067.     }
  16068. #endif /* CK_SSL */
  16069.  
  16070. #ifdef FTP_SRP
  16071.     if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
  16072.         if (bufsize < nbyte + FUDGE_FACTOR) {
  16073.             if (outbuf?
  16074.                 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
  16075.                 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
  16076.                 bufsize = nbyte + FUDGE_FACTOR;
  16077.             } else {
  16078.                 bufsize = 0;
  16079.                 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
  16080.                 return(ERR);
  16081.             }
  16082.         }
  16083.         if ((length =
  16084.              srp_encode(ftp_dpl == FPL_PRV,
  16085.                         (CHAR *) buf,
  16086.                         (CHAR *) outbuf,
  16087.                         nbyte
  16088.                         )
  16089.              ) < 0) {
  16090.             secure_error ("srp_encode failed");
  16091.             return ERR;
  16092.         }
  16093.     }
  16094. #endif /* FTP_SRP */
  16095. #ifdef FTP_KRB4
  16096.     if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
  16097.         struct sockaddr_in myaddr, hisaddr;
  16098.         GSOCKNAME_T len;
  16099.         len = sizeof(myaddr);
  16100.         if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
  16101.             secure_error("secure_putbuf: getsockname failed");
  16102.             return(ERR);
  16103.         }
  16104.         len = sizeof(hisaddr);
  16105.         if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
  16106.             secure_error("secure_putbuf: getpeername failed");
  16107.             return(ERR);
  16108.         }
  16109.         if (bufsize < nbyte + FUDGE_FACTOR) {
  16110.             if (outbuf ?
  16111.                 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
  16112.                  (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
  16113.                 bufsize = nbyte + FUDGE_FACTOR;
  16114.             } else {
  16115.                 bufsize = 0;
  16116.                 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
  16117.                 return(ERR);
  16118.             }
  16119.         }
  16120.         if (ftp_dpl == FPL_PRV) {
  16121.             length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
  16122.                                  ftp_sched,
  16123. #ifdef KRB524
  16124.                                  ftp_cred.session,
  16125. #else /* KRB524 */
  16126.                                  &ftp_cred.session,
  16127. #endif /* KRB524 */
  16128.                                  &myaddr,
  16129.                                  &hisaddr
  16130.                                  );
  16131.         } else {
  16132.             length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
  16133. #ifdef KRB524
  16134.                                  ftp_cred.session,
  16135. #else /* KRB524 */
  16136.                                  &ftp_cred.session,
  16137. #endif /* KRB524 */
  16138.                                  &myaddr,
  16139.                                  &hisaddr
  16140.                                  );
  16141.         }
  16142.         if (length == -1) {
  16143.             secure_error("krb_mk_%s failed for KERBEROS_V4",
  16144.                          ftp_dpl == FPL_PRV ? "priv" : "safe");
  16145.             return(ERR);
  16146.         }
  16147.     }
  16148. #endif /* FTP_KRB4 */
  16149. #ifdef FTP_GSSAPI
  16150.     if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
  16151.         gss_buffer_desc in_buf, out_buf;
  16152.         OM_uint32 maj_stat, min_stat;
  16153.         int conf_state;
  16154.  
  16155.         in_buf.value = buf;
  16156.         in_buf.length = nbyte;
  16157.         maj_stat = gss_seal(&min_stat, gcontext,
  16158.                             (ftp_dpl == FPL_PRV), /* confidential */
  16159.                             GSS_C_QOP_DEFAULT,
  16160.                             &in_buf,
  16161.                             &conf_state,
  16162.                             &out_buf
  16163.                             );
  16164.         if (maj_stat != GSS_S_COMPLETE) {
  16165.             /* generally need to deal */
  16166.             /* ie. should loop, but for now just fail */
  16167.             user_gss_error(maj_stat, min_stat,
  16168.                            ftp_dpl == FPL_PRV?
  16169.                            "GSSAPI seal failed":
  16170.                            "GSSAPI sign failed");
  16171.             return(ERR);
  16172.         }
  16173.         if (bufsize < out_buf.length) {
  16174.             if (outbuf ?
  16175.                 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
  16176.                 (outbuf = malloc((unsigned) out_buf.length))) {
  16177.                 bufsize = out_buf.length;
  16178.             } else {
  16179.                 bufsize = 0;
  16180.                 secure_error("%s (in malloc of PROT buffer)",
  16181.                              ck_errstr());
  16182.                 return(ERR);
  16183.             }
  16184.         }
  16185.         memcpy(outbuf, out_buf.value, length=out_buf.length);
  16186.         gss_release_buffer(&min_stat, &out_buf);
  16187.     }
  16188. #endif /* FTP_GSSAPI */
  16189.     net_len = htonl((ULONG) length);
  16190.     if (looping_write(fd, (char *)&net_len, 4) == -1)
  16191.       return(-1);
  16192.     if (looping_write(fd, outbuf, length) != length)
  16193.       return(-1);
  16194.     return(0);
  16195. }
  16196.  
  16197.  
  16198. /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
  16199.  
  16200. static int
  16201. secure_getbyte(fd,fc) int fd,fc; {
  16202.     /* number of chars in ucbuf, pointer into ucbuf */
  16203.     static unsigned int nin = 0, bufp = 0;
  16204.     int kerror;
  16205.     ftp_uint32 length;
  16206.  
  16207.     if (fc) {
  16208.     nin = bufp = 0;
  16209.     ucbuf[0] = NUL;
  16210.     return(0);
  16211.     }
  16212.     if (nin == 0) {
  16213.         if (iscanceled())
  16214.           return(-9);
  16215.  
  16216. #ifdef FTP_TIMEOUT
  16217.     if (check_data_connection(fd,0) < 0)
  16218.       return(-3);
  16219. #endif    /* FTP_TIMEOUT */
  16220.  
  16221. #ifdef CK_SSL
  16222.         if (ssl_ftp_data_active_flag) {
  16223.             int count, error;
  16224.             count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
  16225.             error = SSL_get_error(ssl_ftp_data_con,count);
  16226. #ifdef DEBUG
  16227.         if (error != SSL_ERROR_NONE)
  16228.           debug(F101,"ftp secure_getbyte error","",error);
  16229.         if (count == 0)
  16230.           debug(F101,"ftp secure_getbyte count","",count);
  16231. #endif    /* DEBUG */
  16232.             switch (error) {
  16233.               case SSL_ERROR_NONE:
  16234.         if (count > 0) {
  16235.             nin = bufp = count;
  16236.             rpackets++;
  16237.             pktnum++;
  16238.             if (fdispla != XYFD_B) {
  16239.             rpktl = count;
  16240.             ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
  16241.             }
  16242.             break;
  16243.         }
  16244.               case SSL_ERROR_WANT_WRITE:
  16245.               case SSL_ERROR_WANT_READ:
  16246.               case SSL_ERROR_SYSCALL:
  16247. #ifdef NT
  16248.                 {
  16249.                     int gle = GetLastError();
  16250.                 }
  16251. #endif /* NT */
  16252.               case SSL_ERROR_WANT_X509_LOOKUP:
  16253.               case SSL_ERROR_SSL:
  16254.               case SSL_ERROR_ZERO_RETURN:
  16255.               default:
  16256.                 nin = bufp = count = 0;
  16257.                 SSL_shutdown(ssl_ftp_data_con);
  16258.                 SSL_free(ssl_ftp_data_con);
  16259.                 ssl_ftp_data_active_flag = 0;
  16260.                 ssl_ftp_data_con = NULL;
  16261. #ifdef TCPIPLIB
  16262.                 socket_close(data);
  16263. #else /* TCPIPLIB */
  16264. #ifdef USE_SHUTDOWN
  16265.                 shutdown(data, 1+1);
  16266. #endif /* USE_SHUTDOWN */
  16267.                 close(data);
  16268. #endif /* TCPIPLIB */
  16269.                 data = -1;
  16270.                 globaldin = data;
  16271.                 break;
  16272.             }
  16273.         } else
  16274. #endif /* CK_SSL */
  16275.           {
  16276.               kerror = looping_read(fd, (char *)&length, sizeof(length));
  16277.               if (kerror != sizeof(length)) {
  16278.                   secure_error("Couldn't read PROT buffer length: %d/%s",
  16279.                                kerror,
  16280.                                kerror == -1 ? ck_errstr()
  16281.                                : "premature EOF"
  16282.                                );
  16283.                   return(ERR);
  16284.               }
  16285.               debug(F101,"secure_getbyte length","",length);
  16286.               debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
  16287.  
  16288.               length = (ULONG) ntohl(length);
  16289.               if (length > maxbuf) {
  16290.                   secure_error("Length (%d) of PROT buffer > PBSZ=%u",
  16291.                                length,
  16292.                                maxbuf
  16293.                                );
  16294.                   return(ERR);
  16295.               }
  16296.               if ((kerror = looping_read(fd, ucbuf, length)) != length) {
  16297.                   secure_error("Couldn't read %u byte PROT buffer: %s",
  16298.                                length,
  16299.                                kerror == -1 ? ck_errstr() : "premature EOF"
  16300.                                );
  16301.                   return(ERR);
  16302.               }
  16303.  
  16304.               /* Other auth types go here ... */
  16305. #ifdef FTP_SRP
  16306.               if (strcmp(auth_type, "SRP") == 0) {
  16307.                   if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
  16308.                                                 (CHAR *) ucbuf,
  16309.                                                 ucbuf,
  16310.                                                 length
  16311.                                                 )
  16312.                        ) == -1) {
  16313.                       secure_error ("srp_encode failed" );
  16314.                       return ERR;
  16315.                   }
  16316.               }
  16317. #endif /* FTP_SRP */
  16318. #ifdef FTP_KRB4
  16319.               if (strcmp(auth_type, "KERBEROS_V4") == 0) {
  16320.                   struct sockaddr_in myaddr, hisaddr;
  16321.                   GSOCKNAME_T len;
  16322.                   len = sizeof(myaddr);
  16323.                   if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
  16324.                       secure_error("secure_putbuf: getsockname failed");
  16325.                       return(ERR);
  16326.                   }
  16327.                   len = sizeof(hisaddr);
  16328.                   if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
  16329.                       secure_error("secure_putbuf: getpeername failed");
  16330.                       return(ERR);
  16331.                   }
  16332.                   if (ftp_dpl) {
  16333.                       kerror = krb_rd_priv(ucbuf, length, ftp_sched,
  16334. #ifdef KRB524
  16335.                                            ftp_cred.session,
  16336. #else /* KRB524 */
  16337.                                            &ftp_cred.session,
  16338. #endif /* KRB524 */
  16339.                                            &hisaddr, &myaddr, &ftp_msg_data);
  16340.                   } else {
  16341.                       kerror = krb_rd_safe(ucbuf, length,
  16342. #ifdef KRB524
  16343.                                            ftp_cred.session,
  16344. #else /* KRB524 */
  16345.                                            &ftp_cred.session,
  16346. #endif /* KRB524 */
  16347.                                            &hisaddr, &myaddr, &ftp_msg_data);
  16348.                   }
  16349.                   if (kerror) {
  16350.                       secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
  16351.                                    ftp_dpl == FPL_PRV ? "priv" : "safe",
  16352.                                    krb_get_err_text(kerror));
  16353.                       return(ERR);
  16354.                   }
  16355.                   memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
  16356.                   nin = bufp = ftp_msg_data.app_length;
  16357.               }
  16358. #endif /* FTP_KRB4 */
  16359. #ifdef FTP_GSSAPI
  16360.               if (strcmp(auth_type, "GSSAPI") == 0) {
  16361.                   gss_buffer_desc xmit_buf, msg_buf;
  16362.                   OM_uint32 maj_stat, min_stat;
  16363.                   int conf_state;
  16364.  
  16365.                   xmit_buf.value = ucbuf;
  16366.                   xmit_buf.length = length;
  16367.                   conf_state = (ftp_dpl == FPL_PRV);
  16368.                   /* decrypt/verify the message */
  16369.                   maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
  16370.                                         &msg_buf, &conf_state, NULL);
  16371.                   if (maj_stat != GSS_S_COMPLETE) {
  16372.                       user_gss_error(maj_stat, min_stat,
  16373.                                      (ftp_dpl == FPL_PRV)?
  16374.                                      "failed unsealing ENC message":
  16375.                                      "failed unsealing MIC message");
  16376.                       return ERR;
  16377.                   }
  16378.                   memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
  16379.                   gss_release_buffer(&min_stat, &msg_buf);
  16380.               }
  16381. #endif /* FTP_GSSAPI */
  16382.               /* Other auth types go here ... */
  16383.  
  16384.               /* Update file transfer display */
  16385.               rpackets++;
  16386.               pktnum++;
  16387.               if (fdispla != XYFD_B) {
  16388.                   rpktl = nin;
  16389.                   ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
  16390.               }
  16391.           }
  16392.     }
  16393.     if (nin == 0)
  16394.       return(EOF);
  16395.     else
  16396.       return(ucbuf[bufp - nin--]);
  16397. }
  16398.  
  16399. /* secure_getc(fd,fc)
  16400.  * Call with:
  16401.  *   fd = file descriptor for connection.
  16402.  *   fc = 0 to get a character, fc != 0 to initialize buffer pointers.
  16403.  * Returns:
  16404.  *   c>=0 on success (character value)
  16405.  *   -1   on EOF
  16406.  *   -2   on security error
  16407.  *   -3   on timeout (if built with FTP_TIMEOUT defined)
  16408.  */
  16409. static int
  16410. secure_getc(fd,fc) int fd,fc; {        /* file descriptor, function code */
  16411.  
  16412.     if (!ftpissecure()) {
  16413.         static unsigned int nin = 0, bufp = 0;
  16414.     if (fc) {
  16415.         nin = bufp = 0;
  16416.         ucbuf[0] = NUL;
  16417.         return(0);
  16418.     }
  16419.         if (nin == 0) {
  16420.             if (iscanceled())
  16421.               return(-9);
  16422.  
  16423. #ifdef FTP_TIMEOUT
  16424.         if (check_data_connection(fd,0) < 0) {
  16425.                 debug(F100,"secure_getc TIMEOUT","",0);
  16426.                 nin = bufp = 0;
  16427.         ftp_timed_out = 1;
  16428.         return(-3);
  16429.         }        
  16430. #endif    /* FTP_TIMEOUT */
  16431.  
  16432.             nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
  16433.             if ((nin == 0) || (nin == (unsigned int)-1)) {
  16434.                 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
  16435.                 debug(F101,"secure_getc returns EOF","",EOF);
  16436.                 nin = bufp = 0;
  16437.                 return(EOF);
  16438.             }
  16439.             debug(F101,"ftp secure_getc recv","",nin);
  16440.             ckhexdump("ftp secure_getc recv",ucbuf,16);
  16441.             rpackets++;
  16442.             pktnum++;
  16443.             if (fdispla != XYFD_B) {
  16444.                 rpktl = nin;
  16445.                 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
  16446.             }
  16447.         }
  16448.         return(ucbuf[bufp - nin--]);
  16449.     } else
  16450.       return(secure_getbyte(fd,fc));
  16451. }
  16452.  
  16453. /* returns:
  16454.  *     n>0  on success (n == # of bytes read)
  16455.  *       0  on EOF
  16456.  *      -1  on error (errno set), only for FPL_CLR
  16457.  *      -2  on security error
  16458.  */
  16459. static int
  16460. secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
  16461.     static int c = 0;
  16462.     int i;
  16463.  
  16464.     debug(F101,"secure_read bytes requested","",nbyte);
  16465.     if (c == EOF)
  16466.       return(c = 0);
  16467.     for (i = 0; nbyte > 0; nbyte--) {
  16468.         c = secure_getc(fd,0);
  16469.         switch (c) {
  16470.           case -9:                      /* Canceled from keyboard */
  16471.             debug(F101,"ftp secure_read interrupted","",c);
  16472.             return(0);
  16473.           case ERR:
  16474.             debug(F101,"ftp secure_read error","",c);
  16475.             return(c);
  16476.           case EOF:
  16477.             debug(F101,"ftp secure_read EOF","",c);
  16478.             if (!i)
  16479.               c = 0;
  16480.             return(i);
  16481. #ifdef FTP_TIMEOUT
  16482.           case -3:
  16483.             debug(F101,"ftp secure_read timeout","",c);
  16484.         return(c);
  16485. #endif    /* FTP_TIMEOUT */
  16486.           default:
  16487.             buf[i++] = c;
  16488.         }
  16489.     }
  16490.     return(i);
  16491. }
  16492.  
  16493. #ifdef USE_RUSERPASS
  16494. /* BEGIN_RUSERPASS
  16495.  *
  16496.  * Copyright (c) 1985 Regents of the University of California.
  16497.  * All rights reserved.
  16498.  *
  16499.  * Redistribution and use in source and binary forms, with or without
  16500.  * modification, are permitted provided that the following conditions
  16501.  * are met:
  16502.  * 1. Redistributions of source code must retain the above copyright
  16503.  *    notice, this list of conditions and the following disclaimer.
  16504.  * 2. Redistributions in binary form must reproduce the above copyright
  16505.  *    notice, this list of conditions and the following disclaimer in the
  16506.  *    documentation and/or other materials provided with the distribution.
  16507.  * 3. All advertising materials mentioning features or use of this software
  16508.  *    must display the following acknowledgement:
  16509.  *      This product includes software developed by the University of
  16510.  *      California, Berkeley and its contributors.
  16511.  * 4. Neither the name of the University nor the names of its contributors
  16512.  *    may be used to endorse or promote products derived from this software
  16513.  *    without specific prior written permission.
  16514.  *
  16515.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  16516.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16517.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16518.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  16519.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  16520.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  16521.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  16522.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  16523.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  16524.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  16525.  * SUCH DAMAGE.
  16526.  */
  16527.  
  16528. #ifndef lint
  16529. static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
  16530. #endif /* not lint */
  16531.  
  16532. #ifndef MAXHOSTNAMELEN
  16533. #define MAXHOSTNAMELEN 64
  16534. #endif
  16535.  
  16536. char * renvlook();
  16537. static FILE * cfile;
  16538.  
  16539. #define DEFAULT 1
  16540. #define LOGIN   2
  16541. #define PASSWD  3
  16542. #define ACCOUNT 4
  16543. #define MACDEF  5
  16544. #define ID      10
  16545. #define MACH    11
  16546.  
  16547. static char tokval[100];
  16548.  
  16549. static struct toktab {
  16550.     char *tokstr;
  16551.     int tval;
  16552. } toktab[]= {
  16553.     "default",  DEFAULT,
  16554.     "login",    LOGIN,
  16555.     "password", PASSWD,
  16556.     "passwd",   PASSWD,
  16557.     "account",  ACCOUNT,
  16558.     "machine",  MACH,
  16559.     "macdef",   MACDEF,
  16560.     0,          0
  16561. };
  16562.  
  16563. static int
  16564. token() {
  16565.     char *cp;
  16566.     int c;
  16567.     struct toktab *t;
  16568.  
  16569.     if (feof(cfile))
  16570.       return(0);
  16571.     while ((c = getc(cfile)) != EOF &&
  16572.            (c == '\n' || c == '\t' || c == ' ' || c == ','))
  16573.       continue;
  16574.     if (c == EOF)
  16575.       return(0);
  16576.     cp = tokval;
  16577.     if (c == '"') {
  16578.         while ((c = getc(cfile)) != EOF && c != '"') {
  16579.             if (c == '\\')
  16580.               c = getc(cfile);
  16581.             *cp++ = c;
  16582.         }
  16583.     } else {
  16584.         *cp++ = c;
  16585.         while ((c = getc(cfile)) != EOF
  16586.                && c != '\n' && c != '\t' && c != ' ' && c != ',') {
  16587.             if (c == '\\')
  16588.               c = getc(cfile);
  16589.             *cp++ = c;
  16590.         }
  16591.     }
  16592.     *cp = 0;
  16593.     if (tokval[0] == 0)
  16594.       return(0);
  16595.     for (t = toktab; t->tokstr; t++)
  16596.       if (!strcmp(t->tokstr, tokval))
  16597.         return(t->tval);
  16598.     return(ID);
  16599. }
  16600.  
  16601. ruserpass(host, aname, apass, aacct)
  16602.     char *host, **aname, **apass, **aacct;
  16603. {
  16604.     char *hdir, buf[FTP_BUFSIZ], *tmp;
  16605.     char myname[MAXHOSTNAMELEN], *mydomain;
  16606.     int t, i, c, usedefault = 0;
  16607. #ifdef NT
  16608.     struct _stat stb;
  16609. #else /* NT */
  16610.     struct stat stb;
  16611. #endif /* NT */
  16612.  
  16613.     hdir = getenv("HOME");
  16614.     if (hdir == NULL)
  16615.         hdir = ".";
  16616.     ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
  16617.     cfile = fopen(buf, "r");
  16618.     if (cfile == NULL) {
  16619.         if (errno != ENOENT)
  16620.           perror(buf);
  16621.         return(0);
  16622.     }
  16623.     if (gethostname(myname, MAXHOSTNAMELEN) < 0)
  16624.       myname[0] = '\0';
  16625.     if ((mydomain = ckstrchr(myname, '.')) == NULL)
  16626.       mydomain = "";
  16627.  
  16628.   next:
  16629.     while ((t = token())) switch(t) {
  16630.  
  16631.       case DEFAULT:
  16632.         usedefault = 1;
  16633.         /* FALL THROUGH */
  16634.  
  16635.       case MACH:
  16636.         if (!usedefault) {
  16637.             if (token() != ID)
  16638.               continue;
  16639.             /*
  16640.              * Allow match either for user's input host name
  16641.              * or official hostname.  Also allow match of
  16642.              * incompletely-specified host in local domain.
  16643.              */
  16644.             if (ckstrcmp(host, tokval,-1,1) == 0)
  16645.               goto match;
  16646.             if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
  16647.               goto match;
  16648.             if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
  16649.                 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
  16650.                 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
  16651.                 tokval[tmp - ftp_host] == '\0')
  16652.               goto match;
  16653.             if ((tmp = ckstrchr(host, '.')) != NULL &&
  16654.                 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
  16655.                 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
  16656.                 tokval[tmp - host] == '\0')
  16657.               goto match;
  16658.             continue;
  16659.         }
  16660.  
  16661.       match:
  16662.         while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
  16663.  
  16664.           case LOGIN:
  16665.             if (token())
  16666.               if (*aname == 0) {
  16667.                   *aname = malloc((unsigned) strlen(tokval) + 1);
  16668.                   strcpy(*aname, tokval);      /* safe */
  16669.               } else {
  16670.                   if (strcmp(*aname, tokval))
  16671.                     goto next;
  16672.               }
  16673.             break;
  16674.           case PASSWD:
  16675.             if (strcmp(*aname, "anonymous") &&
  16676.                 fstat(fileno(cfile), &stb) >= 0 &&
  16677.                 (stb.st_mode & 077) != 0) {
  16678.                 fprintf(stderr, "Error - .netrc file not correct mode.\n");
  16679.                 fprintf(stderr, "Remove password or correct mode.\n");
  16680.                 goto bad;
  16681.             }
  16682.             if (token() && *apass == 0) {
  16683.                 *apass = malloc((unsigned) strlen(tokval) + 1);
  16684.                 strcpy(*apass, tokval);          /* safe */
  16685.             }
  16686.             break;
  16687.           case ACCOUNT:
  16688.             if (fstat(fileno(cfile), &stb) >= 0
  16689.                 && (stb.st_mode & 077) != 0) {
  16690.                 fprintf(stderr, "Error - .netrc file not correct mode.\n");
  16691.                 fprintf(stderr, "Remove account or correct mode.\n");
  16692.                 goto bad;
  16693.             }
  16694.             if (token() && *aacct == 0) {
  16695.                 *aacct = malloc((unsigned) strlen(tokval) + 1);
  16696.                 strcpy(*aacct, tokval);          /* safe */
  16697.             }
  16698.             break;
  16699.  
  16700.           default:
  16701.             fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
  16702.             break;
  16703.         }
  16704.         goto done;
  16705.     }
  16706.  
  16707.   done:
  16708.     fclose(cfile);
  16709.     return(0);
  16710.  
  16711.   bad:
  16712.     fclose(cfile);
  16713.     return(-1);
  16714. }
  16715. #endif /* USE_RUSERPASS */
  16716.  
  16717. static char *radixN =
  16718.   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  16719.  
  16720. static char pad = '=';
  16721.  
  16722. static int
  16723. radix_encode(inbuf, outbuf, inlen, outlen, decode)
  16724.     CHAR inbuf[], outbuf[];
  16725.     int inlen, *outlen, decode;
  16726. {
  16727.     int i, j, D = 0;
  16728.     char *p;
  16729.     CHAR c = NUL;
  16730.  
  16731.     if (decode) {
  16732.         for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
  16733.             if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
  16734.               return(1);
  16735.             D = p - radixN;
  16736.             switch (i&3) {
  16737.               case 0:
  16738.                 outbuf[j] = D<<2;
  16739.                 break;
  16740.               case 1:
  16741.                 outbuf[j++] |= D>>4;
  16742.                 outbuf[j] = (D&15)<<4;
  16743.                 break;
  16744.               case 2:
  16745.                 outbuf[j++] |= D>>2;
  16746.                 outbuf[j] = (D&3)<<6;
  16747.                 break;
  16748.               case 3:
  16749.                 outbuf[j++] |= D;
  16750.             }
  16751.             if (j == *outlen)
  16752.               return(4);
  16753.         }
  16754.         switch (i&3) {
  16755.           case 1: return(3);
  16756.           case 2: if (D&15) return(3);
  16757.             if (strcmp((char *)&inbuf[i], "==")) return(2);
  16758.             break;
  16759.           case 3: if (D&3) return(3);
  16760.             if (strcmp((char *)&inbuf[i], "="))  return(2);
  16761.         }
  16762.         *outlen = j;
  16763.     } else {
  16764.         for (i = 0, j = 0; i < inlen; i++) {
  16765.             switch (i%3) {
  16766.               case 0:
  16767.                 outbuf[j++] = radixN[inbuf[i]>>2];
  16768.                 c = (inbuf[i]&3)<<4;
  16769.                 break;
  16770.               case 1:
  16771.                 outbuf[j++] = radixN[c|inbuf[i]>>4];
  16772.                 c = (inbuf[i]&15)<<2;
  16773.                 break;
  16774.               case 2:
  16775.                 outbuf[j++] = radixN[c|inbuf[i]>>6];
  16776.                 outbuf[j++] = radixN[inbuf[i]&63];
  16777.                 c = 0;
  16778.             }
  16779.             if (j == *outlen)
  16780.               return(4);
  16781.         }
  16782.         if (i%3) outbuf[j++] = radixN[c];
  16783.         switch (i%3) {
  16784.           case 1: outbuf[j++] = pad;
  16785.           case 2: outbuf[j++] = pad;
  16786.         }
  16787.         outbuf[*outlen = j] = '\0';
  16788.     }
  16789.     return(0);
  16790. }
  16791.  
  16792. static char *
  16793. radix_error(e) int e;
  16794. {
  16795.     switch (e) {
  16796.       case 0:  return("Success");
  16797.       case 1:  return("Bad character in encoding");
  16798.       case 2:  return("Encoding not properly padded");
  16799.       case 3:  return("Decoded # of bits not a multiple of 8");
  16800.       case 4:  return("Output buffer too small");
  16801.       default: return("Unknown error");
  16802.     }
  16803. }
  16804. /* END_RUSERPASS */
  16805.  
  16806. #ifdef FTP_SRP
  16807. /*---------------------------------------------------------------------------+
  16808.  |                                                                           |
  16809.  |   Package: srpftp                                                         |
  16810.  |   Author: Eugene Jhong                                                    |
  16811.  |                                                                           |
  16812.  +---------------------------------------------------------------------------*/
  16813.  
  16814. /*
  16815.  * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
  16816.  * All Rights Reserved.
  16817.  *
  16818.  * Permission is hereby granted, free of charge, to any person obtaining
  16819.  * a copy of this software and associated documentation files (the
  16820.  * "Software"), to deal in the Software without restriction, including
  16821.  * without limitation the rights to use, copy, modify, merge, publish,
  16822.  * distribute, sublicense, and/or sell copies of the Software, and to
  16823.  * permit persons to whom the Software is furnished to do so, subject to
  16824.  * the following conditions:
  16825.  *
  16826.  * The above copyright notice and this permission notice shall be
  16827.  * included in all copies or substantial portions of the Software.
  16828.  *
  16829.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  16830.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  16831.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  16832.  *
  16833.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  16834.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16835.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
  16836.  * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
  16837.  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16838.  *
  16839.  * In addition, the following conditions apply:
  16840.  *
  16841.  * 1. Any software that incorporates the SRP authentication technology
  16842.  *    must display the following acknowlegment:
  16843.  *    "This product uses the 'Secure Remote Password' cryptographic
  16844.  *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
  16845.  *
  16846.  * 2. Any software that incorporates all or part of the SRP distribution
  16847.  *    itself must also display the following acknowledgment:
  16848.  *    "This product includes software developed by Tom Wu and Eugene
  16849.  *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
  16850.  *
  16851.  * 3. Redistributions in source or binary form must retain an intact copy
  16852.  *    of this copyright notice and list of conditions.
  16853.  */
  16854.  
  16855. #define SRP_PROT_VERSION        1
  16856.  
  16857. #ifdef CK_ENCRYPTION
  16858. #define SRP_DEFAULT_CIPHER      CIPHER_ID_CAST5_CBC
  16859. #else
  16860. #define SRP_DEFAULT_CIPHER      CIPHER_ID_NONE
  16861. #endif /* CK_ENCRYPTION */
  16862.  
  16863. #define SRP_DEFAULT_HASH        HASH_ID_SHA
  16864.  
  16865. CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
  16866. CHAR srp_pref_hash = HASH_ID_SHA;
  16867.  
  16868. static struct t_client *tc = NULL;
  16869. static CHAR *skey = NULL;
  16870. static krypto_context *incrypt = NULL;
  16871. static krypto_context *outcrypt = NULL;
  16872.  
  16873. typedef unsigned int srp_uint32;
  16874.  
  16875. /*--------------------------------------------------------------+
  16876.  | srp_selcipher: select cipher                                 |
  16877.  +--------------------------------------------------------------*/
  16878. static int
  16879. srp_selcipher (cname) char *cname; {
  16880.     cipher_desc *cd;
  16881.  
  16882.     if (!(cd = cipher_getdescbyname (cname))) {
  16883.         int i;
  16884.         CHAR *list = cipher_getlist ();
  16885.  
  16886.         fprintf (stderr, "ftp: supported ciphers:\n\n");
  16887.         for (i = 0; i < strlen (list); i++)
  16888.           fprintf (stderr, "    %s\n", (cipher_getdescbyid(list[i]))->name);
  16889.         fprintf (stderr, "\n");
  16890.         return -1;
  16891.     }
  16892.     srp_pref_cipher = cd->id;
  16893.     return 0;
  16894. }
  16895.  
  16896. /*--------------------------------------------------------------+
  16897.  | srp_selhash: select hash                                     |
  16898.  +--------------------------------------------------------------*/
  16899. static int
  16900. srp_selhash (hname) char *hname; {
  16901.     hash_desc *hd;
  16902.  
  16903.     if (!(hd = hash_getdescbyname (hname))) {
  16904.         int i;
  16905.         CHAR *list = hash_getlist ();
  16906.  
  16907.         fprintf (stderr, "ftp: supported hash functions:\n\n");
  16908.         for (i = 0; i < strlen (list); i++)
  16909.           fprintf (stderr, "    %s\n", (hash_getdescbyid(list[i]))->name);
  16910.         fprintf (stderr, "\n");
  16911.         return -1;
  16912.     }
  16913.     srp_pref_hash = hd->id;
  16914.     return 0;
  16915. }
  16916.  
  16917. /*--------------------------------------------------------------+
  16918.  | srp_userpass: get username and password                      |
  16919.  +--------------------------------------------------------------*/
  16920. static int
  16921. srp_userpass (host) char *host; {
  16922.     char tmp[BUFSIZ], prompt[PROMPTSIZ];
  16923.     char *user;
  16924.  
  16925.     user = NULL;
  16926. #ifdef USE_RUSERPASS
  16927.     ruserpass (host, &user, &srp_pass, &srp_acct);
  16928. #endif /* USE_RUSERPASS */
  16929.  
  16930.     while (user == NULL)     {
  16931.         char *myname;
  16932.         int ok;
  16933.  
  16934.         myname = whoami();
  16935.         if (!myname) myname = "";
  16936.         if (myname[0])
  16937.           ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
  16938.                     NULL,NULL,NULL,NULL,NULL,NULL,NULL);
  16939.         else
  16940.           ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
  16941.         tmp[0] = '\0';
  16942.         ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
  16943.                     DEFAULT_UQ_TIMEOUT);
  16944.         if (!ok || *tmp == '\0')
  16945.           user = myname;
  16946.         else
  16947.           user = brstrip(tmp);
  16948.     }
  16949.     ckstrncpy (srp_user, user,BUFSIZ);
  16950.     return(0);
  16951. }
  16952.  
  16953. /*--------------------------------------------------------------+
  16954.  | srp_reset: reset srp information                             |
  16955.  +--------------------------------------------------------------*/
  16956. static int
  16957. srp_reset () {
  16958.     if (tc) { t_clientclose (tc); tc = NULL; }
  16959.     if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
  16960.     if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
  16961.     return(0);
  16962. }
  16963.  
  16964. /*--------------------------------------------------------------+
  16965.  | srp_ftp_auth: perform srp authentication                         |
  16966.  +--------------------------------------------------------------*/
  16967. static int
  16968. srp_ftp_auth(host, user, pass)
  16969.     char *host;
  16970.     char *user;
  16971.     char *pass;
  16972. {
  16973.     struct t_num *wp;
  16974.     struct t_num N;
  16975.     struct t_num g;
  16976.     struct t_num s;
  16977.     struct t_num yp;
  16978.     CHAR buf[FTP_BUFSIZ];
  16979.     CHAR tmp[FTP_BUFSIZ];
  16980.     CHAR *bp, *cp;
  16981.     int n, e, clen, blen, len, i;
  16982.     CHAR cid = 0;
  16983.     CHAR hid = 0;
  16984.  
  16985.     srp_pass = srp_acct = 0;
  16986.  
  16987.     n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
  16988.     if (n != REPLY_CONTINUE) {
  16989.         if (ftp_deb)
  16990.             fprintf(stderr, "SRP rejected as an authentication type\n");
  16991.         return(0);
  16992.     } else {                            /* Send protocol version */
  16993.         CHAR vers[4];
  16994.         memset (vers, 0, 4);
  16995.         vers[3] = SRP_PROT_VERSION;
  16996.         if (!quiet)
  16997.           printf ("SRP accepted as authentication type.\n");
  16998.         bp = tmp; blen = 0;
  16999.         srp_put (vers, &bp, 4, &blen);
  17000.         len = FTP_BUFSIZ;
  17001.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17002.           goto encode_error;
  17003.         reply_parse = "ADAT=";
  17004.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17005.     }
  17006.     if (n == REPLY_CONTINUE) {          /* Get protocol version */
  17007.         bp = buf;
  17008.         if (!reply_parse)
  17009.           goto data_error;
  17010.         blen = FTP_BUFSIZ;
  17011.         if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
  17012.           goto decode_error;
  17013.         if (srp_get (&bp, &cp, &blen, &clen) != 4)
  17014.           goto data_error;
  17015.  
  17016.         if (host) {                     /* Get username/password if needed */
  17017.             srp_userpass (host);
  17018.         } else {
  17019.             ckstrncpy (srp_user, user, BUFSIZ);
  17020.             srp_pass = pass;
  17021.         }
  17022.         bp = tmp; blen = 0;             /* Send username */
  17023.         srp_put (srp_user, &bp, strlen (srp_user), &blen);
  17024.         len = FTP_BUFSIZ;
  17025.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17026.           goto encode_error;
  17027.         reply_parse = "ADAT=";
  17028.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17029.     }
  17030.     if (n == REPLY_CONTINUE) {          /* Get N, g and s */
  17031.         bp = buf;
  17032.         if (!reply_parse)
  17033.           goto data_error;
  17034.         blen = FTP_BUFSIZ;
  17035.         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
  17036.           goto decode_error;
  17037.         if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
  17038.           goto data_error;
  17039.         if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
  17040.           goto data_error;
  17041.         if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
  17042.           goto data_error;
  17043.         if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
  17044.             fprintf (stderr, "Unable to open SRP client structure.\n");
  17045.             goto bad;
  17046.         }
  17047.         wp = t_clientgenexp (tc);       /* Send wp */
  17048.         bp = tmp; blen = 0;
  17049.         srp_put (wp->data, &bp, wp->len, &blen);
  17050.         len = FTP_BUFSIZ;
  17051.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17052.           goto encode_error;
  17053.         reply_parse = "ADAT=";
  17054.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17055.     }
  17056.     if (n == REPLY_CONTINUE) {          /* Get yp */
  17057.         bp = buf;
  17058.         if (!reply_parse)
  17059.           goto data_error;
  17060.         blen = FTP_BUFSIZ;
  17061.         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
  17062.           goto decode_error;
  17063.         if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
  17064.           goto data_error;
  17065.         if (!srp_pass) {
  17066.             static char ftppass[PASSBUFSIZ];
  17067.             int ok;
  17068.             setint();
  17069.             ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
  17070.                         DEFAULT_UQ_TIMEOUT);
  17071.             if (ok)
  17072.           srp_pass = brstrip(ftppass);
  17073.         }
  17074.         t_clientpasswd (tc, srp_pass);
  17075.         memset (srp_pass, 0, strlen (srp_pass));
  17076.         skey = t_clientgetkey (tc, &yp); /* Send response */
  17077.         bp = tmp; blen = 0;
  17078.         srp_put (t_clientresponse (tc), &bp, 20, &blen);
  17079.         len = FTP_BUFSIZ;
  17080.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17081.           goto encode_error;
  17082.         reply_parse = "ADAT=";
  17083.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17084.     }
  17085.     if (n == REPLY_CONTINUE) {          /* Get response */
  17086.         bp = buf;
  17087.         if (!reply_parse)
  17088.           goto data_error;
  17089.         blen = FTP_BUFSIZ;
  17090.         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
  17091.           goto encode_error;
  17092.         if (srp_get (&bp, &cp, &blen, &clen) != 20)
  17093.           goto data_error;
  17094.         if (t_clientverify (tc, cp)) {
  17095.             fprintf (stderr, "WARNING: bad response to client challenge.\n");
  17096.             goto bad;
  17097.         }
  17098.         bp = tmp; blen = 0;             /* Send nothing */
  17099.         srp_put ("\0", &bp, 1, &blen);
  17100.         len = FTP_BUFSIZ;
  17101.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17102.           goto encode_error;
  17103.         reply_parse = "ADAT=";
  17104.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17105.     }
  17106.     if (n == REPLY_CONTINUE) {          /* Get cipher & hash lists, seqnum */
  17107.         CHAR seqnum[4];
  17108.         CHAR *clist;
  17109.         CHAR *hlist;
  17110.         CHAR *p1;
  17111.         int clist_len, hlist_len;
  17112.         bp = buf;
  17113.         if (!reply_parse)
  17114.           goto data_error;
  17115.         blen = FTP_BUFSIZ;
  17116.         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
  17117.           goto encode_error;
  17118.         if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
  17119.           goto data_error;
  17120.         if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
  17121.           goto data_error;
  17122.         if (srp_get (&bp, &cp, &blen, &clen) != 4)
  17123.           goto data_error;
  17124.         memcpy (seqnum, cp, 4);
  17125.         if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
  17126.           cid = srp_pref_cipher;
  17127.         if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
  17128.           cid = SRP_DEFAULT_CIPHER;
  17129.         if (!cid) {
  17130.             CHAR *loclist = cipher_getlist ();
  17131.             for (i = 0; i < strlen (loclist); i++)
  17132.               if (cipher_supported (clist, loclist[i])) {
  17133.                   cid = loclist[i];
  17134.                   break;
  17135.               }
  17136.         }
  17137.         if (!cid) {
  17138.             fprintf (stderr, "Unable to agree on cipher.\n");
  17139.             goto bad;
  17140.         }
  17141.         /* Choose hash */
  17142.  
  17143.         if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
  17144.           hid = srp_pref_hash;
  17145.  
  17146.         if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
  17147.           hid = SRP_DEFAULT_HASH;
  17148.  
  17149.         if (!hid) {
  17150.             CHAR *loclist = hash_getlist ();
  17151.             for (i = 0; i < strlen (loclist); i++)
  17152.               if (hash_supported (hlist, loclist[i])) {
  17153.                   hid = loclist[i];
  17154.                   break;
  17155.               }
  17156.         }
  17157.         if (!hid) {
  17158.             fprintf (stderr, "Unable to agree on hash.\n");
  17159.             goto bad;
  17160.         }
  17161.         /* Set incrypt */
  17162.  
  17163.         if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
  17164.                                     KRYPTO_DECODE)))
  17165.           goto bad;
  17166.  
  17167.         /* Generate random number for outkey and outseqnum */
  17168.  
  17169.         t_random (seqnum, 4);
  17170.  
  17171.         /* Send cid, hid, outkey, outseqnum */
  17172.  
  17173.         bp = tmp; blen = 0;
  17174.         srp_put (&cid, &bp, 1, &blen);
  17175.         srp_put (&hid, &bp, 1, &blen);
  17176.         srp_put (seqnum, &bp, 4, &blen);
  17177.         len = FTP_BUFSIZ;
  17178.         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
  17179.           goto encode_error;
  17180.         reply_parse = "ADAT=";
  17181.         n = ftpcmd("ADAT",buf,-1,-1,0);
  17182.  
  17183.         /* Set outcrypt */
  17184.  
  17185.         if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
  17186.                                      KRYPTO_ENCODE)))
  17187.           goto bad;
  17188.  
  17189.         t_clientclose (tc);
  17190.         tc = NULL;
  17191.     }
  17192.     if (n != REPLY_COMPLETE)
  17193.       goto bad;
  17194.  
  17195.     if (ftp_vbm) {
  17196.         if (ftp_deb)
  17197.           printf("\n");
  17198.         printf ("SRP authentication succeeded.\n");
  17199.         printf ("Using cipher %s and hash function %s.\n",
  17200.                 (cipher_getdescbyid(cid))->name,
  17201.                 (hash_getdescbyid(hid))->name
  17202.                 );
  17203.     }
  17204.     reply_parse = NULL;
  17205.     auth_type = "SRP";
  17206.     return(1);
  17207.  
  17208.   encode_error:
  17209.     fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
  17210.     goto bad;
  17211.  
  17212.   decode_error:
  17213.     fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
  17214.     goto bad;
  17215.  
  17216.   data_error:
  17217.     fprintf (stderr, "Unable to unmarshal authentication data.\n");
  17218.     goto bad;
  17219.  
  17220.   bad:
  17221.     fprintf (stderr, "SRP authentication failed, trying regular login.\n");
  17222.     reply_parse = NULL;
  17223.     return(0);
  17224. }
  17225.  
  17226. /*--------------------------------------------------------------+
  17227.  | srp_put: put item to send buffer                             |
  17228.  +--------------------------------------------------------------*/
  17229. static int
  17230. srp_put (in, out, inlen, outlen)
  17231.     CHAR *in;
  17232.     CHAR **out;
  17233.     int inlen;
  17234.     int *outlen;
  17235. {
  17236.     srp_uint32 net_len;
  17237.  
  17238.     net_len = htonl (inlen);
  17239.     memcpy (*out, &net_len, 4);
  17240.  
  17241.     *out += 4; *outlen += 4;
  17242.  
  17243.     memcpy (*out, in, inlen);
  17244.  
  17245.     *out += inlen; *outlen += inlen;
  17246.     return(0);
  17247. }
  17248.  
  17249. /*--------------------------------------------------------------+
  17250.  | srp_get: get item from receive buffer                        |
  17251.  +--------------------------------------------------------------*/
  17252. static int
  17253. srp_get (in, out, inlen, outlen)
  17254.     CHAR **in;
  17255.     CHAR **out;
  17256.     int *inlen;
  17257.     int *outlen;
  17258. {
  17259.     srp_uint32 net_len;
  17260.  
  17261.     if (*inlen < 4) return -1;
  17262.  
  17263.     memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
  17264.     *outlen = ntohl (net_len);
  17265.  
  17266.     if (*inlen < *outlen) return -1;
  17267.  
  17268.     *out = *in; *inlen -= *outlen; *in += *outlen;
  17269.  
  17270.     return *outlen;
  17271. }
  17272.  
  17273. /*--------------------------------------------------------------+
  17274.  | srp_encode: encode control message                           |
  17275.  +--------------------------------------------------------------*/
  17276. static int
  17277. srp_encode (private, in, out, len)
  17278.     int private;
  17279.     CHAR *in;
  17280.     CHAR *out;
  17281.     unsigned len;
  17282. {
  17283.     if (private)
  17284.       return krypto_msg_priv (outcrypt, in, out, len);
  17285.     else
  17286.       return krypto_msg_safe (outcrypt, in, out, len);
  17287. }
  17288.  
  17289. /*--------------------------------------------------------------+
  17290.  | srp_decode: decode control message                           |
  17291.  +--------------------------------------------------------------*/
  17292. static int
  17293. srp_decode (private, in, out, len)
  17294.     int private;
  17295.     CHAR *in;
  17296.     CHAR *out;
  17297.     unsigned len;
  17298. {
  17299.     if (private)
  17300.       return krypto_msg_priv (incrypt, in, out, len);
  17301.     else
  17302.       return krypto_msg_safe (incrypt, in, out, len);
  17303. }
  17304.  
  17305. #endif /* FTP_SRP */
  17306.  
  17307.  
  17308.  
  17309. #ifdef NOT_USED
  17310. /*
  17311.   The following code is from the Unix FTP client.  Be sure to
  17312.   make sure that the functionality is not lost.  Especially
  17313.   the Proxy stuff even though we have not yet implemented it.
  17314. */
  17315.  
  17316. /* Send multiple files  */
  17317.  
  17318. static int
  17319. ftp_mput(argc, argv) int argc; char **argv; {
  17320.     register int i;
  17321.     sig_t oldintr;
  17322.     int ointer;
  17323.     char *tp;
  17324.     sigtype mcancel();
  17325.  
  17326.     if (argc < 2 && !another(&argc, &argv, "local-files")) {
  17327.         printf("usage: %s local-files\n", argv[0]);
  17328.         ftpcode = -1;
  17329.         return;
  17330.     }
  17331.     mname = argv[0];
  17332.     mflag = 1;
  17333.     oldintr = signal(SIGINT, mcancel);
  17334.  
  17335.     /* Replace with calls to cc_execute() */
  17336.     setjmp(jcancel);
  17337. #ifdef FTP_PROXY
  17338.     if (proxy) {
  17339.         char *cp, *tp2, tmpbuf[CKMAXPATH];
  17340.  
  17341.         while ((cp = remglob(argv,0)) != NULL) {
  17342.             if (*cp == 0) {
  17343.                 mflag = 0;
  17344.                 continue;
  17345.             }
  17346.             if (mflag && confirm(argv[0], cp)) {
  17347.                 tp = cp;
  17348.                 if (mcase) {
  17349.                     while (*tp && !islower(*tp)) {
  17350.                         tp++;
  17351.                     }
  17352.                     if (!*tp) {
  17353.                         tp = cp;
  17354.                         tp2 = tmpbuf;
  17355.                         while ((*tp2 = *tp) != 0) {
  17356.                             if (isupper(*tp2)) {
  17357.                                 *tp2 = 'a' + *tp2 - 'A';
  17358.                             }
  17359.                             tp++;
  17360.                             tp2++;
  17361.                         }
  17362.                     }
  17363.                     tp = tmpbuf;
  17364.                 }
  17365.                 if (ntflag) {
  17366.                     tp = dotrans(tp);
  17367.                 }
  17368.                 if (mapflag) {
  17369.                     tp = domap(tp);
  17370.                 }
  17371.                 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
  17372.                 if (!mflag && fromatty) {
  17373.                     ointer = interactive;
  17374.                     interactive = 1;
  17375.                     if (confirm("Continue with","mput")) {
  17376.                         mflag++;
  17377.                     }
  17378.                     interactive = ointer;
  17379.                 }
  17380.             }
  17381.         }
  17382.         signal(SIGINT, oldintr);
  17383.         mflag = 0;
  17384.         return;
  17385.     }
  17386. #endif /* FTP_PROXY */
  17387.     for (i = 1; i < argc; i++) {
  17388.         register char **cpp, **gargs;
  17389.  
  17390.         if (mflag && confirm(argv[0], argv[i])) {
  17391.             tp = argv[i];
  17392.             sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
  17393.             if (!mflag && fromatty) {
  17394.                 ointer = interactive;
  17395.                 interactive = 1;
  17396.                 if (confirm("Continue with","mput")) {
  17397.                     mflag++;
  17398.                 }
  17399.                 interactive = ointer;
  17400.             }
  17401.         }
  17402.         continue;
  17403.  
  17404.         gargs = ftpglob(argv[i]);
  17405.         if (globerr != NULL) {
  17406.             printf("%s\n", globerr);
  17407.             if (gargs) {
  17408.                 blkfree(gargs);
  17409.                 free((char *)gargs);
  17410.             }
  17411.             continue;
  17412.         }
  17413.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  17414.             if (mflag && confirm(argv[0], *cpp)) {
  17415.                 tp = *cpp;
  17416.                 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
  17417.                 if (!mflag && fromatty) {
  17418.                     ointer = interactive;
  17419.                     interactive = 1;
  17420.                     if (confirm("Continue with","mput")) {
  17421.                         mflag++;
  17422.                     }
  17423.                     interactive = ointer;
  17424.                 }
  17425.             }
  17426.         }
  17427.         if (gargs != NULL) {
  17428.             blkfree(gargs);
  17429.             free((char *)gargs);
  17430.         }
  17431.     }
  17432.     signal(SIGINT, oldintr);
  17433.     mflag = 0;
  17434. }
  17435.  
  17436. /* Get multiple files */
  17437.  
  17438. static int
  17439. ftp_mget(argc, argv) int argc; char **argv; {
  17440.     int rc = -1;
  17441.     sig_t oldintr;
  17442.     int ointer;
  17443.     char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
  17444.     sigtype mcancel();
  17445.  
  17446.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  17447.         printf("usage: %s remote-files\n", argv[0]);
  17448.         ftpcode = -1;
  17449.         return(-1);
  17450.     }
  17451.     mname = argv[0];
  17452.     mflag = 1;
  17453.     oldintr = signal(SIGINT,mcancel);
  17454.     /* Replace with calls to cc_execute() */
  17455.     setjmp(jcancel);
  17456.     while ((cp = remglob(argv,proxy)) != NULL) {
  17457.         if (*cp == '\0') {
  17458.             mflag = 0;
  17459.             continue;
  17460.         }
  17461.         if (mflag && confirm(argv[0], cp)) {
  17462.             tp = cp;
  17463.             if (mcase) {
  17464.                 while (*tp && !islower(*tp)) {
  17465.                     tp++;
  17466.                 }
  17467.                 if (!*tp) {
  17468.                     tp = cp;
  17469.                     tp2 = tmpbuf;
  17470.                     while ((*tp2 = *tp) != 0) {
  17471.                         if (isupper(*tp2)) {
  17472.                             *tp2 = 'a' + *tp2 - 'A';
  17473.                         }
  17474.                         tp++;
  17475.                         tp2++;
  17476.                     }
  17477.                 }
  17478.                 tp = tmpbuf;
  17479.             }
  17480.             rc = (recvrequest("RETR", tp, cp, "wb",
  17481.                                tp != cp || !interactive) == 0,0,NULL,0,0,0);
  17482.             if (!mflag && fromatty) {
  17483.                 ointer = interactive;
  17484.                 interactive = 1;
  17485.                 if (confirm("Continue with","mget")) {
  17486.                     mflag++;
  17487.                 }
  17488.                 interactive = ointer;
  17489.             }
  17490.         }
  17491.     }
  17492.     signal(SIGINT,oldintr);
  17493.     mflag = 0;
  17494.     return(rc);
  17495. }
  17496.  
  17497. /* Delete multiple files */
  17498.  
  17499. static int
  17500. mdelete(argc, argv) int argc; char **argv; {
  17501.     sig_t oldintr;
  17502.     int ointer;
  17503.     char *cp;
  17504.     sigtype mcancel();
  17505.  
  17506.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  17507.         printf("usage: %s remote-files\n", argv[0]);
  17508.         ftpcode = -1;
  17509.         return(-1);
  17510.     }
  17511.     mname = argv[0];
  17512.     mflag = 1;
  17513.     oldintr = signal(SIGINT, mcancel);
  17514.     /* Replace with calls to cc_execute() */
  17515.     setjmp(jcancel);
  17516.     while ((cp = remglob(argv,0)) != NULL) {
  17517.         if (*cp == '\0') {
  17518.             mflag = 0;
  17519.             continue;
  17520.         }
  17521.         if (mflag && confirm(argv[0], cp)) {
  17522.             rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
  17523.             if (!mflag && fromatty) {
  17524.                 ointer = interactive;
  17525.                 interactive = 1;
  17526.                 if (confirm("Continue with", "mdelete")) {
  17527.                     mflag++;
  17528.                 }
  17529.                 interactive = ointer;
  17530.             }
  17531.         }
  17532.     }
  17533.     signal(SIGINT, oldintr);
  17534.     mflag = 0;
  17535.     return(rc);
  17536. }
  17537.  
  17538. /* Get a directory listing of multiple remote files */
  17539.  
  17540. static int
  17541. mls(argc, argv) int argc; char **argv; {
  17542.     sig_t oldintr;
  17543.     int ointer, i;
  17544.     char *cmd, mode[1], *dest;
  17545.     sigtype mcancel();
  17546.     int rc = -1;
  17547.  
  17548.     if (argc < 2 && !another(&argc, &argv, "remote-files"))
  17549.       goto usage;
  17550.     if (argc < 3 && !another(&argc, &argv, "local-file")) {
  17551.       usage:
  17552.         printf("usage: %s remote-files local-file\n", argv[0]);
  17553.         ftpcode = -1;
  17554.         return(-1);
  17555.     }
  17556.     dest = argv[argc - 1];
  17557.     argv[argc - 1] = NULL;
  17558.     if (strcmp(dest, "-") && *dest != '|')
  17559.       if (!globulize(&dest) ||
  17560.           !confirm("output to local-file:", dest)) {
  17561.           ftpcode = -1;
  17562.           return(-1);
  17563.       }
  17564.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  17565.     mname = argv[0];
  17566.     mflag = 1;
  17567.     oldintr = signal(SIGINT, mcancel);
  17568.     /* Replace with calls to cc_execute() */
  17569.     setjmp(jcancel);
  17570.     for (i = 1; mflag && i < argc-1; ++i) {
  17571.         *mode = (i == 1) ? 'w' : 'a';
  17572.         rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
  17573.         if (!mflag && fromatty) {
  17574.             ointer = interactive;
  17575.             interactive = 1;
  17576.             if (confirm("Continue with", argv[0])) {
  17577.                 mflag ++;
  17578.             }
  17579.             interactive = ointer;
  17580.         }
  17581.     }
  17582.     signal(SIGINT, oldintr);
  17583.     mflag = 0;
  17584.     return(rc);
  17585. }
  17586.  
  17587. static char *
  17588. remglob(argv,doswitch) char *argv[]; int doswitch; {
  17589.     char temp[16];
  17590.     static char buf[CKMAXPATH];
  17591.     static FILE *ftemp = NULL;
  17592.     static char **args;
  17593.     int oldhash;
  17594.     char *cp, *mode;
  17595.  
  17596.     if (!mflag) {
  17597.         if (!doglob) {
  17598.             args = NULL;
  17599.         } else {
  17600.             if (ftemp) {
  17601.                 (void) fclose(ftemp);
  17602.                 ftemp = NULL;
  17603.             }
  17604.         }
  17605.         return(NULL);
  17606.     }
  17607.     if (!doglob) {
  17608.         if (args == NULL)
  17609.           args = argv;
  17610.         if ((cp = *++args) == NULL)
  17611.           args = NULL;
  17612.         return(cp);
  17613.     }
  17614.     if (ftemp == NULL) {
  17615.         (void) strcpy(temp, _PATH_TMP);
  17616. #ifdef MKTEMP
  17617. #ifndef MKSTEMP
  17618.         (void) mktemp(temp);
  17619. #endif /* MKSTEMP */
  17620. #endif /* MKTEMP */
  17621.         verbose = 0;
  17622.         oldhash = hash, hash = 0;
  17623. #ifdef FTP_PROXY
  17624.         if (doswitch) {
  17625.             pswitch(!proxy);
  17626.         }
  17627. #endif /* FTP_PROXY */
  17628.         for (mode = "wb"; *++argv != NULL; mode = "ab")
  17629.           recvrequest ("NLST", temp, *argv, mode, 0);
  17630. #ifdef FTP_PROXY
  17631.         if (doswitch) {
  17632.             pswitch(!proxy);
  17633.         }
  17634. #endif /* FTP_PROXY */
  17635.         hash = oldhash;
  17636.         ftemp = fopen(temp, "r");
  17637.         unlink(temp);
  17638.         if (ftemp == NULL && (!dpyactive || ftp_deb)) {
  17639.             printf("Can't find list of remote files, oops\n");
  17640.             return(NULL);
  17641.         }
  17642.     }
  17643.     if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
  17644.         fclose(ftemp), ftemp = NULL;
  17645.         return(NULL);
  17646.     }
  17647.     if ((cp = ckstrchr(buf,'\n')) != NULL)
  17648.       *cp = '\0';
  17649.     return(buf);
  17650. }
  17651. #endif /* NOT_USED */
  17652. #endif /* TCPSOCKET (top of file) */
  17653. #endif /* SYSFTP (top of file) */
  17654. #endif /* NOFTP (top of file) */
  17655.