3 /* C K C F T P -- FTP Client for C-Kermit */
5 char *ckftpv = "FTP Client, 9.0.263, 5 Feb 2015";
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.
14 Copyright (C) 2000, 2014,
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.
19 Portions of conditionally included code Copyright Regents of the
20 University of California and The Stanford SRP Authentication Project;
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.
32 . Make syslog entries for session? Files?
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
38 . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
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).
48 Quick FTP command reference:
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>
59 CWD - Change Working Directory
60 REIN - Logout but not disconnect
73 SITE - Site parameters or commands
79 CDUP - Change to Parent Directory
80 SMNT - Structure Mount
82 RMD - Remove Directory
88 FEAT - List Features (done)
89 OPTS - Send options (done)
92 LANG - Specify language for messages (not done)
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)
101 Alphabetical syntax list:
103 ACCT <SP> <account-information> <CRLF>
104 ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
105 APPE <SP> <pathname> <CRLF>
107 CWD <SP> <pathname> <CRLF>
108 DELE <SP> <pathname> <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>
119 OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
120 PASS <SP> <password> <CRLF>
122 PORT <SP> <host-port> <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>
137 STRU <SP> <structure-code> <CRLF>
139 TYPE <SP> <type-code> <CRLF>
140 USER <SP> <username> <CRLF>
142 #include "ckcsym.h" /* Standard includes */
145 #ifndef NOFTP /* NOFTP = no FTP */
146 #ifndef SYSFTP /* SYSFTP = use external ftp client */
147 #ifdef TCPSOCKET /* Build only if TCP/IP included */
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. */
157 #endif /* CK_ANSIC */
168 #include <setjmpex.h>
180 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
183 #include <sys/stat.h>
184 #endif /* def VMS [else] */
188 #include <errno.h> /* Error number symbols */
190 #ifndef ERRNO_INCLUDED
191 #include <errno.h> /* Error number symbols */
192 #endif /* ERRNO_INCLUDED */
193 #endif /* HPUXPRE65 */
199 #define EPIPE 32 /* Broken pipe error */
202 /* Kermit includes */
208 #include "ckcnet.h" /* Includes ckctel.h */
209 #include "ckctel.h" /* (then why include it again?) */
213 #include "ckuath.h" /* SMS 2007/02/15 */
214 #endif /* def CK_SSL */
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.
235 #endif /* SV68R3V6 */
236 #endif /* DCLTIMEVAL */
239 /* Also maybe in some places the elements must be unsigned... */
245 /* Currently we don't use this... */
251 #else /* !DCLTIMEVAL */
254 #include <sys/time.h>
255 #endif /* SYSTIMEH */
256 #endif /* NOSYSTIMEH */
259 #include <sys/timeb.h>
260 #endif /* SYSTIMEBH */
261 #endif /* NOSYSTIMEBH */
262 #endif /* DCLTIMEVAL */
264 /* 2010-03-09 SMS. VAX C needs help to find "sys". It's easier not to try. */
268 #include <sys/types.h>
269 #endif /* def VMS [else] */
274 #endif /* HAVE_STDLIB_H */
278 /* This section moved to ckcdeb.h */
292 #ifdef VMS /* SMS 2007/02/15 */
293 #include "ckvrtl.h" /* for utime() */
296 #include <sys/utime.h>
302 #endif /* SYSUTIMEH */
304 #endif /* NOSETTIME */
308 #include <sys/select.h>
309 #endif /* SELECT_H */
310 #endif /* SCO_OSR504 */
312 #ifndef INADDR_NONE /* 2010-03-29 */
313 #define INADDR_NONE -1
314 #endif /* INADDR_NONE */
316 /* select() dialects... */
319 #define BSDSELECT /* BSD select() syntax/semantics */
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 */
327 #define howmany(x, y) (((x)+((y)-1))/(y))
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)))
337 #ifdef OS2 /* OS/2 or Win32 */
347 #define BSDSELECT /* SMS 2007/02/15 */
350 /* Other select() peculiarities */
353 #ifndef HPUX10 /* HP-UX 9.xx and earlier */
355 /* The three interior args to select() are (int *) rather than (fd_set *) */
358 #endif /* INTSELECT */
359 #endif /* HPUX1100 */
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
373 #define connect Rconnect
374 #define getsockname Rgetsockname
375 #define listen Rlisten
376 #endif /* CK_SOCKS5 */
377 #endif /* CK_SOCKS */
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];
388 int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
390 /* Feature selection */
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.
398 /* #define USE_SHUTDOWN */
399 #endif /* USE_SHUTDOWN */
402 #ifndef NORESTART /* Restart / recover */
405 #endif /* FTP_RESTART */
406 #endif /* NORESTART */
407 #endif /* NORESEND */
409 #ifndef NOUPDATE /* Update mode */
412 #endif /* DOUPDATE */
413 #endif /* NOUPDATE */
415 #ifndef UNICODE /* Unicode required */
416 #ifndef NOCSETS /* for charset translation */
422 #ifndef HAVE_MSECS /* Millisecond timer */
428 #endif /* HAVE_MSECS */
431 #ifdef PIPESEND /* PUT from pipe */
435 #endif /* PIPESEND */
437 #ifndef NOSPL /* PUT from array */
440 #endif /* PUTARRAY */
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.
469 #ifndef NOFTP_GSSAPI /* 299 */
471 #endif /* NOFTP_GSSAPI */
474 #endif /* CK_KERBEROS */
476 /* FTP_SECURITY is defined if any of the above is selected */
491 #endif /* FTP_KRB4 */
492 #endif /* FTP_GSSAPI */
493 #endif /* FTP_SECURITY */
507 #endif /* CRYPT_DLL */
510 #define des_cblock Block
511 #define des_key_schedule Schedule
516 #include "kerberosIV/krb.h"
520 /* For some reason lost in history the Makefile Solaris targets have -Usun */
525 #define krb_get_err_text_entry krb_get_err_text
527 #endif /* FTP_KRB4 */
533 #endif /* HEADER_DES_H */
534 #endif /* FTP_KRB4 */
541 #endif /* HAVE_PWD_H */
543 #include "t_client.h"
548 #include <gssapi/gssapi.h>
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.
554 #include <gssapi/gssapi_generic.h>
555 #include <gssapi/gssapi_krb5.h>
556 static gss_ctx_id_t gcontext;
559 /** exported constants defined in gssapi_krb5{,_nx}.h **/
561 /* these are bogus, but will compile */
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
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.
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"},
604 CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
608 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
609 #endif /* MACOSX103 */
613 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
615 CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
617 CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
619 CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
623 * See krb5/gssapi_krb5.c for a description of the algorithm for
624 * encoding an object identifier.
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
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
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
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
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)
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"},
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;
664 #endif /* FTP_GSSAPI */
677 #endif /* CK_ENCRYPTION */
678 #endif /* FTP_KRB4 */
682 #endif /* FTP_GSSAPI */
685 extern int k95stdout, wherex[], wherey[];
686 extern unsigned char colorcmd;
690 static char ftp_realm[REALM_SZ + 1];
691 static KTEXT_ST ftp_tkt;
693 static LEASH_CREDENTIALS ftp_cred;
695 static CREDENTIALS ftp_cred;
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 */
702 /* getreply() function codes */
704 #define GRF_AUTH 1 /* Reply to AUTH command */
705 #define GRF_FEAT 2 /* Reply to FEAT command */
707 /* Operational definitions */
709 #define DEF_VBM 0 /* Default verbose mode */
710 /* #define SETVBM */ /* (see getreply) */
712 #define URL_ONEFILE /* GET, not MGET, for FTP URL */
714 #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
715 #define SRVNAMLEN 32 /* Max length for server type name */
717 #define PASSBUFSIZ 256
718 #define PROMPTSIZ 256
720 #ifndef MGETMAX /* Max operands for MGET command */
725 #define FUDGE_FACTOR 100
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.
736 #define FUDGE_FACTOR 96
737 #endif /* FUDGE_FACTOR */
738 #endif /* FTP_GSSAPI */
742 #define FUDGE_FACTOR 32
743 #endif /* FUDGE_FACTOR */
744 #endif /* FTP_KRB4 */
746 #ifndef FUDGE_FACTOR /* In case no auth types define it */
747 #define FUDGE_FACTOR 0
748 #endif /* FUDGE_FACTOR */
750 #ifndef MAXHOSTNAMELEN
751 #define MAXHOSTNAMELEN 64
752 #endif /* MAXHOSTNAMELEN */
753 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
755 /* Fascist compiler toadying */
758 #ifdef COMMENT /* Might be needed here and there */
759 #define SENDARG2TYPE const char *
761 #define SENDARG2TYPE char *
763 #endif /* SENDARG2TYPE */
765 /* Common text messages */
767 static char *nocx = "?No FTP control connection\n";
769 static char *fncnam[] = {
770 "rename", "overwrite", "backup", "append", "discard", "ask", "update",
774 /* Macro definitions */
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)))
780 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
785 extern struct urldata g_url;
789 extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
791 extern char zinbuffer[], zoutbuffer[];
793 extern char *zinptr, *zoutptr;
794 extern int zincnt, zoutcnt, zobufsize, fncact;
797 extern int f_tmpdir; /* Directory changed temporarily */
798 extern char savdir[]; /* For saving current directory */
800 #endif /* CK_TMPDIR */
802 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
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;
815 int ftp_timed_out = 0;
816 long ftp_timeout = 0;
817 #endif /* FTP_TIMEOUT */
820 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
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;
831 extern int locus, autolocus;
835 extern int nfilc, dcset7, dcset8, fileorder;
836 extern struct csinfo fcsinfo[];
837 extern struct keytab fcstab[];
841 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
842 extern char sndnbefore[], sndnafter[], *rcvexcept[];
845 extern char * remdest;
846 extern int remfile, remappd, rempipe;
849 extern int cmd_quoting;
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 */
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;
865 extern char fspec[]; /* Most recent filespec */
866 extern int fspeclen; /* Length of fspec[] buffer */
871 extern char * sndfilter, * rcvfilter;
872 #endif /* PIPESEND */
875 extern int ckrooterr;
879 extern int krb4_autoget;
880 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
884 extern int krb5_autoget;
885 extern int krb5_d_no_addresses;
886 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
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 */
895 extern char atmbuf[]; /* The same, but static */
896 extern char cmdbuf[];
898 extern char tmpbuf[];
901 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
903 /* Public variables declared here */
906 int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
908 int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
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 */
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 */
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 */
929 /* Definitions and typedefs needed for prototypes */
931 #define sig_t my_sig_t
932 #define sigtype SIGTYP
933 typedef sigtype (*sig_t)();
935 /* Static global variables */
937 static char ftpsndbuf[FTP_BUFSIZ+64];
939 static char * fts_sto = NULL;
941 static int ftpsndret = 0;
942 static struct _ftpsnd {
943 sig_t oldintr, oldintp;
947 char * cmd, * local, * remote;
955 This is just a first stab -- these strings should match how the
956 corresponding FTP servers identify themselves.
959 static char * myostype = "UNIX";
963 static char * myostype = "VMS";
967 static char * myostype = "WIN32";
969 static char * myostype = "OS/2";
972 static char * myostype = "UNSUPPORTED";
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;
1008 static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
1009 static int c0, c1; /* Temp variables for characters */
1011 static char putpath[CKMAXPATH+1] = { NUL, NUL };
1012 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
1014 #define RFNBUFSIZ 4096 /* Remote filename buffer size */
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 */
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;
1027 /* Protection level symbols */
1029 #define FPL_CLR 1 /* Clear */
1030 #define FPL_SAF 2 /* Safe */
1031 #define FPL_PRV 3 /* Private */
1032 #define FPL_CON 4 /* Confidential */
1034 /* Symbols for file types returned by MLST/MLSD */
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 */
1041 /* File type symbols keyed to the file-type symbols from ckcker.h */
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) */
1047 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
1049 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1051 #define SFT_AUTH 1 /* FTP server feature codes */
1062 #define CNV_AUTO 2 /* FTP filename conversion */
1066 /* SET FTP values */
1068 static int /* SET FTP values... */
1069 ftp_aut = 1, /* Auto-authentication */
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 */
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 */
1094 static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
1095 static int ftp_bug_use_ssl_v3 = 0; /* use SSLv3 for AUTH SSL */
1100 ftp_csr = -1, /* Remote (server) character set */
1103 #endif /* NOCSETS */
1104 ftp_xla = 0; /* Character-set translation on/off */
1106 ftp_csx = -1, /* Remote charset currently in use */
1107 ftp_csl = -1; /* Local charset currently in use */
1109 static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
1111 char * ftp_nml = NULL; /* /NAMELIST */
1112 char * ftp_tmp = NULL; /* Temporary string */
1113 static char * ftp_acc = NULL; /* Account string */
1114 static char * auth_type = NULL; /* Authentication type */
1115 static char * srv_renam = NULL; /* Server-rename string */
1116 FILE * fp_nml = NULL; /* Namelist file pointer */
1118 static int csocket = -1; /* Control socket */
1119 static int connected = 0; /* Connected to FTP server */
1120 /* static unsigned short ftp_port = 0; */ /* FTP port */
1121 /* static int ftp_port = 0; */ /* SMS 2007/02/15 */
1122 static int ftp_port = 0; /* fdc 2007/08/30 */
1124 static int hostcmd = 0; /* Has HOST command been sent */
1125 #endif /* FTPHOST */
1126 static int form, mode, stru, bytesize, curtype = FTT_ASC;
1127 static char bytename[8];
1129 /* For parsing replies to FTP server command */
1130 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
1133 static int proxy, unix_proxy
1134 #endif /* FTP_PROXY */
1136 static char pasv[64]; /* Passive-mode port */
1137 static int passivemode = 0;
1138 static int sendport = 0;
1139 static int servertype = 0; /* FTP server's OS type */
1141 static int testing = 0;
1142 static char ftpcmdbuf[FTP_BUFSIZ];
1144 /* Macro definitions */
1146 #define UC(b) ckitoa(((int)b)&0xff)
1147 #define nz(x) ((x) == 0 ? 1 : (x))
1149 /* Command tables and definitions */
1151 #define FTP_ACC 1 /* FTP command keyword codes */
1191 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
1197 static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
1198 { "proceed", 0, 0 }, /* 0 = proceed */
1199 { "quit", 1, 0 } /* 1 = quit */
1202 static struct keytab ftpcmdtab[] = { /* FTP command table */
1203 { "account", FTP_ACC, 0 },
1204 { "append", FTP_APP, 0 },
1205 { "bye", FTP_CLS, 0 },
1206 { "cd", FTP_CWD, 0 },
1207 { "cdup", FTP_GUP, 0 },
1208 { "check", FTP_CHK, 0 },
1209 { "chmod", FTP_CHM, 0 },
1210 { "close", FTP_CLS, 0 },
1211 { "cwd", FTP_CWD, CM_INV },
1212 { "delete", FTP_MDE, 0 },
1213 { "directory", FTP_DIR, 0 },
1214 { "disable", FTP_DIS, 0 },
1215 { "enable", FTP_ENA, 0 },
1216 { "features", FTP_FEA, 0 },
1217 { "get", FTP_GET, 0 },
1218 { "help", FTP_HLP, 0 },
1219 { "idle", FTP_IDL, 0 },
1220 { "login", FTP_USR, CM_INV },
1221 { "mdelete", FTP_MDE, CM_INV },
1222 { "mget", FTP_MGE, 0 },
1223 { "mkdir", FTP_MKD, 0 },
1224 { "modtime", FTP_MOD, 0 },
1225 { "mput", FTP_MPU, 0 },
1226 { "open", FTP_OPN, 0 },
1227 { "opt", FTP_OPT, CM_INV|CM_ABR },
1228 { "opts", FTP_OPT, CM_INV },
1229 { "options", FTP_OPT, 0 },
1230 { "put", FTP_PUT, 0 },
1231 { "pwd", FTP_PWD, 0 },
1232 { "quit", FTP_CLS, CM_INV },
1233 { "quote", FTP_QUO, 0 },
1234 { "reget", FTP_RGE, 0 },
1235 { "rename", FTP_REN, 0 },
1236 { "reput", FTP_REP, 0 },
1237 { "resend", FTP_REP, CM_INV },
1238 { "reset", FTP_RES, 0 },
1239 { "rmdir", FTP_RMD, 0 },
1240 { "send", FTP_PUT, CM_INV },
1241 { "site", FTP_SIT, 0 },
1242 { "size", FTP_SIZ, 0 },
1243 { "status", FTP_STA, 0 },
1244 { "system", FTP_SYS, 0 },
1245 { "type", FTP_TYP, 0 },
1246 { "umask", FTP_UMA, 0 },
1247 { "up", FTP_GUP, CM_INV },
1248 { "user", FTP_USR, 0 },
1249 { "vdirectory",FTP_VDI, 0 },
1252 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1254 #define OPN_ANO 1 /* FTP OPEN switch codes */
1267 static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
1268 { "/ssl", OPN_TLS, 0 },
1269 { "/tls", OPN_TLS, 0 },
1272 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1274 #endif /* FTP_SECURITY */
1276 static struct keytab ftpswitab[] = { /* FTP command switches */
1277 { "/account", OPN_ACC, CM_ARG },
1278 { "/active", OPN_ACT, 0 },
1279 { "/anonymous", OPN_ANO, 0 },
1280 { "/noinit", OPN_NIN, 0 },
1281 { "/nologin", OPN_NOL, 0 },
1282 { "/passive", OPN_PSV, 0 },
1283 { "/password", OPN_PSW, CM_ARG },
1284 { "/user", OPN_USR, CM_ARG },
1287 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1289 /* FTP { ENABLE, DISABLE } items */
1297 static struct keytab ftpenatab[] = {
1298 { "AUTH", ENA_AUTH, 0 },
1299 { "FEAT", ENA_FEAT, 0 },
1300 { "MDTM", ENA_MDTM, 0 },
1301 { "ML", ENA_MLST, CM_INV|CM_ABR },
1302 { "MLS", ENA_MLST, CM_INV|CM_ABR },
1303 { "MLSD", ENA_MLST, CM_INV },
1304 { "MLST", ENA_MLST, 0 },
1305 { "SIZE", ENA_SIZE, 0 },
1308 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1310 /* SET FTP command keyword indices */
1312 #define FTS_AUT 1 /* Autoauthentication */
1313 #define FTS_CRY 2 /* Encryption */
1314 #define FTS_LOG 3 /* Autologin */
1315 #define FTS_CPL 4 /* Command protection level */
1316 #define FTS_CFW 5 /* Credentials forwarding */
1317 #define FTS_DPL 6 /* Data protection level */
1318 #define FTS_DBG 7 /* Debugging */
1319 #define FTS_PSV 8 /* Passive mode */
1320 #define FTS_SPC 9 /* Send port commands */
1321 #define FTS_TYP 10 /* (file) Type */
1322 #define FTS_USN 11 /* Unique server names (for files) */
1323 #define FTS_VBM 12 /* Verbose mode */
1324 #define FTS_ATP 13 /* Authentication type */
1325 #define FTS_CNV 14 /* Filename conversion */
1326 #define FTS_TST 15 /* Test (progress) messages */
1327 #define FTS_PRM 16 /* (file) Permissions */
1328 #define FTS_XLA 17 /* Charset translation */
1329 #define FTS_CSR 18 /* Server charset */
1330 #define FTS_ERR 19 /* Error action */
1331 #define FTS_FNC 20 /* Collision */
1332 #define FTS_SRP 21 /* SRP options */
1333 #define FTS_GFT 22 /* GET automatic file-type switching */
1334 #define FTS_DAT 23 /* Set file dates */
1335 #define FTS_STO 24 /* Server time offset */
1336 #define FTS_APW 25 /* Anonymous password */
1337 #define FTS_DIS 26 /* File-transfer display style */
1338 #define FTS_BUG 27 /* Bug(s) */
1339 #define FTS_TMO 28 /* Timeout */
1343 #define FTB_SV2 1 /* use SSLv2 */
1344 #define FTB_SV3 2 /* use SSLv3 */
1346 static struct keytab ftpbugtab[] = {
1347 { "use-ssl-v2", FTB_SV2, 0 },
1348 { "use-ssl-v3", FTB_SV3, 0 }
1351 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1353 /* FTP PUT options (mutually exclusive, not a bitmask) */
1355 #define PUT_UPD 1 /* Update */
1356 #define PUT_RES 2 /* Restart */
1357 #define PUT_SIM 4 /* Simulation */
1358 #define PUT_DIF 8 /* Dates Differ */
1360 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1362 { "append", XYFX_A, 0 }, /* append to old file */
1365 { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
1367 { "backup", XYFX_B, 0 }, /* rename old file */
1369 { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
1370 { "discard", XYFX_D, 0 }, /* don't accept new file */
1371 { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1373 { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
1374 { "rename", XYFX_R, 0 }, /* rename the incoming file */
1375 #ifndef MAC /* This crashes Mac Kermit. */
1376 { "update", XYFX_U, 0 }, /* replace if newer */
1380 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1384 /* FTP authentication options */
1386 #define FTA_AUTO 0 /* Auto */
1387 #define FTA_SRP 1 /* SRP */
1388 #define FTA_GK5 2 /* Kerberos 5 */
1389 #define FTA_K4 3 /* Kerberos 4 */
1390 #define FTA_SSL 4 /* SSL */
1391 #define FTA_TLS 5 /* TLS */
1393 /* FTP authentication types */
1396 static int ftp_auth_type[FTPATYPS] = {
1398 FTA_GK5, /* GSSAPI Kerberos 5 */
1399 #endif /* FTP_GK5 */
1402 #endif /* FTP_SRP */
1404 FTA_K4, /* Kerberos 4 */
1405 #endif /* FTP_KRB4 */
1413 static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
1414 { "automatic", FTA_AUTO, CM_INV },
1416 { "gssapi-krb5", FTA_GK5, 0 },
1417 #endif /* FTP_GSSAPI */
1419 { "k4", FTA_K4, CM_INV },
1420 #endif /* FTP_KRB4 */
1422 { "k5", FTA_GK5, CM_INV },
1423 #endif /* FTP_GSSAPI */
1425 { "kerberos4", FTA_K4, 0 },
1426 #endif /* FTP_KRB4 */
1428 { "kerberos5", FTA_GK5, CM_INV },
1429 #endif /* FTP_GSSAPI */
1431 { "kerberos_iv",FTA_K4, CM_INV },
1432 #endif /* FTP_KRB4 */
1434 { "kerberos_v", FTA_GK5, CM_INV },
1435 #endif /* FTP_GSSAPI */
1437 { "krb4", FTA_K4, CM_INV },
1438 #endif /* FTP_KRB4 */
1440 { "krb5", FTA_GK5, CM_INV },
1441 #endif /* FTP_GSSAPI */
1443 { "srp", FTA_SRP, 0 },
1444 #endif /* FTP_SRP */
1446 { "ssl", FTA_SSL, 0 },
1447 { "tls", FTA_TLS, 0 },
1451 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1454 #define SRP_CIPHER 1
1456 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
1457 { "cipher", SRP_CIPHER, 0 },
1458 { "hash", SRP_HASH, 0 },
1461 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1462 #endif /* FTP_SRP */
1463 #endif /* FTP_SECURITY */
1465 static struct keytab ftpset[] = { /* SET FTP commmand table */
1466 { "anonymous-password", FTS_APW, 0 },
1468 { "authtype", FTS_ATP, 0 },
1469 { "autoauthentication", FTS_AUT, 0 },
1470 { "autoencryption", FTS_CRY, 0 },
1471 #endif /* FTP_SECURITY */
1472 { "autologin", FTS_LOG, 0 },
1473 { "bug", FTS_BUG, 0 },
1475 { "character-set-translation",FTS_XLA, 0 },
1476 #endif /* NOCSETS */
1477 { "collision", FTS_FNC, 0 },
1479 { "command-protection-level", FTS_CPL, 0 },
1480 { "cpl", FTS_CPL, CM_INV },
1481 { "credential-forwarding", FTS_CFW, 0 },
1482 { "da", FTS_DAT, CM_INV|CM_ABR },
1483 { "data-protection-level", FTS_DPL, 0 },
1484 #endif /* FTP_SECURITY */
1485 { "dates", FTS_DAT, 0 },
1486 { "debug", FTS_DBG, 0 },
1487 { "display", FTS_DIS, 0 },
1489 { "dpl", FTS_DPL, CM_INV },
1490 #endif /* FTP_SECURITY */
1491 { "error-action", FTS_ERR, 0 },
1492 { "filenames", FTS_CNV, 0 },
1493 { "get-filetype-switching", FTS_GFT, 0 },
1494 { "passive-mode", FTS_PSV, 0 },
1495 { "pasv", FTS_PSV, CM_INV },
1496 { "permissions", FTS_PRM, 0 },
1497 { "progress-messages", FTS_TST, 0 },
1498 { "send-port-commands", FTS_SPC, 0 },
1500 { "server-character-set", FTS_CSR, 0 },
1501 #endif /* NOCSETS */
1502 { "server-time-offset", FTS_STO, 0 },
1504 { "srp", FTS_SRP, 0 },
1506 { "srp", FTS_SRP, CM_INV },
1507 #endif /* FTP_SRP */
1509 { "timeout", FTS_TMO, 0 },
1510 #endif /* FTP_TIMEOUT */
1511 { "type", FTS_TYP, 0 },
1512 { "unique-server-names", FTS_USN, 0 },
1513 { "verbose-mode", FTS_VBM, 0 },
1516 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1519 GET and PUT switches are approximately the same as Kermit GET and SEND,
1520 and use the same SND_xxx definitions, but hijack a couple for FTP use.
1521 Don't just make up new ones, since the number of SND_xxx options must be
1522 known in advance for the switch-parsing arrays.
1524 #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
1525 #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
1526 #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
1528 static struct keytab putswi[] = { /* FTP PUT switch table */
1529 { "/after", SND_AFT, CM_ARG },
1531 { "/array", SND_ARR, CM_ARG },
1532 #endif /* PUTARRAY */
1533 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1534 { "/as-name", SND_ASN, CM_ARG },
1535 { "/ascii", SND_TXT, CM_INV },
1536 { "/b", SND_BIN, CM_INV|CM_ABR },
1537 { "/before", SND_BEF, CM_ARG },
1538 { "/binary", SND_BIN, 0 },
1540 { "/command", SND_CMD, CM_PSH },
1541 #endif /* PUTPIPE */
1543 /* This works but it's dangerous */
1545 { "/dates-differ", SND_DIF, CM_INV },
1546 #endif /* DOUPDATE */
1547 #endif /* COMMENT */
1548 { "/delete", SND_DEL, 0 },
1550 { "/dotfiles", SND_DOT, 0 },
1551 #endif /* UNIXOROSK */
1552 { "/error-action", SND_ERR, CM_ARG },
1553 { "/except", SND_EXC, CM_ARG },
1554 { "/filenames", SND_NAM, CM_ARG },
1557 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1559 #endif /* PIPESEND */
1561 { "/followlinks", SND_LNK, 0 },
1562 #endif /* CKSYMLINK */
1564 { "/image", SND_IMG, 0 },
1566 { "/image", SND_BIN, CM_INV },
1568 { "/larger-than", SND_LAR, CM_ARG },
1569 { "/listfile", SND_FIL, CM_ARG },
1571 { "/local-character-set", SND_CSL, CM_ARG },
1572 #endif /* NOCSETS */
1574 { "/move-to", SND_MOV, CM_ARG },
1575 #endif /* CK_TMPDIR */
1576 { "/nobackupfiles", SND_NOB, 0 },
1578 { "/nodotfiles", SND_NOD, 0 },
1579 #endif /* UNIXOROSK */
1581 { "/nofollowlinks", SND_NLK, 0 },
1582 #endif /* CKSYMLINK */
1584 { "/not-after", SND_NAF, CM_ARG },
1585 { "/not-before", SND_NBE, CM_ARG },
1587 { "/permissions", SND_PRM, CM_ARG },
1589 { "/permissions", SND_PRM, CM_ARG|CM_INV },
1591 { "/quiet", SND_SHH, 0 },
1593 { "/recover", SND_RES, 0 },
1594 #endif /* FTP_RESTART */
1596 { "/recursive", SND_REC, 0 },
1597 #endif /* RECURSIVE */
1598 { "/rename-to", SND_REN, CM_ARG },
1600 { "/restart", SND_RES, CM_INV },
1601 #endif /* FTP_RESTART */
1603 { "/server-character-set", SND_CSR, CM_ARG },
1604 #endif /* NOCSETS */
1605 { "/server-rename-to", SND_SRN, CM_ARG },
1606 { "/simulate", SND_SIM, 0 },
1607 { "/since", SND_AFT, CM_INV|CM_ARG },
1608 { "/smaller-than", SND_SMA, CM_ARG },
1610 { "/starting-at", SND_STA, CM_ARG },
1611 #endif /* COMMENT */
1613 { "/subdirectories", SND_REC, CM_INV },
1614 #endif /* RECURSIVE */
1615 { "/tenex", SND_TEN, 0 },
1616 { "/text", SND_TXT, 0 },
1618 { "/transparent", SND_XPA, 0 },
1619 #endif /* NOCSETS */
1620 { "/type", SND_TYP, CM_ARG },
1622 { "/update", SND_UPD, 0 },
1623 #endif /* DOUPDATE */
1624 { "/unique-server-names", SND_USN, 0 },
1627 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1629 static struct keytab getswi[] = { /* FTP [M]GET switch table */
1630 { "/after", SND_AFT, CM_INV },
1631 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1632 { "/as-name", SND_ASN, CM_ARG },
1633 { "/ascii", SND_TXT, CM_INV },
1634 { "/before", SND_BEF, CM_INV },
1635 { "/binary", SND_BIN, 0 },
1636 { "/collision", SND_COL, CM_ARG },
1638 { "/command", SND_CMD, CM_PSH },
1639 #endif /* PUTPIPE */
1640 { "/delete", SND_DEL, 0 },
1641 { "/error-action", SND_ERR, CM_ARG },
1642 { "/except", SND_EXC, CM_ARG },
1643 { "/filenames", SND_NAM, CM_ARG },
1646 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1648 #endif /* PIPESEND */
1650 { "/image", SND_IMG, 0 },
1652 { "/image", SND_BIN, CM_INV },
1654 { "/larger-than", SND_LAR, CM_ARG },
1655 { "/listfile", SND_FIL, CM_ARG },
1657 { "/local-character-set", SND_CSL, CM_ARG },
1658 #endif /* NOCSETS */
1659 { "/match", SND_PAT, CM_ARG },
1660 { "/ml", SND_MLS, CM_INV|CM_ABR },
1661 { "/mls", SND_MLS, CM_INV|CM_ABR },
1662 { "/mlsd", SND_MLS, 0 },
1663 { "/mlst", SND_MLS, CM_INV },
1665 { "/move-to", SND_MOV, CM_ARG },
1666 #endif /* CK_TMPDIR */
1667 { "/namelist", SND_NML, CM_ARG },
1668 { "/nlst", SND_NLS, 0 },
1669 { "/nobackupfiles", SND_NOB, 0 },
1670 { "/nodotfiles", SND_NOD, 0 },
1672 { "/dates-differ", SND_DIF, CM_INV },
1673 #endif /* DOUPDATE */
1674 { "/not-after", SND_NAF, CM_INV },
1675 { "/not-before", SND_NBE, CM_INV },
1676 { "/permissions", SND_PRM, CM_INV },
1677 { "/quiet", SND_SHH, 0 },
1679 { "/recover", SND_RES, 0 },
1680 #endif /* FTP_RESTART */
1682 { "/recursive", SND_REC, 0 },
1683 #endif /* RECURSIVE */
1684 { "/rename-to", SND_REN, CM_ARG },
1686 { "/restart", SND_RES, CM_INV },
1687 #endif /* FTP_RESTART */
1689 { "/server-character-set", SND_CSR, CM_ARG },
1690 #endif /* NOCSETS */
1691 { "/server-rename-to", SND_SRN, CM_ARG },
1692 { "/smaller-than", SND_SMA, CM_ARG },
1694 { "/subdirectories", SND_REC, CM_INV },
1695 #endif /* RECURSIVE */
1696 { "/text", SND_TXT, 0 },
1697 { "/tenex", SND_TEN, 0 },
1699 { "/transparent", SND_XPA, 0 },
1700 #endif /* NOCSETS */
1701 { "/to-screen", SND_MAI, 0 },
1703 { "/update", SND_UPD, CM_INV },
1704 #endif /* DOUPDATE */
1707 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1709 static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
1710 { "/error-action", SND_ERR, CM_ARG },
1711 { "/except", SND_EXC, CM_ARG },
1712 { "/filenames", SND_NAM, CM_ARG },
1713 { "/larger-than", SND_LAR, CM_ARG },
1714 { "/nobackupfiles", SND_NOB, 0 },
1716 { "/nodotfiles", SND_NOD, 0 },
1717 #endif /* UNIXOROSK */
1718 { "/quiet", SND_SHH, 0 },
1720 { "/recursive", SND_REC, 0 },
1721 #endif /* RECURSIVE */
1722 { "/smaller-than", SND_SMA, CM_ARG },
1724 { "/subdirectories", SND_REC, CM_INV },
1725 #endif /* RECURSIVE */
1728 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1730 static struct keytab fntab[] = { /* Filename conversion keyword table */
1731 { "automatic", 2, CNV_AUTO },
1732 { "converted", 1, CNV_CNV },
1733 { "literal", 0, CNV_LIT }
1735 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1737 static struct keytab ftptyp[] = { /* SET FTP TYPE table */
1738 { "ascii", FTT_ASC, 0 },
1739 { "binary", FTT_BIN, 0 },
1740 { "tenex", FTT_TEN, 0 },
1741 { "text", FTT_ASC, CM_INV },
1744 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1747 static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
1748 { "clear", FPL_CLR, 0 },
1749 { "confidential", FPL_CON, 0 },
1750 { "private", FPL_PRV, 0 },
1751 { "safe", FPL_SAF, 0 },
1754 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1755 #endif /* FTP_SECURITY */
1757 /* Definitions for FTP from RFC765. */
1761 #define REPLY_PRELIM 1 /* Positive preliminary */
1762 #define REPLY_COMPLETE 2 /* Positive completion */
1763 #define REPLY_CONTINUE 3 /* Positive intermediate */
1764 #define REPLY_TRANSIENT 4 /* Transient negative completion */
1765 #define REPLY_ERROR 5 /* Permanent negative completion */
1766 #define REPLY_SECURE 6 /* Security encoded message */
1768 /* Form codes and names */
1770 #define FORM_N 1 /* Non-print */
1771 #define FORM_T 2 /* Telnet format effectors */
1772 #define FORM_C 3 /* Carriage control (ASA) */
1774 /* Structure codes and names */
1776 #define STRU_F 1 /* File (no record structure) */
1777 #define STRU_R 2 /* Record structure */
1778 #define STRU_P 3 /* Page structure */
1780 /* Mode types and names */
1782 #define MODE_S 1 /* Stream */
1783 #define MODE_B 2 /* Block */
1784 #define MODE_C 3 /* Compressed */
1786 /* Protection levels and names */
1788 #define PROT_C 1 /* Clear */
1789 #define PROT_S 2 /* Safe */
1790 #define PROT_P 3 /* Private */
1791 #define PROT_E 4 /* Confidential */
1793 #ifdef COMMENT /* Not used */
1795 char *strunames[] = {"0", "File", "Record", "Page" };
1796 char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
1797 char *modenames[] = {"0", "Stream", "Block", "Compressed" };
1798 char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
1799 #endif /* FTP_NAMES */
1803 #define REC_ESC '\377' /* Record-mode Escape */
1804 #define REC_EOR '\001' /* Record-mode End-of-Record */
1805 #define REC_EOF '\002' /* Record-mode End-of-File */
1809 #define BLK_EOR 0x80 /* Block is End-of-Record */
1810 #define BLK_EOF 0x40 /* Block is End-of-File */
1811 #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
1812 #define BLK_RESTART 0x10 /* Block is Restart Marker */
1813 #define BLK_BYTECOUNT 2 /* Bytes in this block */
1814 #endif /* COMMENT */
1816 #define RADIX_ENCODE 0 /* radix_encode() function codes */
1817 #define RADIX_DECODE 1
1820 The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
1821 results in a serious performance degradation due to the increased number
1822 of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1823 network i/o. So instead we set the value to 1<<13 (8K), about half the size
1824 of the typical TCP window. Maybe we should add a command to allow the value
1827 #define DEFAULT_PBSZ 1<<13
1831 _PROTOTYP(int remtxt, (char **) );
1832 _PROTOTYP(char * gskreason, (int) );
1833 _PROTOTYP(static int ftpclose,(void));
1834 _PROTOTYP(static int zzsend, (int, CHAR));
1835 _PROTOTYP(static int getreply,(int,int,int,int,int));
1836 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1837 _PROTOTYP(static int setpbsz,(unsigned int));
1838 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1839 int,int,char *,int,int,int));
1840 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1841 _PROTOTYP(static int fts_cpl,(int));
1842 _PROTOTYP(static int fts_dpl,(int));
1844 _PROTOTYP(static int ftp_auth, (void));
1845 #endif /* FTP_SECURITY */
1846 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1847 _PROTOTYP(static int ftp_login, (char *));
1848 _PROTOTYP(static int ftp_reset, (void));
1849 _PROTOTYP(static int ftp_rename, (char *, char *));
1850 _PROTOTYP(static int ftp_umask, (char *));
1851 _PROTOTYP(static int secure_flush, (int));
1853 _PROTOTYP(static int secure_putc, (char, int));
1854 #endif /* COMMENT */
1855 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1856 _PROTOTYP(static int scommand, (char *));
1857 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1858 _PROTOTYP(static int secure_getc, (int, int));
1859 _PROTOTYP(static int secure_getbyte, (int, int));
1860 _PROTOTYP(static int secure_read, (int, char *, int));
1861 _PROTOTYP(static int initconn, (void));
1862 _PROTOTYP(static int dataconn, (char *));
1863 _PROTOTYP(static int setprotbuf,(unsigned int));
1864 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1866 _PROTOTYP(static char * radix_error,(int));
1867 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1868 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1870 _PROTOTYP(static VOID mlsreset, (void));
1871 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1872 _PROTOTYP(static VOID lostpeer, (void));
1873 _PROTOTYP(static VOID cancel_remote, (int));
1874 _PROTOTYP(static VOID changetype, (int, int));
1876 _PROTOTYP(static sigtype cmdcancel, (int));
1879 _PROTOTYP(static int srp_reset, ());
1880 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1881 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1882 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1883 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1884 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1885 _PROTOTYP(static int srp_selcipher, (char *));
1886 _PROTOTYP(static int srp_selhash, (char *));
1887 #endif /* FTP_SRP */
1890 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1891 #endif /* FTP_GSSAPI */
1893 /* D O F T P A R G -- Do an FTP command-line argument. */
1906 #define FT_SECURE 10
1907 #define FT_VERIFY 11
1909 static struct keytab ftpztab[] = {
1910 { "!gss", FT_NOGSS, 0 },
1911 { "!krb4", FT_NOK4, 0 },
1912 { "!srp", FT_NOSRP, 0 },
1913 { "!ssl", FT_NOSSL, 0 },
1914 { "!tls", FT_NOTLS, 0 },
1915 { "cert", FT_CERTFI, CM_ARG },
1916 { "certsok", FT_OKCERT, 0 },
1917 { "debug", FT_DEBUG, 0 },
1918 { "key", FT_KEY, CM_ARG },
1919 { "nogss", FT_NOGSS, 0 },
1920 { "nokrb4", FT_NOK4, 0 },
1921 { "nosrp", FT_NOSRP, 0 },
1922 { "nossl", FT_NOSSL, 0 },
1923 { "notls", FT_NOTLS, 0 },
1925 { "secure", FT_SECURE, 0 },
1926 #endif /* COMMENT */
1927 { "verify", FT_VERIFY, CM_ARG },
1930 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1933 The following cipher and hash tables should be replaced with
1934 dynamicly created versions based upon the linked library.
1936 #define SRP_BLOWFISH_ECB 1
1937 #define SRP_BLOWFISH_CBC 2
1938 #define SRP_BLOWFISH_CFB64 3
1939 #define SRP_BLOWFISH_OFB64 4
1940 #define SRP_CAST5_ECB 5
1941 #define SRP_CAST5_CBC 6
1942 #define SRP_CAST5_CFB64 7
1943 #define SRP_CAST5_OFB64 8
1944 #define SRP_DES_ECB 9
1945 #define SRP_DES_CBC 10
1946 #define SRP_DES_CFB64 11
1947 #define SRP_DES_OFB64 12
1948 #define SRP_DES3_ECB 13
1949 #define SRP_DES3_CBC 14
1950 #define SRP_DES3_CFB64 15
1951 #define SRP_DES3_OFB64 16
1953 static struct keytab ciphertab[] = {
1954 { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
1955 { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
1956 { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1957 { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1958 { "cast5_ecb", SRP_CAST5_ECB, 0 },
1959 { "cast5_cbc", SRP_CAST5_CBC, 0 },
1960 { "cast5_cfb64", SRP_CAST5_CFB64, 0 },
1961 { "cast5_ofb64", SRP_CAST5_OFB64, 0 },
1962 { "des_ecb", SRP_DES_ECB, 0 },
1963 { "des_cbc", SRP_DES_CBC, 0 },
1964 { "des_cfb64", SRP_DES_CFB64, 0 },
1965 { "des_ofb64", SRP_DES_OFB64, 0 },
1966 { "des3_ecb", SRP_DES3_ECB, 0 },
1967 { "des3_cbc", SRP_DES3_CBC, 0 },
1968 { "des3_cfb64", SRP_DES3_CFB64, 0 },
1969 { "des3_ofb64", SRP_DES3_OFB64, 0 },
1973 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1977 static struct keytab hashtab[] = {
1978 { "md5", SRP_MD5, 0 },
1980 { "sha", SRP_SHA, 0 },
1983 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1985 #endif /* FTP_SECURITY */
1988 strval(s1,s2) char * s1, * s2; {
1991 return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1995 static char * rfnptr = NULL;
1996 static int rfnlen = 0;
1997 static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
1998 static char * xgnbp = NULL;
2001 strgetc() { /* Helper function for xgnbyte() */
2007 c = (unsigned) *xgnbp++;
2008 return(((unsigned) c) & 0xff);
2011 static int /* Helper function for xpnbyte() */
2016 #endif /* CK_ANSIC */
2018 rfnlen = rfnptr - rfnbuf;
2019 if (rfnlen >= (RFNBUFSIZ - 1))
2031 #endif /* CK_ANSIC */
2038 bytswap(c0,c1) int * c0, * c1; {
2044 #endif /* NOCSETS */
2047 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
2048 int ftplogactive = 0;
2049 long ftplogprev = 0L;
2054 extern char diafil[];
2055 long d1, d2, t1, t2;
2058 debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
2059 debug(F110,"ftp cx log buf",ftplogbuf,0);
2061 if (!ftplogactive || !ftplogbuf[0]) /* No active record */
2064 ftplogactive = 0; /* Record is not active */
2066 d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
2067 ckstrncpy(buf,ckdate(),31); /* Get current date */
2068 d2 = mjd(buf); /* Convert them to mjds */
2069 p = ftplogbuf; /* Get start time */
2071 p[14] = NUL; /* Convert to seconds */
2072 t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2075 p = buf; /* Get end time */
2078 t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2079 t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
2083 ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
2084 ckstrncat(ftplogbuf,p,CXLOGBUFL);
2087 debug(F101,"ftp cx log dialog","",dialog);
2088 if (dialog) { /* If logging */
2090 x = diaopn(diafil,1,1); /* Open log in append mode */
2092 debug(F101,"ftp cx log open","",x);
2093 x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
2094 debug(F101,"ftp cx log write","",x);
2095 x = zclose(ZDIFIL); /* Close the log */
2096 debug(F101,"ftp cx log close","",x);
2103 ftplogend(); /* Previous session not closed out? */
2105 ftplogactive = 1; /* Record is active */
2107 ckmakxmsg(ftplogbuf,CXLOGBUFL,
2108 ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
2109 " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
2110 " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
2111 debug(F110,"ftp cx log begin",ftplogbuf,0);
2113 #endif /* CKLOGDIAL */
2115 static char * dummy[2] = { NULL, NULL };
2117 static struct keytab modetab[] = {
2123 int /* Called from ckuusy.c */
2128 #endif /* CK_ANSIC */
2132 extern char **xargv, *xarg0;
2133 extern int xargc, stayflg, haveftpuid;
2134 extern char uidbuf[];
2136 xp = *xargv+1; /* Pointer for bundled args */
2138 if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
2140 fatal("?Invalid argument bundling");
2143 if ((xargc < 1) || (**xargv == '-')) {
2144 fatal("?Required argument missing");
2147 switch (c) { /* Big switch on arg */
2148 case 'h': /* help */
2149 printf("C-Kermit's FTP client command-line personality. Usage:\n");
2150 printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
2151 printf("Options:\n");
2152 printf(" -h = help (this message)\n");
2153 printf(" -m mode = \"passive\" (default) or \"active\"\n");
2154 printf(" -u name = username for autologin (or -M)\n");
2155 printf(" -P password = password for autologin (RISKY)\n");
2156 printf(" -A = autologin anonymously\n");
2157 printf(" -D directory = cd after autologin\n");
2158 printf(" -b = force binary mode\n");
2159 printf(" -a = force text (\"ascii\") mode (or -T)\n");
2160 printf(" -d = debug (double to add timestamps)\n");
2161 printf(" -n = no autologin\n");
2162 printf(" -v = verbose (default)\n");
2163 printf(" -q = quiet\n");
2164 printf(" -S = Stay (issue command prompt when done)\n");
2165 printf(" -Y = do not execute Kermit init file\n");
2166 printf(" -p files = files to put after autologin (or -s)\n");
2167 printf(" -g files = files to get after autologin\n");
2168 printf(" -R = recursive (for use with -p)\n");
2171 printf("\nSecurity options:\n");
2172 printf(" -k realm = Kerberos 4 realm\n");
2173 printf(" -f = Kerboros 5 credentials forwarding\n");
2174 printf(" -x = autoencryption mode\n");
2175 printf(" -c cipher = SRP cipher type\n");
2176 printf(" -H hash = SRP encryption hash\n");
2177 printf(" -z option = Security options\n");
2178 #endif /* FTP_SECURITY */
2180 printf("\n-p or -g, if given, should be last. Example:\n");
2181 printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2183 doexit(GOOD_EXIT,-1);
2186 case 'R': /* Recursive */
2190 case 'd': /* Debug */
2196 deblog = debopn("debug.log",0);
2200 /* fall thru on purpose */
2202 case 't': /* Trace */
2206 case 'n': /* No autologin */
2210 case 'i': /* No prompt */
2211 case 'v': /* Verbose */
2212 break; /* (ignored) */
2214 case 'q': /* Quiet */
2218 case 'S': /* Stay */
2223 case 'u': /* My User Name */
2224 if ((int)strlen(*xargv) > 63) {
2225 fatal("username too long");
2227 ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2232 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2236 case 'T': /* Text */
2237 case 'a': /* "ascii" */
2238 case 'b': /* Binary */
2239 binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2240 ftp_xfermode = XMODE_M;
2247 case 's': { /* Send (= Put) */
2250 fatal("Only one FTP action at a time please");
2253 fatal("invalid argument bundling after -s");
2255 nfils = 0; /* Initialize file counter */
2256 havefiles = 0; /* Assume nothing to send */
2257 cmlist = xargv + 1; /* Remember this pointer */
2259 while (++xargv, --xargc > 0) { /* Traverse the list */
2266 if (!strcmp(*xargv,".")) {
2271 #endif /* RECURSIVE */
2272 if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2276 } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2281 xargc++, xargv--; /* Adjust argv/argc */
2284 fatal("No files to put");
2286 fatal("No files to get");
2292 case 'D': /* Directory */
2293 makestr(&ftp_rdir,*xargv);
2296 case 'm': /* Mode (Active/Passive */
2297 ftp_psv = lookup(modetab,*xargv,2,NULL);
2298 if (ftp_psv < 0) fatal("Invalid mode");
2302 makestr(&ftp_tmp,*xargv); /* You-Know-What */
2305 case 'Y': /* No initialization file */
2306 break; /* (already done in prescan) */
2309 case 'U': { /* URL */
2310 /* These are set by urlparse() - any not set are NULL */
2313 Kermit has accepted host:port notation since many years before URLs were
2314 invented. Unfortunately, URLs conflict with this notation. Thus "ftp
2315 host:449" looks like a URL and results in service = host and host = 449.
2316 Here we try to catch this situation transparently to the user.
2318 if (ckstrcmp(g_url.svc,"ftp",-1,0)
2320 && ckstrcmp(g_url.svc,"ftps",-1,0)
2327 g_url.por = g_url.hos;
2328 g_url.hos = g_url.svc;
2331 ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2332 g_url.svc," host=",g_url.hos);
2336 makestr(&ftp_host,g_url.hos);
2339 ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2340 makestr(&ftp_logname,uidbuf);
2343 makestr(&ftp_tmp,g_url.psw);
2348 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2349 makestr(&ftp_logname,uidbuf);
2352 fatal("Only one FTP action at a time please");
2357 dummy[0] = g_url.pth;
2369 case 'k': { /* K4 Realm */
2371 ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2372 #endif /* FTP_KRB4 */
2373 if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2379 if (ftp_deb) printf("K5 Credentials Forwarding\n");
2380 #else /* FTP_GSSAPI */
2381 printf("K5 Credentials Forwarding not supported\n");
2382 #endif /* FTP_GSSAPI */
2387 if (ftp_deb) printf("Autoencryption\n");
2390 case 'c': { /* Cipher */
2392 if (!srp_selcipher(*xargv)) {
2393 if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2395 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2397 printf("?SRP not supported\n");
2398 #endif /* FTP_SRP */
2403 if (!srp_selhash(*xargv)) {
2404 if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2406 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2408 printf("?SRP not supported\n");
2409 #endif /* FTP_SRP */
2413 /* *xargv contains a value of the form tag=value */
2414 /* we need to lookup the tag and save the value */
2415 char * p = NULL, * q = NULL;
2417 y = ckindex("=",p,0,0,1);
2420 x = lookup(ftpztab,p,nftpztab,&z);
2422 printf("?Invalid security option: \"%s\"\n",p);
2425 printf("Security option: \"%s",p);
2426 if (ftpztab[z].flgs & CM_ARG) {
2428 fatal("?Missing required value");
2431 fatal("?Missing required value");
2435 switch (ftpztab[z].kwval) { /* -z options w/args */
2438 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2439 if (ftp_auth_type[z] == FTA_GK5) {
2441 y < (FTPATYPS-1) && ftp_auth_type[y];
2444 ftp_auth_type[y] = ftp_auth_type[y+1];
2445 ftp_auth_type[FTPATYPS-1] = 0;
2449 #endif /* FTP_GSSAPI */
2453 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2454 if (ftp_auth_type[z] == FTA_K4) {
2456 y < (FTPATYPS-1) && ftp_auth_type[y];
2459 ftp_auth_type[y] = ftp_auth_type[y+1];
2460 ftp_auth_type[FTPATYPS-1] = 0;
2464 #endif /* FTP_KRB4 */
2468 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2469 if (ftp_auth_type[z] == FTA_SRP) {
2471 y < (FTPATYPS-1) && ftp_auth_type[y];
2474 ftp_auth_type[y] = ftp_auth_type[y+1];
2475 ftp_auth_type[FTPATYPS-1] = 0;
2479 #endif /* FTP_SRP */
2483 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2484 if (ftp_auth_type[z] == FTA_SSL) {
2486 y < (FTPATYPS-1) && ftp_auth_type[y];
2489 ftp_auth_type[y] = ftp_auth_type[y+1];
2490 ftp_auth_type[FTPATYPS-1] = 0;
2498 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2499 if (ftp_auth_type[z] == FTA_TLS) {
2501 y < (FTPATYPS-1) && ftp_auth_type[y];
2504 ftp_auth_type[y] = ftp_auth_type[y+1];
2505 ftp_auth_type[FTPATYPS-1] = 0;
2513 makestr(&ssl_rsa_cert_file,q);
2518 ssl_certsok_flag = 1;
2527 deblog = debopn("debug.log",0);
2533 makestr(&ssl_rsa_key_file,q);
2542 printf("?Bad number: %s\n",q);
2543 ssl_verify_flag = atoi(q);
2548 if (ftp_deb) printf("\"\n");
2552 #endif /* FTP_SECURITY */
2556 "unknown command-line option, type \"ftp -h\" for help"
2560 c = *++xp; /* See if options are bundled */
2573 return(connected ? loggedin : 0);
2578 return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2582 ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
2583 if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2585 ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
2593 /* g m s t i m e r -- Millisecond timer */
2598 /* For those versions of ztime() that also set global ztmsec. */
2603 if (!*p) return(0L);
2604 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2605 return(z * 1000 + ztmsec);
2607 return((long)time(NULL) * 1000L);
2608 #endif /* HAVE_MSECS */
2612 /* d o s e t f t p -- The SET FTP command */
2617 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2621 case FTS_FNC: /* Filename collision action */
2622 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2624 if ((y = cmcfm()) < 0)
2629 case FTS_CNV: /* Filename conversion */
2630 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2632 if ((y = cmcfm()) < 0)
2637 case FTS_DBG: /* Debug messages */
2638 return(seton(&ftp_deb));
2640 case FTS_LOG: /* Auto-login */
2641 return(seton(&ftp_log));
2643 case FTS_PSV: /* Passive mode */
2644 return(dosetftppsv());
2646 case FTS_SPC: /* Send port commands */
2647 x = seton(&ftp_spc);
2648 if (x > 0) sendport = ftp_spc;
2651 case FTS_TYP: /* Type */
2652 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2654 if ((y = cmcfm()) < 0) return(y);
2657 tenex = (ftp_typ == FTT_TEN);
2660 case FTS_USN: /* Unique server names */
2661 return(seton(&ftp_usn));
2663 case FTS_VBM: /* Verbose mode */
2664 if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
2666 ftp_vbx = ftp_vbm; /* Global sticky copy */
2669 case FTS_TST: /* "if (testing)" messages */
2670 return(seton(&testing));
2672 case FTS_PRM: /* Send permissions */
2673 return(setonaut(&ftp_prm));
2675 case FTS_AUT: /* Auto-authentication */
2676 return(seton(&ftp_aut));
2678 case FTS_ERR: /* Error action */
2679 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2681 if ((y = cmcfm()) < 0)
2684 return(success = 1);
2687 case FTS_XLA: /* Translation */
2688 return(seton(&ftp_xla));
2690 case FTS_CSR: /* Server charset */
2691 if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2693 if ((y = cmcfm()) < 0)
2696 ftp_xla = 1; /* Also enable translation */
2697 return(success = 1);
2698 #endif /* NOCSETS */
2701 return(seton(&get_auto)); /* GET-filetype-switching */
2704 return(seton(&ftp_dates)); /* Set file dates */
2707 case FTS_TMO: /* Timeout */
2708 if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
2710 if ((y = cmcfm()) < 0)
2713 return(success = 1);
2714 #endif /* FTP_TIMEOUT */
2716 case FTS_STO: { /* Server time offset */
2717 char * s, * p = NULL;
2719 if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2721 if (!strcmp(s,"+0")) {
2723 } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2724 printf("?Invalid time offset\n");
2727 makestr(&p,s); /* Make a safe copy the string */
2728 if ((x = cmcfm()) < 0) { /* Get confirmation */
2733 fts_sto = p; /* Confirmed - set the string. */
2734 return(success = 1);
2738 if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2740 makestr(&ftp_apw, *s ? s : NULL);
2741 return(success = 1);
2745 if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2750 return seton(&ftp_bug_use_ssl_v2);
2752 return seton(&ftp_bug_use_ssl_v3);
2760 case FTS_CRY: /* Auto-encryption */
2761 return(seton(&ftp_cry));
2763 case FTS_CFW: /* Credential-forwarding */
2764 return(seton(&ftp_cfw));
2766 case FTS_CPL: /* Command protection level */
2767 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2768 if ((y = cmcfm()) < 0) return(y);
2769 success = fts_cpl(x);
2772 case FTS_DPL: /* Data protection level */
2773 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2774 if ((y = cmcfm()) < 0) return(y);
2775 success = fts_dpl(x);
2778 case FTS_ATP: { /* FTP Auth Type */
2779 int i, j, atypes[8];
2781 for (i = 0; i < 8; i++) {
2782 if ((y = cmkey(ftpauth,nftpauth,"",
2783 (i == 0) ? "automatic" : "",
2789 if (i > 0 && (y == FTA_AUTO)) {
2790 printf("?Choice may only be used in first position.\r\n");
2793 for (j = 0; j < i; j++) {
2794 if (atypes[j] == y) {
2795 printf("\r\n?Choice has already been used.\r\n");
2800 if (y == FTA_AUTO) {
2807 if ((z = cmcfm()) < 0)
2809 if (atypes[0] == FTA_AUTO) {
2812 ftp_auth_type[i++] = FTA_GK5;
2813 #endif /* FTP_GSSAPI */
2815 ftp_auth_type[i++] = FTA_SRP;
2816 #endif /* FTP_SRP */
2818 ftp_auth_type[i++] = FTA_K4;
2819 #endif /* FTP_KRB4 */
2821 ftp_auth_type[i++] = FTA_TLS;
2822 ftp_auth_type[i++] = FTA_SSL;
2824 ftp_auth_type[i] = 0;
2826 for (i = 0; i < 8; i++)
2827 ftp_auth_type[i] = atypes[i];
2829 return(success = 1);
2834 if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2838 if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2840 if ((z = cmcfm()) < 0)
2842 success = !srp_selcipher(ciphertab[x].kwd);
2845 if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2847 if ((z = cmcfm()) < 0)
2849 success = !srp_selhash(hashtab[x].kwd);
2850 return(success = 1);
2852 if ((z = cmcfm()) < 0)
2857 if ((z = cmcfm()) < 0)
2860 #endif /* FTP_SRP */
2861 #endif /* FTP_SECURITY */
2864 doxdis(2); /* 2 == ftp */
2865 return(success = 1);
2878 printf(" ftp closing %s...\n",ftp_host);
2880 return((x > -1) ? 1 : 0);
2883 /* o p e n f t p -- Parse FTP hostname & port and open */
2886 openftp(s,opn_tls) char * s; int opn_tls; {
2887 char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2888 int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2890 struct FDB sw, fl, cm;
2891 extern int nnetdir; /* Network services directory */
2892 extern int nhcount; /* Lookup result */
2893 extern char *nh_p[]; /* Network directory entry pointers */
2894 extern char *nh_p2[]; /* Network directory entry nettype */
2897 if (!*s) return(-2);
2899 makestr(&hostname,s);
2900 hostsave = hostname;
2901 makestr(&ftp_logname,NULL);
2905 debug(F110,"ftp open",hostname,0);
2907 if (sav_psv > -1) { /* Restore prevailing active/passive */
2908 ftp_psv = sav_psv; /* selection in case it was */
2909 sav_psv = -1; /* temporarily overriden by a switch */
2911 if (sav_log > -1) { /* Ditto for autologin */
2915 cmfdbi(&sw, /* Switches */
2917 "Service name or port;\n or switch",
2919 "", /* addtl string data */
2920 nftpswi, /* addtl numeric data 1: tbl size */
2921 4, /* addtl numeric data 2: none */
2922 xxstring, /* Processing function */
2923 ftpswitab, /* Keyword table */
2924 &fl /* Pointer to next FDB */
2926 cmfdbi(&fl, /* A host name or address */
2929 "xYzBoo", /* default */
2930 "", /* addtl string data */
2931 0, /* addtl numeric data 1 */
2932 0, /* addtl numeric data 2 */
2937 cmfdbi(&cm, /* Command confirmation */
2950 rc = cmfdb(&sw); /* Parse a service name or a switch */
2954 if (cmresult.fcode == _CMCFM) { /* Done? */
2956 } else if (cmresult.fcode == _CMFLD) { /* Port */
2957 if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2958 makestr(&service,cmresult.sresult);
2960 makestr(&service,opn_tls?"ftps":"ftp");
2961 } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2962 c = cmgbrk(); /* get break character */
2963 getval = (c == ':' || c == '=');
2965 if (getval && !(cmresult.kflags & CM_ARG)) {
2966 printf("?This switch does not take arguments\n");
2969 if (!getval && (cmresult.kflags & CM_ARG)) {
2970 printf("?This switch requires an argument\n");
2973 switch (cmresult.nresult) { /* Switch */
2974 case OPN_ANO: /* /ANONYMOUS */
2978 case OPN_NIN: /* /NOINIT */
2981 case OPN_NOL: /* /NOLOGIN */
2984 makestr(&ftp_logname,NULL);
2986 case OPN_PSW: /* /PASSWORD */
2987 if (!anonymous) /* Don't log real passwords */
2989 rc = cmfld("Password for FTP server","",&p,xxstring);
2991 makestr(&ftp_tmp,NULL);
2992 } else if (rc < 0) {
2995 makestr(&ftp_tmp,brstrip(p));
2999 case OPN_USR: /* /USER */
3000 rc = cmfld("Username for FTP server","",&p,xxstring);
3002 makestr(&ftp_logname,NULL);
3003 } else if (rc < 0) {
3009 makestr(&ftp_logname,brstrip(p));
3013 rc = cmfld("Account for FTP server","",&p,xxstring);
3015 makestr(&ftp_acc,NULL);
3016 } else if (rc < 0) {
3019 makestr(&ftp_acc,brstrip(p));
3035 if (n == 0) { /* After first time through */
3036 cmfdbi(&sw, /* accept only switches */
3038 "\nCarriage return to confirm to command, or switch",
3050 debug(F100,"ftp openftp while exit","",0);
3052 debug(F101,"ftp openftp cmcfm rc","",rc);
3055 #endif /* COMMENT */
3057 if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
3061 if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
3063 ftp_log = haveuser ? 1 : 0;
3065 if (*hostname == '=') { /* Bypass directory lookup */
3066 hostname++; /* if hostname starts with '=' */
3068 } else if (isdigit(*hostname)) { /* or if it starts with a digit */
3072 makestr(&service,opn_tls?"ftps":"ftp");
3075 if (!havehost && nnetdir > 0) { /* If there is a networks directory */
3076 lunet(hostname); /* Look up the name */
3077 debug(F111,"ftp openftp lunet",hostname,nhcount);
3080 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3081 success = ftpopen(hostname,service,opn_tls);
3082 debug(F101,"ftp openftp A ftpopen success","",success);
3086 for (i = 0; i < nhcount; i++) {
3087 if (nh_p2[i]) /* If network type specified */
3088 if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
3091 makestr(&hostname,nh_p[i]);
3092 debug(F111,"ftpopen lunet substitution",hostname,i);
3094 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3095 success = ftpopen(hostname,service,opn_tls);
3096 debug(F101,"ftp openftp B ftpopen success","",success);
3101 if (!found) { /* E.g. if no network types match */
3103 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3104 success = ftpopen(hostname,service,opn_tls);
3105 debug(F101,"ftp openftp C ftpopen success","",success);
3112 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3113 success = ftpopen(hostname,service,opn_tls);
3114 debug(F111,"ftp openftp D ftpopen success",hostname,success);
3115 debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
3122 debug(F101,"ftp openftp xopenftp rc","",rc);
3123 if (hostsave) free(hostsave);
3124 if (service) free(service);
3125 if (rc < 0 && ftp_logname) {
3136 VOID /* 12 Aug 2007 */
3137 doftpglobaltype(x) int x; {
3138 ftp_xfermode = XMODE_M; /* Set manual FTP transfer mode */
3139 ftp_typ = x; /* Used by top-level BINARY and */
3140 g_ftp_typ = x; /* ASCII commands. */
3149 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
3152 makestr(&ftp_acc,brstrip(s));
3154 printf(" ftp account: \"%s\"\n",ftp_acc);
3155 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
3160 doftpusr() { /* Log in as USER */
3161 extern char uidbuf[];
3162 extern char pwbuf[];
3163 extern int pwflg, pwcrypt;
3165 char *s, * acct = "";
3167 debok = 0; /* Don't log */
3169 if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
3171 ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
3172 if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
3173 if (x == -3) { /* no input */
3174 if ( pwbuf[0] && pwflg ) {
3175 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
3178 ck_encrypt((char *)tmpbuf);
3185 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
3187 if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
3188 "", &s, xxstring)) < 0)
3194 acct = &tmpbuf[x+2];
3195 ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
3199 printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
3200 success = ftp_user(line,tmpbuf,acct);
3203 #endif /* CKLOGDIAL */
3207 /* DO (various FTP commands)... */
3210 doftptyp(type) int type; { /* TYPE */
3213 changetype(ftp_typ,ftp_vbm);
3214 debug(F101,"doftptyp changed type","",type);
3219 doftpxmkd(s,vbm) char * s; int vbm; { /* MKDIR action */
3220 int lcs = -1, rcs = -1;
3224 if (lcs < 0) lcs = fcharset;
3226 if (rcs < 0) rcs = ftp_csr;
3228 #endif /* NOCSETS */
3229 debug(F110,"ftp doftpmkd",s,0);
3230 if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3231 return(success = 1);
3232 if (ftpcode == 500 || ftpcode == 502) {
3234 printf("MKD command not recognized, trying XMKD\n");
3235 if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3236 return(success = 1);
3238 return(success = 0);
3242 doftpmkd() { /* MKDIR parse */
3245 if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3248 ckstrncpy(line,s,LINBUFSIZ);
3250 printf(" ftp mkdir \"%s\"...\n",line);
3251 return(success = doftpxmkd(line,-1));
3255 doftprmd() { /* RMDIR */
3256 int x, lcs = -1, rcs = -1;
3258 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3261 ckstrncpy(line,s,LINBUFSIZ);
3263 printf(" ftp rmdir \"%s\"...\n",line);
3267 if (lcs < 0) lcs = fcharset;
3269 if (rcs < 0) rcs = ftp_csr;
3271 #endif /* NOCSETS */
3272 if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3273 return(success = 1);
3274 if (ftpcode == 500 || ftpcode == 502) {
3276 printf("RMD command not recognized, trying XMKD\n");
3277 success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3284 doftpren() { /* RENAME */
3287 if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3289 ckstrncpy(line,s,LINBUFSIZ);
3290 if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3292 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3293 if ((x = cmcfm()) < 0)
3297 printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3298 success = ftp_rename(line,tmpbuf);
3303 doftpres() { /* RESET (log out without close) */
3305 if ((x = cmcfm()) < 0)
3309 printf(" ftp reset...\n");
3310 return(success = ftp_reset());
3314 doftpxhlp() { /* HELP */
3317 if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3320 ckstrncpy(line,s,LINBUFSIZ);
3322 printf(" ftp help \"%s\"...\n",line);
3323 /* No need to translate -- all FTP commands are ASCII */
3324 return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3328 doftpdir(cx) int cx; { /* [V]DIRECTORY */
3329 int x, lcs = 0, rcs = 0, xlate = 0;
3330 char * p, * s, * m = "";
3331 if (cx == FTP_VDI) {
3332 switch (servertype) {
3343 if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3345 if ((x = remtxt(&s)) < 0)
3351 #endif /* NOCSETS */
3353 ckstrncpy(line,s,LINBUFSIZ);
3358 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
3359 lcs = ftp_csl; /* Local charset */
3360 if (lcs < 0) lcs = fcharset;
3361 if (lcs < 0) xlate = 0;
3363 if (xlate) { /* Still ON? */
3364 rcs = ftp_csx; /* Remote (Server) charset */
3365 if (rcs < 0) rcs = ftp_csr;
3366 if (rcs < 0) xlate = 0;
3368 #endif /* NOCSETS */
3374 printf("Directory of files %s at %s:\n", line, ftp_host);
3376 printf("Directory of files at %s:\n", ftp_host);
3378 debug(F111,"doftpdir",s,cx);
3380 if (cx == FTP_DIR) {
3381 /* Translation of line[] is done inside recvrequest() */
3382 /* when it calls ftpcmd(). */
3384 (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3386 success = 1; /* VDIR - one file at a time... */
3387 p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3389 if (!ftp_vbm && !quiet)
3391 while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3392 if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3396 p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3397 debug(F110,"ftp vdir file",s,0);
3403 doftppwd() { /* PWD */
3404 int x, lcs = -1, rcs = -1;
3408 if (lcs < 0) lcs = fcharset;
3410 if (rcs < 0) rcs = ftp_csr;
3412 #endif /* NOCSETS */
3413 if ((x = cmcfm()) < 0)
3416 if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3418 } else if (ftpcode == 500 || ftpcode == 502) {
3420 printf("PWD command not recognized, trying XPWD\n");
3421 success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3427 doftpcwd(s,vbm) char * s; int vbm; { /* CD (CWD) */
3428 int lcs = -1, rcs = -1;
3432 if (lcs < 0) lcs = fcharset;
3434 if (rcs < 0) rcs = ftp_csr;
3436 #endif /* NOCSETS */
3438 debug(F110,"ftp doftpcwd",s,0);
3439 if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3440 return(success = 1);
3441 if (ftpcode == 500 || ftpcode == 502) {
3443 printf("CWD command not recognized, trying XCWD\n");
3444 if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3445 return(success = 1);
3447 return(success = 0);
3451 doftpcdup() { /* CDUP */
3452 debug(F100,"ftp doftpcdup","",0);
3453 if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3454 return(success = 1);
3455 if (ftpcode == 500 || ftpcode == 502) {
3457 printf("CDUP command not recognized, trying XCUP\n");
3458 if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3459 return(success = 1);
3461 return(success = 0);
3464 /* s y n c d i r -- Synchronizes client & server directories */
3468 local = pointer to pathname of local file to be sent.
3469 sim = 1 for simulation, 0 for real uploading.
3470 Returns 0 on failure, 1 on success.
3472 The 'local' argument is relative to the initial directory of the MPUT,
3473 i.e. the root of the tree being uploaded. If the directory of the
3474 argument file is different from the directory of the previous file
3475 (which is stored in global putpath[]), this routine does the appropriate
3476 CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
3478 static int cdlevel = 0, cdsimlvl = 0; /* Tree-level trackers */
3481 syncdir(local,sim) char * local; int sim; {
3482 char buf[CKMAXPATH+1];
3483 char tmp[CKMAXPATH+1];
3484 char msgbuf[CKMAXPATH+64];
3485 char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
3486 int i, k = 0, done = 0, itsadir = 0, saveq;
3488 debug(F110,"ftp syncdir local (new)",local,0);
3489 debug(F110,"ftp syncdir putpath (old)",putpath,0);
3491 itsadir = isdir(local); /* Is the local file a directory? */
3494 while ((*s = *p)) { /* Copy the argument filename */
3495 if (++k == CKMAXPATH) /* so we can poke it. */
3497 if (*s == '/') /* Pointer to rightmost dirsep */
3502 if (!itsadir) /* If it's a regular file */
3503 *q = NUL; /* keep just the path part */
3505 debug(F110,"ftp syncdir buf",buf,0);
3506 if (!strcmp(buf,putpath)) { /* Same path as previous file? */
3507 if (itsadir) { /* This file is a directory? */
3508 if (doftpcwd(local,0)) { /* Try to CD to it */
3509 doftpcdup(); /* Worked - CD back up */
3510 } else if (sim) { /* Simulating... */
3511 if (fdispla == XYFD_B) {
3512 printf("WOULD CREATE DIRECTORY %s\n",local);
3513 } else if (fdispla) {
3514 ckmakmsg(msgbuf,CKMAXPATH,
3515 "WOULD CREATE DIRECTORY",local,NULL,NULL);
3516 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3518 /* See note above */
3520 } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3522 } else { /* Remote directory created OK */
3523 if (fdispla == XYFD_B) {
3524 printf("CREATED DIRECTORY %s\n",local);
3525 } else if (fdispla) {
3526 ckmakmsg(msgbuf,CKMAXPATH+64,
3527 "CREATED DIRECTORY ",local,NULL,NULL);
3528 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3532 debug(F110,"ftp syncdir no change",buf,0);
3533 return(1); /* Yes, done. */
3535 ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
3536 debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3539 s = putpath; /* Old */
3541 debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
3542 debug(F110,"ftp syncdir A (new) p",p,0); /* New */
3546 while (*p != NUL && *s != NUL && *p == *s) {
3547 if (*p == '/') { psep = p+1; ssep = s+1; }
3551 psep and ssep point to the first path segment that differs.
3552 We have to do as many CDUPs as there are path segments in ssep.
3553 then we have to do as many MKDs and CWDs as there are segments in psep.
3558 debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
3559 debug(F110,"ftp syncdir B (new) p",p,0); /* New */
3561 /* p and s now point to the leftmost spot where the paths differ */
3563 if (*s) { /* We have to back up */
3564 k = 1; /* How many levels counting this one */
3565 while ((c = *s++)) { /* Count dirseps remaining in prev */
3569 debug(F101,"ftp syncdir levels up","",k);
3571 for (i = 1; i <= k; i++) { /* Do that many CDUPs */
3572 debug(F111,"ftp syncdir CDUP A",p,i);
3573 if (fdispla == XYFD_B)
3575 if (sim && cdsimlvl) {
3585 if (!*p) /* If we don't have to go down */
3586 goto xcwd; /* we're done. */
3589 while (p > buf && *p && *p != '/') /* If in middle of segment */
3590 p--; /* back up to beginning */
3591 if (*p == '/') /* and terminate there */
3593 #endif /* COMMENT */
3595 debug(F110,"ftp syncdir NEW PATH",p,0);
3597 s = p; /* Point to start of new down path. */
3598 while (1) { /* Loop through characters. */
3599 if (*s == '/' || !*s) { /* Have a segment. */
3600 if (!*s) /* If end of string, */
3601 done++; /* after this segment we're done. */
3603 *s = NUL; /* NUL out the separator. */
3604 if (*p) { /* If segment is not empty */
3605 debug(F110,"ftp syncdir down segment",p,0);
3606 if (!doftpcwd(p,0)) { /* Try to CD to it */
3608 if (fdispla == XYFD_B) {
3609 printf(" WOULD CREATE DIRECTORY %s\n",local);
3610 } else if (fdispla) {
3611 ckmakmsg(msgbuf,CKMAXPATH,
3612 "WOULD CREATE DIRECTORY",
3614 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3618 if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3619 debug(F110,"ftp syncdir mkdir failed",p,0);
3621 Suppose we are executing SEND /RECURSIVE. Locally we have a directory
3622 FOO but the remote has a regular file with the same name. We can't CD
3623 to it, can't MKDIR it either. There's no way out but to fail and let
3624 the user handle the problem.
3629 debug(F110,"ftp syncdir mkdir OK",p,0);
3630 if (fdispla == XYFD_B) {
3631 printf(" CREATED DIRECTORY %s\n",p);
3632 } else if (fdispla) {
3633 ckmakmsg(msgbuf,CKMAXPATH,
3634 "CREATED DIRECTORY ",p,NULL,NULL);
3635 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3637 if (!doftpcwd(p,0)) { /* Try again to CD */
3638 debug(F110,"ftp syncdir CD failed",p,0);
3642 if (fdispla == XYFD_B) printf(" CWD %s\n",p);
3643 debug(F110,"ftp syncdir CD OK",p,0);
3648 if (done) /* Quit if no next segment */
3650 p = s+1; /* Point to next segment */
3652 s++; /* Point to next source char */
3656 ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3664 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3666 debug(F111,"ftp year ",s,xx->tm_year);
3667 debug(F111,"ftp month",s,xx->tm_mon);
3668 debug(F111,"ftp day ",s,xx->tm_mday);
3669 debug(F111,"ftp hour ",s,xx->tm_hour);
3670 debug(F111,"ftp min ",s,xx->tm_min);
3671 debug(F111,"ftp sec ",s,xx->tm_sec);
3676 /* t m c o m p a r e -- Compare two struct tm's */
3678 /* Like strcmp() but for struct tm's */
3679 /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3682 tmcompare(xx,yy) struct tm * xx, * yy; {
3684 if (xx->tm_year < yy->tm_year) /* First year less than second */
3686 if (xx->tm_year > yy->tm_year) /* First year greater than second */
3689 /* Years are equal so compare months */
3691 if (xx->tm_mon < yy->tm_mon) /* And so on... */
3693 if (xx->tm_mon > yy->tm_mon)
3696 if (xx->tm_mday < yy->tm_mday)
3698 if (xx->tm_mday > yy->tm_mday)
3701 if (xx->tm_hour < yy->tm_hour)
3703 if (xx->tm_hour > yy->tm_hour)
3706 if (xx->tm_min < yy->tm_min)
3708 if (xx->tm_min > yy->tm_min)
3711 if (xx->tm_sec < yy->tm_sec)
3713 if (xx->tm_sec > yy->tm_sec)
3718 #endif /* DOUPDATE */
3720 #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */
3721 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3722 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3725 /* Macro for whether a given year is a leap year. */
3726 #define ISLEAP(year) \
3727 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3728 #endif /* HAVE_TIMEGM */
3730 /* m k u t i m e -- Like mktime() but argument is already UTC */
3734 mkutime(struct tm * tm)
3736 mkutime(tm) struct tm * tm;
3737 #endif /* CK_ANSIC */
3740 return(timegm(tm)); /* Have system service, use it. */
3743 Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3744 Given a struct tm representing a calendar time in UTC, convert it to
3745 seconds since epoch. Returns (time_t) -1 if the time is not
3746 convertable. Note that this function does not canonicalize the provided
3747 struct tm, nor does it allow out-of-range values or years before 1970.
3748 Result should be identical with timegm().
3753 We do allow some ill-formed dates, but we don't do anything special
3754 with them and our callers really shouldn't pass them to us. Do
3755 explicitly disallow the ones that would cause invalid array accesses
3756 or other algorithm problems.
3760 debug(F101,"mkutime tm_mon","",tm->tm_mon);
3761 debug(F101,"mkutime tm_year","",tm->tm_year);
3764 if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3765 return((time_t) -1);
3767 /* Convert to time_t. */
3768 for (i = 1970; i < tm->tm_year + 1900; i++)
3769 result += 365 + ISLEAP(i);
3770 for (i = 0; i < tm->tm_mon; i++)
3771 result += MONTHDAYS[i];
3772 if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3774 result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3775 result = 60 * result + tm->tm_min;
3776 result = 60 * result + tm->tm_sec;
3777 debug(F101,"mkutime result","",result);
3779 #endif /* HAVE_TIMEGM */
3784 s e t m o d t i m e -- Set file modification time.
3786 f = char * filename;
3787 t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3789 UNIX-specific; isolates mainline code from hideous #ifdefs.
3797 setmodtime(char * f, time_t t)
3799 setmodtime(f,t) char * f; time_t t;
3800 #endif /* CK_ANSIC */
3809 struct timeval tp[2];
3810 #else /* def BSD44 */
3822 #else /* def SYSUTIMEH */
3825 #define SYSUTIMEH /* Our utimbuf matches this one. */
3831 #endif /* def VMS [else] */
3832 #endif /* def SYSUTIMEH [else] */
3833 #endif /* def V7 [else] */
3834 #endif /* def BSD44 [else] */
3836 if (stat(f,&sb) < 0) {
3837 debug(F111,"setmodtime stat failure",f,errno);
3841 tp[0].tv_sec = sb.st_atime; /* Access time first */
3842 tp[1].tv_sec = t; /* Update time second */
3843 debug(F111,"setmodtime BSD44",f,t);
3846 tp.timep[0] = t; /* Set modif. time to creation date */
3847 tp.timep[1] = sb.st_atime; /* Don't change the access time */
3848 debug(F111,"setmodtime V7",f,t);
3851 tp.modtime = t; /* Set modif. time to creation date */
3852 tp.actime = sb.st_atime; /* Don't change the access time */
3853 debug(F111,"setmodtime SYSUTIMEH",f,t);
3855 tp.mtime = t; /* Set modif. time to creation date */
3856 tp.atime = sb.st_atime; /* Don't change the access time */
3857 debug(F111,"setmodtime (other)",f,t);
3858 #endif /* SYSUTIMEH */
3862 /* Try to set the file date */
3866 debug(F111,"setmodtime utimes()","BSD44",x);
3871 The following produces the nonsensical warning:
3872 Argument of type "const struct utimbuf *" is incompatible with
3873 parameter of type "const struct utimbuf *". If you can make it
3874 go away, be my guest.
3876 const struct utimbuf * t2 = &tp;
3881 debug(F111,"setmodtime utime()","other",x);
3887 debug(F101,"setmodtime result","",rc);
3893 c h k m o d t i m e -- Check/Set file modification time.
3898 0 if local older than remote,
3899 1 if modtimes are equal,
3900 2 if local newer than remote.
3901 1 = Set (local file's modtime from remote's); returns:
3906 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3908 struct _stat statbuf;
3910 struct stat statbuf;
3912 struct tm * tmlocal = NULL;
3914 int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3915 char * s, timebuf[64];
3917 debug(F111,"chkmodtime",local,mdtmok);
3918 if (!mdtmok) /* Server supports MDTM? */
3919 return(-1); /* No don't bother. */
3924 if (lcs < 0) lcs = fcharset;
3926 if (rcs < 0) rcs = ftp_csr;
3928 #endif /* NOCSETS */
3931 rc = stat(local,&statbuf);
3932 if (rc == 0) { /* Get local file's mod time */
3933 /* Convert to struct tm */
3934 tmlocal = gmtime((time_t *)&statbuf.st_mtime);
3937 dbtime(local,tmlocal);
3942 /* Get remote file's mod time as yyyymmddhhmmss */
3944 if (havemdtm) { /* Already got it from MLSD? */
3947 } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3949 bzero((char *)&tmremote, sizeof(struct tm));
3951 while ((c = *s++)) { /* Skip past response code */
3959 debug(F111,"ftp chkmodtime string",s,flag);
3960 if (fts_sto) { /* User gave server time offset? */
3962 debug(F110,"ftp chkmodtime offset",fts_sto,0);
3963 ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3964 if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3965 ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
3966 timebuf[8] = timebuf[9]; /* h */
3967 timebuf[9] = timebuf[10]; /* h */
3968 timebuf[10] = timebuf[12]; /* m */
3969 timebuf[11] = timebuf[13]; /* m */
3970 timebuf[12] = timebuf[12]; /* s */
3971 timebuf[13] = timebuf[13]; /* s */
3974 debug(F110,"ftp chkmodtime adjust",s,0);
3977 if (flag) { /* Convert to struct tm */
3979 int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
3980 if (!ckstrcmp(s,"191",3,0)) {
3981 pat = "%05d%02d%02d%02d%02d%02d";
3983 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3985 pat = "%04d%02d%02d%02d%02d%02d";
3987 if (sscanf(s, /* Parse into struct tm */
3989 &(tmremote.tm_year),
3991 &(tmremote.tm_mday),
3992 &(tmremote.tm_hour),
3996 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3997 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
4001 debug(F100,"SERVER TIME FOLLOWS:","",0);
4002 dbtime(remote,&tmremote);
4009 } else { /* Failed */
4010 debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
4011 if (ftpcode == 500 || /* Command unrecognized */
4012 ftpcode == 502 || /* Command not implemented */
4013 ftpcode == 202) /* Command superfluous */
4014 mdtmok = 0; /* Don't ask this server again */
4017 if (fc == 0) { /* Compare */
4018 if (havedate == 1) { /* Only if we have both file dates */
4020 Compare with local file's time. We don't use
4021 clock time (time_t) here in case of signed/unsigned
4028 dbtime("LOCAL",tmlocal);
4029 dbtime("REMOT",&tmremote);
4032 #endif /* COMMENT */
4033 xx = tmcompare(tmlocal,&tmremote);
4034 debug(F101,"chkmodtime tmcompare","",xx);
4037 } else if (ftp_dates) { /* Set */
4039 Here we must convert struct tm to time_t
4040 without applying timezone conversion, for which
4041 there is no portable API. The method is hidden
4042 in mkutime(), defined above.
4045 utc = mkutime(&tmremote);
4046 debug(F111,"ftp chkmodtime mkutime",remote,utc);
4047 if (utc != (time_t)-1)
4048 return(setmodtime(local,utc));
4053 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
4056 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
4057 char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
4066 #endif /* GFTIMER */
4067 char fullname[CKMAXPATH+1];
4069 debug(F110,"ftp getfile remote A",remote,0);
4070 debug(F110,"ftp getfile local A",local,0);
4071 debug(F110,"ftp getfile pipename",pipename,0);
4072 if (!remote) remote = "";
4075 /* Automatic type switching? */
4076 if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
4078 x = matchname(remote,0,servertype);
4079 debug(F111,"ftp getfile matchname",remote,x);
4081 case 0: ftp_typ = FTT_ASC; break;
4082 case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
4083 default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
4085 changetype(ftp_typ,ftp_vbm);
4086 binary = ftp_typ; /* For file-transfer display */
4088 #endif /* PATTERNS */
4091 ftp_csx = -1; /* For file-transfer display */
4092 ftp_csl = -1; /* ... */
4094 if (rcs > -1) /* -1 means no translation */
4095 if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
4096 if (fcs < 0) /* File charset not forced? */
4097 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4098 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4099 debug(F110,"ftp getfile","initxlate",0);
4100 initxlate(rcs,fcs); /* NB: opposite order of PUT */
4105 #endif /* NOCSETS */
4107 if (!local) local = "";
4108 if (!pipename && !*local)
4111 out2screen = !strcmp(local,"-");
4115 ckstrncpy(fullname,pipename,CKMAXPATH+1);
4117 zfnqfp(local,CKMAXPATH,fullname);
4119 ckstrncpy(fullname,local,CKMAXPATH+1);
4121 if (!out2screen && displa && fdispla) { /* Screen */
4122 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
4123 ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
4124 ftscreen(SCR_FS,0,fsize,"");
4126 tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
4127 tlog(F110," as",fullname,0);
4128 debug(F111,"ftp getfile size",remote,fsize);
4129 debug(F111,"ftp getfile local",local,out2screen);
4131 ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
4133 t0 = gmstimer(); /* Start time */
4134 debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
4135 rc = recvrequest("RETR",
4138 append ? "ab" : "wb",
4146 t1 = gmstimer(); /* End time */
4147 debug(F111,"ftp getfile t1",remote,t1);
4148 debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
4150 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4151 fpxfsecs = sec; /* (for doxlog()) */
4153 sec = (t1 - t0) / 1000;
4155 #endif /* GFTIMER */
4160 #endif /* FTP_TIMEOUT */
4162 debug(F111,"ftp recvrequest rc",remote,rc);
4163 if (cancelfile || cancelgroup) {
4164 debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
4165 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4166 } else if (rc > 0) {
4167 debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
4168 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
4169 } else if (rc < 0) {
4171 case -4: /* Network error */
4172 case -2: /* File error */
4173 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
4176 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
4177 "Failure to make data connection");
4179 case -1: /* (should be covered above) */
4180 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4183 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4185 } else { /* Tudo bem */
4186 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4188 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
4189 makestr(&rrfspec,remote); /* For WHERE command */
4190 makestr(&rfspec,fullname);
4194 if (ftp_dates) /* If FTP DATES ON... */
4195 if (!pipename && !out2screen) /* and it's a real file */
4196 if (rc < 1 && rc != -3) /* and it wasn't skipped */
4197 if (connected) /* and we still have a connection */
4198 if (zchki(local) > -1) { /* and the file wasn't discarded */
4199 chkmodtime(local,remote,1); /* set local file date */
4200 debug(F110,"ftp get set date",local,0);
4202 filcnt++; /* Used by \v(filenum) */
4207 tlog(F100," recovery skipped","",0);
4208 } else if (rc == 0) {
4209 tlog(F101," complete, size", "", fsize);
4210 } else if (cancelfile) {
4211 tlog(F100," canceled by user","",0);
4213 } else if (ftp_timed_out) {
4214 tlog(F100," timed out","",0);
4215 #endif /* FTP_TIMEOUT */
4217 tlog(F110," failed:",ftp_reply_str,0);
4220 doxlog(what,local,fsize,ftp_typ,rc,"");
4226 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
4227 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
4231 local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
4232 char * local, * remote, * mvto, *rnto, *srvrn;
4233 int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
4237 char asname[CKMAXPATH+1];
4238 char fullname[CKMAXPATH+1];
4239 int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
4240 int xlate = 0, restart = 0, mt = -1;
4241 char * s = NULL, * cmd = NULL;
4242 ULONG t0 = 0, t1 = 0; /* Times for stats */
4243 int ofcs = 0, orcs = 0;
4249 #endif /* GFTIMER */
4250 debug(F111,"ftp putfile flg",local,flg);
4251 debug(F110,"ftp putfile srv_renam",srvrn,0);
4252 debug(F101,"ftp putfile fcs","",fcs);
4253 debug(F101,"ftp putfile rcs","",rcs);
4255 ofcs = fcs; /* Save charset args */
4258 sendstart = (CK_OFF_T)0;
4259 restart = flg & PUT_RES;
4263 /* FTP protocol command to send to server */
4264 cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
4266 if (x_cnv == SET_AUTO) { /* Name conversion is auto */
4267 if (alike) { /* If server & client are alike */
4268 nc = 0; /* no conversion */
4269 } else { /* If they are different */
4270 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
4271 nc = -1; /* only minimal conversions needed */
4272 else /* otherwise */
4273 nc = 1; /* full conversion */
4275 } else /* Not auto - do what user said */
4278 /* If Transfer Mode is Automatic, determine file type */
4279 if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
4280 if (isdir(local)) { /* If it's a directory */
4281 k = FT_BIN; /* skip the file scan */
4283 debug(F110,"FTP PUT calling scanfile",local,0);
4284 k = scanfile(local,&o,nscanfile); /* Scan the file */
4286 debug(F111,"FTP PUT scanfile",local,k);
4287 if (k > -1 && !forcetype) {
4288 ftp_typ = (k == FT_BIN) ? 1 : 0;
4289 if (xft > -1 && ftp_typ != xft) {
4291 tlog(F110,"ftp put SKIP (Type):", local, 0);
4294 if (ftp_typ == 1 && tenex) /* User said TENEX? */
4299 ftp_csx = -1; /* For file-transfer display */
4300 ftp_csl = -1; /* ... */
4302 if (rcs > -1) { /* -1 means no translation */
4303 if (ftp_typ == 0) { /* File type is "ascii"? */
4304 if (fcs < 0) { /* File charset not forced? */
4305 if (k < 0) { /* If we didn't scan */
4306 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4307 } else { /* If we did scan, use scan result */
4309 case FT_TEXT: /* Unknown text */
4312 case FT_7BIT: /* 7-bit text */
4315 case FT_8BIT: /* 8-bit text */
4318 case FT_UTF8: /* UTF-8 */
4321 case FT_UCS2: /* UCS-2 */
4323 if (o > -1) /* Input file byte order */
4333 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4334 debug(F110,"ftp putfile","initxlate",0);
4336 debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4341 #endif /* NOCSETS */
4343 binary = ftp_typ; /* For file-transfer display */
4346 if (recursive) { /* If sending recursively, */
4347 if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4348 return(-1); /* Don't PUT if it fails. */
4349 else if (isdir(local)) /* It's a directory */
4350 return(0); /* Don't send it! */
4352 if (*remote) { /* If an as-name template was given */
4354 if (cmd_quoting) { /* and COMMAND QUOTING is ON */
4355 y = CKMAXPATH; /* evaluate it for this file */
4357 zzstring(remote,&s,&y);
4360 ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
4361 } else { /* No as-name */
4362 nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
4363 debug(F110,"FTP PUT nzltor",asname,0);
4365 /* Preliminary messages and log entries */
4368 zfnqfp(local,CKMAXPATH,fullname);
4369 if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4370 fullname[CKMAXPATH] = NUL;
4372 if (displa && fdispla) { /* Screen */
4373 ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
4374 ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
4375 ftscreen(SCR_FS,0,fsize,"");
4378 if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
4379 mt = chkmodtime(fullname,asname,0);
4380 debug(F111,"ftp putfile chkmodtime",asname,mt);
4381 if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4382 tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4384 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
4387 } else if (mt == 1) { /* Times are equal */
4388 tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4389 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
4393 /* Local file is newer */
4394 tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4395 "ftp put /update TEXT:", fullname, 0);
4396 } else if (flg & PUT_RES) {
4397 tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4398 "ftp put /recover TEXT:", fullname, 0);
4400 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4403 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4404 #endif /* DOUPDATE */
4405 tlog(F110," as",asname,0);
4409 debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4410 tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4411 tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4412 } else if (!ftp_typ) {
4413 tlog(F110," character sets:","no conversion",0);
4414 fcs = ofcs; /* Binary file but we still must */
4415 rcs = orcs; /* translate its name */
4417 #endif /* NOCSETS */
4421 t0 = gmstimer(); /* Start time */
4422 if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
4423 if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
4424 rc = (mt < 0) ? /* Update mode... */
4425 SKP_XNX : /* Remote file doesn't exist */
4426 SKP_XUP; /* Remote file is older */
4428 rc = SKP_SIM; /* "Would be sent", period. */
4431 rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4433 t1 = gmstimer(); /* End time */
4434 filcnt++; /* File number */
4437 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4438 fpxfsecs = sec; /* (for doxlog()) */
4440 sec = (t1 - t0) / 1000;
4442 #endif /* GFTIMER */
4444 debug(F111,"ftp sendrequest rc",local,rc);
4446 if (cancelfile || cancelgroup) {
4447 debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4448 ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4449 } else if (rc > 0) {
4450 debug(F101,"ftp put skipped",local,rc);
4451 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
4452 } else if (rc < 0) {
4453 debug(F111,"ftp put error",local,ftpcode);
4454 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4456 debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4457 ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4458 debug(F111,"ftp put ST_OK",local,rc);
4459 ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
4460 debug(F110,"ftp put old sfspec",sfspec,0);
4461 makestr(&sfspec,fullname); /* For WHERE command */
4462 debug(F110,"ftp put new sfspec",sfspec,0);
4463 debug(F110,"ftp put old srfspec",srfspec,0);
4464 makestr(&srfspec,asname);
4465 debug(F110,"ftp put new srfspec",srfspec,0);
4468 /* Final log entries */
4474 tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4475 else if (rc == SKP_XUP)
4476 tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4477 else if (rc == SKP_SIM)
4478 tlog(F100," /simulate: WOULD BE SENT","",0);
4480 tlog(F110," skipped:",gskreason(rc),0);
4481 } else if (rc == 0) {
4482 tlog(F101," complete, size", "", fsize);
4483 } else if (cancelfile) {
4484 tlog(F100," canceled by user","",0);
4486 tlog(F110," failed:",ftp_reply_str,0);
4489 doxlog(what,local,fsize,ftp_typ,rc,"");
4493 if (rc < 0) /* PUT did not succeed */
4494 return(-1); /* so done. */
4496 if (flg & PUT_SIM) /* Simulating, skip the rest. */
4500 /* Set permissions too? */
4502 if (prm) { /* Change permissions? */
4503 s = zgperm(local); /* Get perms of local file */
4506 if (x > 3) s += (x - 3);
4508 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4510 ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4511 tlog(F110, x ? " chmod" : " chmod failed",
4521 /* Disposition of source file */
4525 tlog(F110, (x > -1) ?
4526 " deleted" : " failed to delete",
4533 x = zrename(local,mvto);
4534 tlog(F110, (x > -1) ?
4535 " moved source to" : " failed to move source to",
4541 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
4546 int y; /* Pass it thru the evaluator */
4547 extern int cmd_quoting; /* for \v(filename) */
4548 if (cmd_quoting) { /* But only if cmd_quoting is on */
4551 zzstring(rnto,&s,&y);
4557 x = zrename(local,s);
4558 tlog(F110, (x > -1) ?
4559 " renamed source file to" :
4560 " failed to rename source file to",
4566 /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
4570 /* Disposition of destination file */
4572 if (srvrn) { /* /SERVER-RENAME: */
4575 int y; /* Pass it thru the evaluator */
4576 extern int cmd_quoting; /* for \v(filename) */
4577 debug(F111,"ftp putfile srvrn",s,1);
4579 if (cmd_quoting) { /* But only if cmd_quoting is on */
4581 s = (char *)fullname; /* We can recycle this buffer now */
4582 zzstring(srvrn,&s,&y);
4583 s = (char *)fullname;
4586 debug(F111,"ftp putfile srvrn",s,2);
4589 x = ftp_rename(asname,s);
4590 debug(F111,"ftp putfile ftp_rename",asname,x);
4591 tlog(F110, (x > 0) ?
4592 " renamed destination file to" :
4593 " failed to rename destination file to",
4604 /* xxout must only be used for ASCII transfers */
4610 #endif /* CK_ANSIC */
4616 /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4618 if (zzout(dout,(CHAR)'\015') < 0)
4625 if (zzout(dout,(CHAR)'\015') < 0)
4633 if (zzout(dout,(CHAR)'\015') < 0)
4640 if (zzout(dout,(CHAR)c) < 0)
4651 #endif /* CK_ANSIC */
4661 #endif /* CK_ANSIC */
4667 ispathsep(c) int c; {
4668 switch (servertype) {
4672 return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4676 return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4678 return((c == '>') ? 1 : 0);
4680 return((c == '/') ? 1 : 0);
4687 extern int ck_repaint();
4688 #endif /* CK_CURSES */
4693 x = conchk(); /* Any chars waiting at console? */
4694 if (x-- > 0) { /* Yes... */
4695 c = coninc(5); /* Get one */
4697 case 032: /* Ctrl-X or X */
4699 case 'Z': cancelgroup++; /* fall thru on purpose */
4700 case 030: /* Ctrl-Z or Z */
4702 case 'X': cancelfile++; rc++; break;
4706 case 014: /* Ctrl-L or L or Ctrl-W */
4708 ck_repaint(); /* Refresh screen */
4709 #endif /* CK_CURSES */
4712 while (x-- > 0) /* Soak up any rest */
4718 /* fc = 0 for read; 1 for write */
4720 check_data_connection(fd,fc) int fd, fc; {
4723 fd_set in, out, err;
4725 if (ftp_timeout < 1L)
4731 FD_SET(fd,fc ? &out : &in);
4732 tv.tv_sec = ftp_timeout; /* Time limit */
4736 x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
4738 x = select(FD_SETSIZE,&in,&out,&err,&tv);
4739 #endif /* INTSELECT */
4743 errno = EWOULDBLOCK;
4750 #endif /* EWOULDBLOCK */
4751 debug(F100,"ftp check_data_connection TIMOUT","",0);
4756 #endif /* FTP_TIMEOUT */
4758 /* zzsend - used by buffered output macros. */
4762 zzsend(int fd, CHAR c)
4764 zzsend(fd,c) int fd; CHAR c;
4765 #endif /* CK_ANSIC */
4769 debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4770 debug(F101,"zzsend nout","",nout);
4771 debug(F111,"zzsend","secure?",ftpissecure());
4773 if (iscanceled()) /* Check for cancellation */
4778 if (check_data_connection(fd,1) < 0) {
4782 #endif /* FTP_TIMEOUT */
4784 rc = (!ftpissecure()) ?
4785 send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4786 secure_putbuf(fd, ucbuf, nout);
4792 if (rc > -1 && fdispla != XYFD_B) {
4794 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
4799 /* c m d l i n p u t -- Command-line PUT */
4802 cmdlinput(stay) int stay; {
4803 int x, rc = 0, done = 0, good = 0, status = 0;
4804 ULONG t0, t1; /* Times for stats */
4809 #endif /* GFTIMER */
4811 if (quiet) { /* -q really means quiet */
4821 what = W_FTP|W_SEND;
4828 t0 = gmstimer(); /* Record starting time */
4830 while (!done && !cancelgroup) { /* Loop for all files */
4833 x = gnfile(); /* Get next file from list(s) */
4834 if (x == 0) /* (see gnfile() comments...) */
4838 case 1: /* File to send */
4839 rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */
4840 filnam, /* Local file to send */
4841 filnam, /* Remote name for file */
4842 forcetype, /* Text/binary mode forced */
4844 NULL, /* No move-to */
4845 NULL, /* No rename-to */
4846 NULL, /* No server-rename */
4847 ftp_cnv, /* Filename conversion */
4848 0, /* Unique-server-names */
4849 -1, /* All file types */
4850 0, /* No permissions */
4851 -1, /* No character sets */
4852 -1, /* No character sets */
4853 0 /* No update or restart */
4860 continue; /* Or break? */
4865 continue; /* Or break? */
4867 case 0: /* No more files, done */
4873 printf("?%s: file not found - \"%s\"\n",
4874 puterror ? "Fatal" : "Warning",
4877 continue; /* or break? */
4879 printf("?Warning access denied - \"%s\"\n", filnam);
4880 continue; /* or break? */
4882 printf("?Too many files match\n");
4887 printf("?No files selected\n");
4891 printf("?getnextfile() - unknown failure\n");
4898 else if (cancelfile && good < 1)
4904 lastxfer = W_FTP|W_SEND;
4907 t1 = gmstimer(); /* End time */
4909 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4910 if (!sec) sec = 0.001;
4913 sec = (t1 - t0) / 1000;
4915 #endif /* GFTIMER */
4916 tfcps = (long) (tfc / sec);
4918 lastxfer = W_FTP|W_SEND;
4921 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
4923 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4928 /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
4932 doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
4934 doftpput(cx,who) int cx, who;
4935 #endif /* CK_ANSIC */
4937 struct FDB sf, fl, sw, cm;
4938 int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4939 int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4942 int x_csl, x_csr = -1; /* Local and remote charsets */
4945 char c, * p; /* Workers */
4947 int range[2]; /* Array range */
4948 char ** ap = NULL; /* Array pointer */
4949 int arrayx = -1; /* Array index */
4950 #endif /* PUTARRAY */
4951 ULONG t0 = 0L, t1 = 0L; /* Times for stats */
4956 #endif /* GFTIMER */
4958 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
4959 success = 0; /* Assume failure */
4960 forcetype = 0; /* No /TEXT or /BINARY given yet */
4961 out2screen = 0; /* Not outputting file to screen */
4962 putflags = 0; /* PUT options */
4963 x_cnv = ftp_cnv; /* Filename conversion */
4964 x_usn = ftp_usn; /* Unique server names */
4965 x_prm = ftp_prm; /* Permissions */
4966 if (x_prm == SET_AUTO) /* Permissions AUTO */
4970 x_csr = ftp_csr; /* Inherit global server charset */
4975 #endif /* NOCSETS */
4977 makestr(&filefile,NULL); /* No filename list file yet. */
4978 makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
4979 makestr(&snd_rename,NULL); /* PUT /RENAME */
4980 makestr(&snd_move,NULL); /* PUT /MOVE */
4981 putpath[0] = NUL; /* Initialize for syncdir(). */
4982 puterror = ftp_err; /* Inherit global error action. */
4983 what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
4984 asnambuf[0] = NUL; /* Clear as-name buffer */
4986 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
4987 ftp_typ = g_ftp_typ;
4988 /* g_ftp_typ = -1; */
4990 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
4991 pv[i].sval = NULL; /* to null pointers */
4992 pv[i].ival = -1; /* and -1 int values */
4993 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
4995 if (who == 0) { /* Called with unprefixed command */
4997 case XXRSEN: pv[SND_RES].ival = 1; break;
4998 case XXCSEN: pv[SND_CMD].ival = 1; break;
4999 case XXMOVE: pv[SND_DEL].ival = 1; break;
5000 case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
5001 case XXMSE: mput++; break;
5005 pv[SND_RES].ival = 1;
5009 cmfdbi(&sw, /* First FDB - command switches */
5011 "Filename, or switch", /* hlpmsg */
5013 "", /* addtl string data */
5014 nputswi, /* addtl numeric data 1: tbl size */
5015 4, /* addtl numeric data 2: 4 = cmswi */
5016 xxstring, /* Processing function */
5017 putswi, /* Keyword table */
5018 &sf /* Pointer to next FDB */
5020 cmfdbi(&fl, /* 3rd FDB - local filespec */
5024 "", /* addtl string data */
5025 0, /* addtl numeric data 1 */
5026 0, /* addtl numeric data 2 */
5031 cmfdbi(&cm, /* 4th FDB - Confirmation */
5035 "", /* addtl string data */
5036 0, /* addtl numeric data 1 */
5037 0, /* addtl numeric data 2 */
5044 cmfdbi(&sf, /* 2nd FDB - file to send */
5048 "", /* addtl string data */
5049 /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
5050 nolinks | x_recurse, /* addtl numeric data 1 */
5051 0, /* dirflg 0 means "not dirs only" */
5058 #endif /* COMMENT */
5061 while (1) { /* Parse zero or more switches */
5062 x = cmfdb(&sw); /* Parse something */
5063 debug(F101,"ftp put cmfdb A","",x);
5064 debug(F101,"ftp put fcode A","",cmresult.fcode);
5065 if (x < 0) /* Error */
5066 goto xputx; /* or reparse needed */
5067 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
5069 c = cmgbrk(); /* Get break character */
5070 getval = (c == ':' || c == '='); /* to see how they ended the switch */
5071 if (getval && !(cmresult.kflags & CM_ARG)) {
5072 printf("?This switch does not take arguments\n");
5076 if (!getval && (cmgkwflgs() & CM_ARG)) {
5077 printf("?This switch requires an argument\n");
5081 n = cmresult.nresult; /* Numeric result = switch value */
5082 debug(F101,"ftp put switch","",n);
5084 switch (n) { /* Process the switch */
5085 case SND_AFT: /* Send /AFTER:date-time */
5086 case SND_BEF: /* Send /BEFORE:date-time */
5087 case SND_NAF: /* Send /NOT-AFTER:date-time */
5088 case SND_NBE: /* Send /NOT-BEFORE:date-time */
5090 if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
5092 printf("?Date-time required\n");
5098 makestr(&(pv[n].sval),s);
5101 case SND_ASN: /* /AS-NAME: */
5102 debug(F101,"ftp put /as-name getval","",getval);
5104 if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
5106 printf("?name required\n");
5111 makestr(&(pv[n].sval),brstrip(s));
5112 debug(F110,"ftp put /as-name 1",pv[n].sval,0);
5113 if (pv[n].sval) pv[n].ival = 1;
5117 case SND_ARR: /* /ARRAY */
5120 if ((x = cmfld("Array name (a single letter will do)",
5130 if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
5131 printf("?Bad array: %s\n",s);
5134 if (!(ap = a_ptr[x])) {
5135 printf("?No such array: %s\n",s);
5139 pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
5140 pv[SND_RES].ival = 0;
5141 pv[SND_FIL].ival = 0;
5144 #endif /* PUTARRAY */
5146 case SND_BIN: /* /BINARY */
5147 case SND_TXT: /* /TEXT or /ASCII */
5148 case SND_TEN: /* /TENEX */
5149 pv[SND_BIN].ival = 0;
5150 pv[SND_TXT].ival = 0;
5151 pv[SND_TEN].ival = 0;
5156 case SND_CMD: /* These take no args */
5158 printf("?Sorry, system command access is disabled\n");
5163 else if (sndfilter) {
5164 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
5168 #endif /* PIPESEND */
5169 sw.hlpmsg = "Command, or switch"; /* Change help message */
5170 pv[n].ival = 1; /* Just set the flag */
5171 pv[SND_ARR].ival = 0;
5173 #endif /* PUTPIPE */
5178 goto again; /* Because CMIFI params changed... */
5182 #endif /* CKSYMLINK */
5185 case SND_RES: /* /RECOVER (resend) */
5186 pv[SND_ARR].ival = 0; /* fall thru on purpose... */
5187 #endif /* FTP_RESTART */
5190 case SND_DEL: /* /DELETE */
5191 case SND_SHH: /* /QUIET */
5192 case SND_UPD: /* /UPDATE */
5193 case SND_SIM: /* /UPDATE */
5194 case SND_USN: /* /UNIQUE */
5195 pv[n].ival = 1; /* Just set the flag */
5198 case SND_REC: /* /RECURSIVE */
5199 recursive = 2; /* Must be set before cmifi() */
5201 goto again; /* Because CMIFI params changed... */
5205 case SND_DOT: /* /DOTFILES */
5208 case SND_NOD: /* /NODOTFILES */
5211 #endif /* UNIXOROSK */
5213 case SND_ERR: /* /ERROR-ACTION */
5214 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
5219 case SND_EXC: /* Excludes */
5221 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5223 printf("?Pattern required\n");
5228 if (s) if (!*s) s = NULL;
5229 makestr(&(pv[n].sval),s);
5234 case SND_PRM: /* /PERMISSIONS */
5237 else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5239 pv[SND_PRM].ival = x;
5243 case SND_FLT: /* /FILTER */
5244 debug(F101,"ftp put /filter getval","",getval);
5246 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
5252 if (*s) s = brstrip(s);
5254 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
5255 if (s[x] != '\\') continue;
5256 if (s[x+1] == 'v') break;
5260 "?Filter must contain a replacement variable for filename.\n"
5265 if (s) if (!*s) s = NULL;
5266 makestr(&(pv[n].sval),s);
5270 #endif /* PIPESEND */
5272 case SND_NAM: /* /FILENAMES */
5274 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
5276 debug(F101,"ftp put /filenames","",x);
5280 case SND_SMA: /* Smaller / larger than */
5284 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
5289 case SND_FIL: /* Name of file containing filenames */
5291 if ((x = cmifi("Name of file containing list of filenames",
5292 "",&s,&y,xxstring)) < 0) {
5294 printf("?Filename required\n");
5298 } else if (y && iswild(s)) {
5299 printf("?Wildcards not allowed\n");
5303 if (s) if (!*s) s = NULL;
5304 makestr(&(pv[n].sval),s);
5307 pv[SND_ARR].ival = 0;
5314 case SND_MOV: /* MOVE after */
5315 case SND_REN: /* RENAME after */
5316 case SND_SRN: { /* SERVER-RENAME after */
5320 m = "device and/or directory for source file after sending";
5323 m = "new name for source file after sending";
5326 m = "new name for destination file after sending";
5330 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5332 printf("%s\n", n == SND_MOV ?
5333 "?Destination required" :
5334 "?New name required"
5340 if (s) if (!*s) s = NULL;
5341 makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5342 pv[n].ival = (pv[n].sval) ? 1 : 0;
5345 case SND_STA: /* Starting position (= PSEND) */
5347 if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5352 case SND_TYP: /* /TYPE */
5354 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5356 pv[n].ival = (x == 2) ? -1 : x;
5360 case SND_CSL: /* Local character set */
5361 case SND_CSR: /* Remote (server) charset */
5362 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5363 return((x == -3) ? -2 : x);
5369 x_xla = 1; /* Overrides global OFF setting */
5372 case SND_XPA: /* Transparent */
5377 #endif /* NOCSETS */
5381 if (pv[SND_RES].ival > 0) { /* /RECOVER */
5382 if (sndfilter || pv[SND_FLT].ival > 0) {
5383 printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5387 if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5388 printf("WARNING: Server says it doesn't support REST.\n");
5390 #endif /* PIPESEND */
5398 switch (cmresult.fcode) { /* How did we get out of switch loop */
5399 case _CMIFI: /* Input filename */
5400 if (pv[SND_FIL].ival > 0) {
5401 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5405 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5406 if (pv[SND_ARR].ival > 0)
5407 ckstrncpy(asnambuf,line,CKMAXPATH);
5409 wild = cmresult.nresult; /* Wild flag */
5410 debug(F111,"ftp put wild",line,wild);
5411 if (!wild && !recursive && !mput)
5414 case _CMFLD: /* Field */
5415 /* Only allowed with /COMMAND and /ARRAY */
5416 if (pv[SND_FIL].ival > 0) {
5417 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5421 /* For MPUT it's OK to have filespecs that don't match any files */
5424 if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5427 printf("?Off limits: %s\n",cmresult.sresult);
5430 printf("?%s - \"%s\"\n",
5431 iswild(cmresult.sresult) ?
5432 "No files match" : "File not found",
5438 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5439 if (pv[SND_ARR].ival > 0)
5440 ckstrncpy(asnambuf,line,CKMAXPATH);
5442 case _CMCFM: /* Confirmation */
5446 printf("?Unexpected function code: %d\n",cmresult.fcode);
5450 debug(F110,"ftp put string",s,0);
5451 debug(F101,"ftp put confirmed","",confirmed);
5453 /* Save and change protocol and transfer mode */
5454 /* Global values are restored in main parse loop */
5459 g_skipbup = skipbup;
5461 if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
5462 g_skipbup = skipbup;
5465 if (pv[SND_TYP].ival > -1) { /* /TYPE */
5466 xfiletype = pv[SND_TYP].ival;
5470 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
5471 forcetype = 1; /* So skip file scan */
5472 ftp_typ = FTT_BIN; /* Set binary */
5473 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
5476 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
5479 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
5486 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
5487 debug(F110,"PUT /COMMAND before stripping",s,0);
5489 debug(F110,"PUT /COMMAND after stripping",s,0);
5491 printf("?Sorry, a command to send from is required\n");
5497 #endif /* PIPESEND */
5499 /* Set up /MOVE and /RENAME */
5501 if (pv[SND_DEL].ival > 0 &&
5502 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5503 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5508 if (pv[SND_MOV].ival > 0) {
5510 char * p = pv[SND_MOV].sval;
5512 if (!isdir(p)) { /* Check directory */
5515 s = (char *)malloc(len + 4);
5517 strcpy(s,p); /* safe */
5519 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5521 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5522 #endif /* datageneral */
5529 #endif /* NOMKDIR */
5532 printf("?Can't create \"%s\"\n",p);
5538 printf("?Directory \"%s\" not found\n",p);
5541 #endif /* CK_MKDIR */
5543 makestr(&snd_move,p);
5545 #endif /* CK_TMPDIR */
5547 if (pv[SND_REN].ival > 0) { /* /RENAME */
5548 char * p = pv[SND_REN].sval;
5551 printf("?New name required for /RENAME\n");
5557 /* If name given is wild, rename string must contain variables */
5562 if (!strcmp(tmpbuf,p)) {
5564 "?/RENAME for file group must contain variables such as \\v(filename)\n"
5571 makestr(&snd_rename,p);
5572 debug(F110,"FTP snd_rename",snd_rename,0);
5574 if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
5575 char * p = pv[SND_SRN].sval;
5578 printf("?New name required for /SERVER-RENAME\n");
5588 if (!strcmp(tmpbuf,p)) {
5590 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5597 makestr(&srv_renam,p);
5598 debug(F110,"ftp put srv_renam",srv_renam,0);
5600 if (!confirmed) { /* CR not typed yet, get more fields */
5602 if (mput) { /* MPUT or MMOVE */
5603 nfils = 0; /* We already have the first one */
5605 if (cmresult.fcode == _CMIFI) {
5606 /* First filespec is valid */
5607 msfiles[nfils++] = line; /* Store pointer */
5608 lp = line + (int)strlen(line) + 1; /* Point past it */
5609 debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5611 /* First filespec matches no files */
5612 debug(F110,"ftp put mput skipping first filespec",
5618 /* Parse a filespec, a "field", or confirmation */
5620 cmfdbi(&sf, /* 1st FDB - file to send */
5624 "", /* addtl string data */
5625 nolinks | x_recurse, /* addtl numeric data 1 */
5626 0, /* dirflg 0 means "not dirs only" */
5631 cmfdbi(&fl, /* 2nd FDB - local filespec */
5635 "", /* addtl string data */
5636 0, /* addtl numeric data 1 */
5637 0, /* addtl numeric data 2 */
5642 cmfdbi(&cm, /* 3rd FDB - Confirmation */
5654 while (!confirmed) { /* Get more filenames */
5655 x = cmfdb(&sf); /* Parse something */
5656 debug(F101,"ftp put cmfdb B","",x);
5657 debug(F101,"ftp put fcode B","",cmresult.fcode);
5658 if (x < 0) /* Error */
5659 goto xputx; /* or reparse needed */
5660 switch (cmresult.fcode) {
5661 case _CMCFM: /* End of command */
5664 debug(F100,"ftp put mput no files match","",0);
5665 printf("?No files match MPUT list\n");
5670 case _CMFLD: /* No match */
5671 debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5673 case _CMIFI: /* Good match */
5674 s = cmresult.sresult;
5675 msfiles[nfils++] = lp; /* Got one, count, point to it, */
5676 p = lp; /* remember pointer, */
5677 while ((*lp++ = *s++)) /* and copy it into buffer */
5678 if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5679 printf("?MPUT list too long\n");
5684 debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5685 if (nfils == 1) /* Take care of \v(filespec) */
5688 zfnqfp(p,TMPBUFSIZ,tmpbuf);
5691 if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5692 strcat(fspec,p); /* safe */
5693 strcat(fspec," "); /* safe */
5696 printf("WARNING - \\v(filespec) buffer overflow\n");
5698 debug(F101,"doxput filespec buffer overflow","",0);
5699 #endif /* COMMENT */
5703 #endif /* NOMSEND */
5704 } else { /* Regular PUT */
5706 if ((x = cmtxt(wild ?
5707 "\nOptional as-name template containing replacement variables \
5708 like \\v(filename)" :
5709 "Optional name to send it with",
5713 if (p) if (!*p) p = NULL;
5717 makestr(&(pv[SND_ASN].sval),p);
5718 if (pv[SND_ASN].sval)
5719 pv[SND_ASN].ival = 1;
5720 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5724 /* Set cmarg2 from as-name, however we got it. */
5727 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5729 p = brstrip(pv[SND_ASN].sval);
5730 ckstrncpy(asnambuf,p,CKMAXPATH+1);
5732 debug(F110,"ftp put asnambuf",asnambuf,0);
5734 if (pv[SND_FIL].ival > 0) {
5736 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5737 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5738 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5742 makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5743 debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5747 if (confirmed && !line[0] && !filefile) {
5749 if (filehead) { /* OK if we have a SEND-LIST */
5750 nfils = filesinlist;
5751 sndsrc = nfils; /* Like MSEND */
5752 addlist = 1; /* But using a different list... */
5753 filenext = filehead;
5756 #endif /* NOMSEND */
5757 printf("?Filename required but not given\n");
5762 addlist = 0; /* Don't use SEND-LIST. */
5763 #endif /* NOMSEND */
5765 if (mput) { /* MPUT (rather than PUT) */
5767 cmlist = msfiles; /* List of filespecs */
5768 sndsrc = nfils; /* rather filespec and as-name */
5769 #endif /* NOMSEND */
5771 } else if (filefile) { /* File contains list of filenames */
5778 } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5780 /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5781 nfils = sndsrc = -1;
5784 printf("?Read access denied - \"%s\"\n", s);
5789 if (s != line) /* We might already have done this. */
5790 ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
5793 debug(F110,"doxput line=s",line,0);
5795 cmarg = line; /* File to send */
5798 zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
5799 #endif /* NOMSEND */
5801 if (!mput) { /* For all but MPUT... */
5803 if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
5805 debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5806 if (pipesend && filefile) {
5807 printf("?Invalid switch combination\n");
5811 #endif /* PIPESEND */
5814 /* If as-name given and filespec is wild, as-name must contain variables */
5815 if ((wild || mput) && asnambuf[0]) {
5818 zzstring(asnambuf,&s,&x);
5819 if (!strcmp(tmpbuf,asnambuf)) {
5821 "?As-name for file group must contain variables such as \\v(filename)\n"
5832 if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
5834 debug(F101,"ftp put display","",fdispla);
5841 #ifdef PUTARRAY /* SEND /ARRAY... */
5842 if (pv[SND_ARR].ival > 0) {
5843 if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5844 if (range[0] == -1) /* If low end of range not specified */
5845 range[0] = 1; /* default to 1 */
5846 if (range[1] == -1) /* If high not specified */
5847 range[1] = a_dim[arrayx]; /* default to size of array */
5848 if ((range[0] < 0) || /* Check range */
5849 (range[0] > a_dim[arrayx]) ||
5850 (range[1] < range[0]) ||
5851 (range[1] > a_dim[arrayx])) {
5852 printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5856 sndarray = ap; /* Array pointer */
5857 sndxin = arrayx; /* Array index */
5858 sndxlo = range[0]; /* Array range */
5860 sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5862 ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5865 #endif /* PUTARRAY */
5869 if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
5870 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
5872 if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
5873 ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5874 if (pv[SND_BEF].ival > 0)
5875 ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5876 if (pv[SND_NAF].ival > 0)
5877 ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5878 if (pv[SND_NBE].ival > 0)
5879 ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5880 if (pv[SND_EXC].ival > 0)
5881 makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5882 if (pv[SND_SMA].ival > -1)
5883 sndsmaller = pv[SND_SMA].wval;
5884 if (pv[SND_LAR].ival > -1)
5885 sndlarger = pv[SND_LAR].wval;
5886 if (pv[SND_NAM].ival > -1)
5887 x_cnv = pv[SND_NAM].ival;
5888 if (pv[SND_USN].ival > -1)
5889 x_usn = pv[SND_USN].ival;
5890 if (pv[SND_ERR].ival > -1)
5891 puterror = pv[SND_ERR].ival;
5894 if (pv[SND_UPD].ival > 0) {
5896 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5900 putflags |= PUT_UPD;
5904 /* This works but it's useless, maybe dangerous */
5905 if (pv[SND_DIF].ival > 0) {
5907 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5911 putflags |= PUT_DIF;
5914 #endif /* COMMENT */
5915 #endif /* DOUPDATE */
5917 if (pv[SND_SIM].ival > 0)
5918 putflags |= PUT_SIM;
5920 if (pv[SND_PRM].ival > -1) {
5923 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5927 x_prm = pv[SND_PRM].ival;
5929 printf("?/PERMISSIONS switch is not supported\n");
5933 if (pv[SND_RES].ival > 0) {
5935 printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5939 if (x_usn || putflags) {
5940 printf("?Conflicting switches: /RECOVER %s\n",
5941 x_usn && putflags ? "/UNIQUE /UPDATE" :
5942 (x_usn ? "/UNIQUE" : "/UPDATE")
5949 (x_csl == FC_UCS2 ||
5952 x_csr == FC_UTF8)) {
5953 printf("?/RECOVER can not be used with Unicode translation\n");
5957 #endif /* NOCSETS */
5960 #endif /* FTP_RESTART */
5962 debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5963 debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5966 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
5967 if (!pv[SND_FLT].sval) {
5970 sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5971 if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5973 debug(F110,"ftp put /FILTER", sndfilter, 0);
5975 if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
5976 if (putflags) /* with pipes or filters */
5978 #endif /* PIPESEND */
5980 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
5985 if (wild) /* (is this necessary?) */
5988 t0 = gmstimer(); /* Record starting time */
5990 done = 0; /* Loop control */
5995 while (!done && !cancelgroup) { /* Loop for all files */
5996 /* or until canceled. */
5999 If we are using a proxy, we don't use the local file list;
6000 instead we use the list on the remote machine which we want
6001 sent to someone else, and we use remglob() to get the names.
6002 But in that case we shouldn't even be executing this routine;
6005 #endif /* FTP_PROXY */
6008 x = gnfile(); /* Get next file from list(s) */
6010 if (x == 0) /* (see gnfile() comments...) */
6012 debug(F111,"FTP PUT gnfile",filnam,x);
6013 debug(F111,"FTP PUT binary",filnam,binary);
6016 case 1: /* File to send */
6019 if (asnambuf[0]) { /* As-name */
6020 int n; char *p; /* to be evaluated... */
6023 zzstring(asnambuf,&p,&n);
6025 debug(F110,"ftp put asname",s2,0);
6028 rc = putfile(cx, /* Function (PUT, APPEND) */
6029 filnam, s2, /* Name to send, as-name */
6030 forcetype, moving, /* Parameters from switches... */
6031 snd_move, snd_rename, srv_renam,
6032 x_cnv, x_usn, xfiletype, x_prm,
6034 x_csl, (!x_xla ? -1 : x_csr),
6037 #endif /* NOCSETS */
6040 debug(F111,"ftp put putfile rc",filnam,rc);
6041 debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
6042 debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
6053 printf("?Fatal upload error: %s\n",filnam);
6058 case 0: /* No more files, done */
6062 printf("?%s: file not found - \"%s\"\n",
6063 puterror ? "Fatal" : "Warning",
6074 printf("?Fatal: file not found - \"%s\"\n", filnam);
6079 continue; /* Not readable, keep going */
6082 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
6087 printf("?Warning access denied - \"%s\"\n", filnam);
6090 case -4: /* Canceled */
6093 #endif /* COMMENT */
6095 printf("?Too many files match\n");
6100 printf("?No files selected\n");
6104 printf("?getnextfile() - unknown failure\n");
6112 } else if (!doftpcdup())
6119 else if (cancelfile && good < 1)
6128 t1 = gmstimer(); /* End time */
6129 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6130 if (!sec) sec = 0.001;
6133 sec = (t1 - t0) / 1000;
6135 #endif /* GFTIMER */
6136 tfcps = (long) (tfc / sec);
6138 lastxfer = W_FTP|W_SEND;
6141 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6143 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
6147 ftreset(); /* Undo switch effects */
6153 static char ** mgetlist = NULL; /* For MGET */
6154 static int mgetn = 0, mgetx = 0;
6155 static char xtmpbuf[4096];
6160 Get files specified by -g command-line option.
6161 File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
6164 cmdlinget(stay) int stay; {
6165 int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
6166 int lcs = -1, rcs = -1, xlate = 0;
6170 char * s, * s2, * s3;
6171 ULONG t0, t1; /* Times for stats */
6176 #endif /* GFTIMER */
6178 if (quiet) { /* -q really means quiet */
6188 what = W_FTP|W_RECV;
6193 havesize = (CK_OFF_T)-1;
6194 makestr(&havemdtm,NULL);
6202 debug(F101,"ftp cmdlinget nfils","",nfils);
6204 if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
6205 if (alike) { /* If server & client are alike */
6206 nc = 0; /* no conversion */
6207 } else { /* If they are different */
6208 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6209 nc = -1; /* only minimal conversions needed */
6210 else /* otherwise */
6211 nc = 1; /* full conversion */
6213 } else /* Not auto - do what user said */
6217 doexit(BAD_EXIT,-1);
6219 t0 = gmstimer(); /* Starting time for this batch */
6222 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
6223 lcs = ftp_csl; /* Local charset */
6224 if (lcs < 0) lcs = fcharset;
6225 if (lcs < 0) xlate = 0;
6227 if (xlate) { /* Still ON? */
6228 rcs = ftp_csx; /* Remote (Server) charset */
6229 if (rcs < 0) rcs = ftp_csr;
6230 if (rcs < 0) xlate = 0;
6232 #endif /* NOCSETS */
6234 If we have only one file and it is a directory, then we ask for a
6235 listing of its contents, rather than retrieving the directory file
6236 itself. This is what (e.g.) Netscape does.
6239 if (doftpcwd((char *)cmlist[mgetx],-1)) {
6240 /* If we can CD to it, it must be a directory */
6242 cmlist[mgetx] = "*";
6245 (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
6251 The following is to work around UNIX servers which, when given a command
6252 like "NLST path/blah" (not wild) returns the basename without the path.
6254 if (!done && servertype == SYS_UNIX && nfils == 1) {
6255 mget = iswild(cmlist[mgetx]);
6257 if (!mget && !done) { /* Invoked by command-line FTP URL */
6259 printf("DOING GET...\n");
6261 cancelfile = 0; /* This file not canceled yet */
6263 rc = 0; /* Initial return code */
6264 fsize = (CK_OFF_T)-1;
6266 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
6267 if (x == REPLY_COMPLETE)
6268 fsize = ckatofs(&ftp_reply_str[4]);
6270 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6271 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6273 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6276 /* If local file already exists, take collision action */
6278 if (zchki(s2) > -1) {
6280 case XYFX_A: /* Append */
6283 case XYFX_R: /* Rename */
6284 case XYFX_B: { /* Backup */
6287 znewn(s2,&p); /* Make unique name */
6288 debug(F110,"ftp cmdlinget znewn",p,0);
6289 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6291 debug(F111,"ftp cmdlinget backup zrename",p,x);
6292 } else { /* Rename incoming file */
6293 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6295 debug(F111,"ftp cmdlinget rename incoming",p,x);
6298 printf("?Backup/Rename failed\n");
6299 return(success = 0);
6303 case XYFX_D: /* Discard */
6304 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6305 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6306 tlog(F100," refused: name","",0);
6307 debug(F110,"ftp cmdlinget skip name",s2,0);
6310 case XYFX_X: /* Overwrite */
6311 case XYFX_U: /* Update (already handled above) */
6312 case XYFX_M: /* ditto */
6316 rc = getfile(s, /* Remote name */
6317 s2, /* Local name */
6318 0, /* Recover/Restart */
6319 append, /* Append */
6320 NULL, /* Pipename */
6321 0, /* Translate charsets */
6322 -1, /* File charset (none) */
6323 -1 /* Server charset (none) */
6325 debug(F111,"ftp cmdlinget rc",s,rc);
6326 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6327 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6329 if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6330 rc = getfile(&s[1], /* Remote name without leading '/' */
6331 s2, /* Local name */
6332 0, /* Recover/Restart */
6333 append, /* Append */
6334 NULL, /* Pipename */
6335 0, /* Translate charsets */
6336 -1, /* File charset (none) */
6337 -1 /* Server charset (none) */
6350 #endif /* FTP_TIMEOUT */
6357 if (ftp_deb && !done)
6358 printf("DOING MGET...\n");
6359 while (!done && !cancelgroup) {
6360 cancelfile = 0; /* This file not canceled yet */
6361 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6367 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6370 debug(F111,"ftp cmdlinget remote_files B",s,0);
6377 The semantics of NLST are ill-defined. Suppose we have just sent
6378 NLST /path/[a-z]*. Most servers send back names like /path/foo,
6379 /path/bar, etc. But some send back only foo and bar, and subsequent
6380 RETR commands based on the pathless names are not going to work.
6382 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6383 if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6384 int len, left = 4096;
6385 char * tmp = xtmpbuf;
6386 len = s3 - cmlist[mgetx] + 1;
6387 ckstrncpy(tmp,cmlist[mgetx],left);
6390 ckstrncpy(tmp,s,left);
6392 debug(F111,"ftp cmdlinget remote_files X",s,0);
6395 first = 0; /* Not first any more */
6397 debug(F111,"ftp cmdlinget havetype",s,havetype);
6398 if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6399 debug(F110,"ftp cmdlinget not-a-file",s,0);
6402 rc = 0; /* Initial return code */
6403 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
6405 } else { /* No - must ask server */
6407 Prior to sending the NLST command we necessarily put the
6408 server into ASCII mode. We must now put it back into the
6409 the requested mode so the upcoming SIZE command returns
6410 right kind of size; this is especially important for
6411 GET /RECOVER; otherwise the server returns the "ASCII" size
6412 of the file, rather than its true size.
6414 changetype(ftp_typ,0); /* Change to requested type */
6415 fsize = (CK_OFF_T)-1;
6417 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6418 if (x == REPLY_COMPLETE)
6419 fsize = ckatofs(&ftp_reply_str[4]);
6422 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6423 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6425 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6428 /* If local file already exists, take collision action */
6430 if (zchki(s2) > -1) {
6432 case XYFX_A: /* Append */
6435 case XYFX_R: /* Rename */
6436 case XYFX_B: { /* Backup */
6439 znewn(s2,&p); /* Make unique name */
6440 debug(F110,"ftp cmdlinget znewn",p,0);
6441 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6443 debug(F111,"ftp cmdlinget backup zrename",p,x);
6444 } else { /* Rename incoming file */
6445 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6447 debug(F111,"ftp cmdlinget rename incoming",p,x);
6450 printf("?Backup/Rename failed\n");
6451 return(success = 0);
6455 case XYFX_D: /* Discard */
6456 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6457 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6458 tlog(F100," refused: name","",0);
6459 debug(F110,"ftp cmdlinget skip name",s2,0);
6461 case XYFX_X: /* Overwrite */
6462 case XYFX_U: /* Update (already handled above) */
6463 case XYFX_M: /* ditto */
6467 /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6468 rc = getfile(s, /* Remote name */
6469 s2, /* Local name */
6470 0, /* Recover/Restart */
6471 append, /* Append */
6472 NULL, /* Pipename */
6473 0, /* Translate charsets */
6474 -1, /* File charset (none) */
6475 -1 /* Server charset (none) */
6477 debug(F111,"ftp cmdlinget rc",s,rc);
6478 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6479 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6492 #endif /* FTP_TIMEOUT */
6506 else if (cancelfile && good < 1)
6512 t1 = gmstimer(); /* End time */
6513 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6514 if (!sec) sec = 0.001;
6517 sec = (t1 - t0) / 1000;
6519 #endif /* GFTIMER */
6521 tfcps = (long) (tfc / sec);
6523 lastxfer = W_FTP|W_RECV;
6526 ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6528 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6532 /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
6535 Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6536 zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
6537 the user-interface perspective, since the server's directory listings show
6538 its own local times and since we don't know what timezone it's in, there's
6539 no way to reconcile our local times with the server's.
6542 doftpget(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
6543 struct FDB fl, sw, cm;
6544 int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6545 int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6546 int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6547 int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6548 int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6551 CK_OFF_T getlarger = (CK_OFF_T)-1;
6552 CK_OFF_T getsmaller = (CK_OFF_T)-1;
6553 char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6554 char * src = "", * local = "";
6557 int x_csl = -1, x_csr = -1; /* Local and remote charsets */
6559 char c; /* Worker char */
6560 ULONG t0 = 0L, t1; /* Times for stats */
6565 #endif /* GFTIMER */
6567 struct stringint pv[SND_MAX+1]; /* Temporary array for switch values */
6569 success = 0; /* Assume failure */
6570 forcetype = 0; /* No /TEXT or /BINARY given yet */
6571 restart = 0; /* No restart yet */
6572 out2screen = 0; /* No TO-SCREEN switch given yet */
6573 mgetmethod = 0; /* No NLST or MLSD switch yet */
6580 x_cnv = ftp_cnv; /* Filename conversion */
6581 if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
6582 if (alike) { /* If server & client are alike */
6583 x_cnv = 0; /* no conversion */
6584 } else { /* If they are different */
6585 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6586 x_cnv = -1; /* only minimal conversions needed */
6587 else /* otherwise */
6588 x_cnv = 1; /* full conversion */
6590 } else /* Not auto - do what user said */
6593 x_prm = ftp_prm; /* Permissions */
6594 if (x_prm == SET_AUTO) /* Permissions AUTO */
6598 x_csr = ftp_csr; /* Inherit global server charset */
6599 x_csl = ftp_csl; /* Inherit global local charset */
6600 if (x_csl < 0) /* If none, use current */
6601 x_csl = fcharset; /* file character-set. */
6602 x_xla = ftp_xla; /* Translation On/Off */
6603 #endif /* NOCSETS */
6605 geterror = ftp_err; /* Inherit global error action. */
6606 asnambuf[0] = NUL; /* No as-name yet. */
6607 pipesave = pipesend;
6611 havesize = (CK_OFF_T)-1;
6612 makestr(&havemdtm,NULL);
6614 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
6615 ftp_typ = g_ftp_typ;
6616 /* g_ftp_typ = -1; */
6618 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
6619 pv[i].sval = NULL; /* to null pointers */
6620 pv[i].ival = -1; /* and -1 int values */
6621 pv[i].wval = (CK_OFF_T)-1; /* and -1 wide values */
6623 zclose(ZMFILE); /* In case it was left open */
6625 x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6627 if (fp_nml) { /* Reset /NAMELIST */
6628 if (fp_nml != stdout)
6632 makestr(&ftp_nml,NULL);
6634 /* Initialize list of remote filespecs */
6637 mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6639 printf("?Memory allocation failure - MGET list\n");
6642 for (i = 0; i < MGETMAX; i++)
6645 mgetn = 0; /* Number of mget arguments */
6646 mgetx = 0; /* Current arg */
6648 if (who == 0) { /* Called with unprefixed command */
6649 if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6652 case XXREGET: pv[SND_RES].ival = 1; break;
6653 case XXRETR: pv[SND_DEL].ival = 1; break;
6655 case XXMGET: mget++; break;
6657 } else { /* FTP command */
6658 if (cx == FTP_GET || cx == FTP_RGE)
6661 case FTP_DEL: /* (fall thru on purpose) */
6662 case FTP_MDE: mdel++; /* (ditto) */
6663 case FTP_GET: /* (ditto) */
6664 case FTP_MGE: mget++; break;
6665 case FTP_RGE: pv[SND_RES].ival = 1; break;
6668 cmfdbi(&sw, /* First FDB - command switches */
6670 "Remote filename;\n or switch", /* hlpmsg */
6672 "", /* addtl string data */
6673 mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
6674 4, /* addtl numeric data 2: 4 = cmswi */
6675 xxstring, /* Processing function */
6676 mdel ? delswi : getswi, /* Keyword table */
6677 &fl /* Pointer to next FDB */
6679 cmfdbi(&fl, /* 2nd FDB - remote filename */
6683 "", /* addtl string data */
6684 0, /* addtl numeric data 1 */
6685 0, /* addtl numeric data 2 */
6690 cmfdbi(&cm, /* 3rd FDB - Confirmation */
6694 "", /* addtl string data */
6695 0, /* addtl numeric data 1 */
6696 0, /* addtl numeric data 2 */
6702 while (1) { /* Parse 0 or more switches */
6703 x = cmfdb(&sw); /* Parse something */
6704 debug(F101,"ftp get cmfdb","",x);
6705 if (x < 0) /* Error */
6706 goto xgetx; /* or reparse needed */
6707 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
6709 c = cmgbrk(); /* Get break character */
6710 getval = (c == ':' || c == '='); /* to see how they ended the switch */
6711 if (getval && !(cmresult.kflags & CM_ARG)) {
6712 printf("?This switch does not take arguments\n");
6716 n = cmresult.nresult; /* Numeric result = switch value */
6717 debug(F101,"ftp get switch","",n);
6719 if (!getval && (cmgkwflgs() & CM_ARG)) {
6720 printf("?This switch requires an argument\n");
6724 switch (n) { /* Process the switch */
6725 case SND_ASN: /* /AS-NAME: */
6726 debug(F101,"ftp get /as-name getval","",getval);
6728 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6730 printf("?name required\n");
6737 makestr(&(pv[n].sval),s);
6741 case SND_BIN: /* /BINARY */
6742 case SND_TXT: /* /TEXT or /ASCII */
6743 case SND_TEN: /* /TENEX */
6744 pv[SND_BIN].ival = 0;
6745 pv[SND_TXT].ival = 0;
6746 pv[SND_TEN].ival = 0;
6751 case SND_CMD: /* These take no args */
6753 printf("?Sorry, system command access is disabled\n");
6758 else if (rcvfilter) {
6759 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6763 #endif /* PIPESEND */
6764 sw.hlpmsg = "Command, or switch"; /* Change help message */
6765 pv[n].ival = 1; /* Just set the flag */
6766 pv[SND_ARR].ival = 0;
6768 #endif /* PUTPIPE */
6770 case SND_SHH: /* /QUIET */
6771 case SND_RES: /* /RECOVER (reget) */
6772 case SND_NOB: /* /NOBACKUPFILES */
6773 case SND_DEL: /* /DELETE */
6774 case SND_UPD: /* /UPDATE */
6775 case SND_USN: /* /UNIQUE */
6776 case SND_NOD: /* /NODOTFILES */
6777 case SND_REC: /* /RECOVER */
6778 case SND_MAI: /* /TO-SCREEN */
6779 pv[n].ival = 1; /* Just set the flag */
6782 case SND_DIF: /* /DATES-DIFFER */
6783 pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
6787 case SND_COL: /* /COLLISION: */
6788 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6791 pv[SND_DIF].ival = 1; /* (phase this out) */
6792 pv[n].ival = x; /* this should be sufficient */
6795 case SND_ERR: /* /ERROR-ACTION */
6796 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6801 case SND_EXC: /* Exception list */
6803 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6805 printf("?Pattern required\n");
6810 if (s) if (!*s) s = NULL;
6811 makestr(&(pv[n].sval),s);
6818 debug(F101,"ftp get /filter getval","",getval);
6820 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6827 if (pv[SND_MAI].ival < 1) {
6829 /* Make sure they included "\v(...)" */
6830 for (x = 0; x < y; x++) {
6831 if (s[x] != '\\') continue;
6832 if (s[x+1] == 'v') break;
6836 "?Filter must contain a replacement variable for filename.\n"
6844 makestr(&(pv[n].sval),s);
6847 makestr(&(pv[n].sval),NULL);
6850 #endif /* PIPESEND */
6854 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6856 debug(F101,"ftp get /filenames","",x);
6860 case SND_SMA: /* Smaller / larger than */
6864 if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
6869 case SND_FIL: /* Name of file containing filnames */
6871 if ((x = cmifi("Name of file containing list of filenames",
6872 "",&s,&y,xxstring)) < 0) {
6874 printf("?Filename required\n");
6878 } else if (y && iswild(s)) {
6879 printf("?Wildcards not allowed BBB\n");
6883 if (s) if (!*s) s = NULL;
6884 makestr(&(pv[n].sval),s);
6889 case SND_MOV: /* MOVE after */
6890 case SND_REN: /* RENAME after */
6891 case SND_SRN: { /* SERVER-RENAME */
6896 "Device and/or directory for incoming file after reception";
6899 m = "New name for incoming file after reception";
6902 m = "New name for source file on server after reception";
6906 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6908 printf("%s\n", n == SND_MOV ?
6909 "?Destination required" :
6910 "?New name required"
6916 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6917 pv[n].ival = (pv[n].sval) ? 1 : 0;
6921 case SND_CSL: /* Local character set */
6922 case SND_CSR: /* Remote (server) charset */
6923 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6924 return((x == -3) ? -2 : x);
6929 x_xla = 1; /* Overrides global OFF setting */
6932 case SND_XPA: /* Transparent */
6937 #endif /* NOCSETS */
6940 if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6942 makestr(&ftp_nml,s);
6945 case SND_PAT: /* /PATTERN: */
6947 if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6949 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6950 pv[n].ival = (pv[n].sval) ? 1 : 0;
6953 case SND_NLS: /* /NLST */
6954 pv[n].ival = 1; /* Use NLST */
6955 pv[SND_MLS].ival = 0; /* Don't use MLSD */
6958 case SND_MLS: /* /MLSD */
6959 pv[n].ival = 1; /* Use MLSD */
6960 pv[SND_NLS].ival = 0; /* Don't use NLST */
6963 default: /* /AFTER, /PERMISSIONS, etc... */
6964 printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6974 For GET, we want to parse an optional as-name, like with PUT.
6975 For MGET, we must parse a list of names, and then send NLST or MLSD
6976 commands for each name separately.
6978 switch (cmresult.fcode) { /* How did we get out of switch loop */
6979 case _CMFLD: /* Field */
6981 s = brstrip(cmresult.sresult);
6982 makestr(&(mgetlist[mgetn++]),s);
6983 while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6986 makestr(&(mgetlist[mgetn++]),brstrip(s));
6987 if (mgetn >= MGETMAX) {
6988 printf("?Too many items in MGET list\n");
6992 if ((x = cmcfm()) < 0)
6995 s = brstrip(cmresult.sresult);
6996 ckstrncpy(line,s,LINBUFSIZ);
6997 if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
7001 ckstrncpy(asnambuf,s,CKMAXPATH+1);
7002 if ((x = cmcfm()) < 0)
7006 case _CMCFM: /* Confirmation */
7009 printf("?Unexpected function code: %d\n",cmresult.fcode);
7013 if (pv[SND_REC].ival > 0) /* /RECURSIVE */
7016 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
7017 forcetype = 1; /* So skip the name-pattern match */
7018 ftp_typ = XYFT_B; /* Set binary */
7019 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
7022 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
7025 } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
7030 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
7032 p = brstrip(pv[SND_ASN].sval); /* As-name */
7033 ckstrncpy(asnambuf,p,CKMAXPATH+1);
7035 debug(F110,"ftp get asnambuf",asnambuf,0);
7038 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
7041 debug(F110,"GET /COMMAND before stripping",p,0);
7043 debug(F110,"GET /COMMAND after stripping",p,0);
7045 printf("?Sorry, a command to write to is required\n");
7052 #endif /* PIPESEND */
7054 /* Set up /MOVE and /RENAME */
7057 /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
7058 if (pv[SND_DEL].ival > 0 &&
7059 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
7060 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
7064 #endif /* COMMENT */
7066 if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
7068 char * p = pv[SND_MOV].sval;
7070 if (!isdir(p)) { /* Check directory */
7073 s = (char *)malloc(len + 4);
7075 strcpy(s,p); /* safe */
7077 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
7079 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
7080 #endif /* datageneral */
7087 #endif /* NOMKDIR */
7090 printf("?Can't create \"%s\"\n",p);
7096 printf("?Directory \"%s\" not found\n",p);
7099 #endif /* CK_MKDIR */
7101 makestr(&rcv_move,p);
7104 #endif /* CK_TMPDIR */
7106 if (pv[SND_REN].ival > 0) { /* /RENAME */
7107 char * p = pv[SND_REN].sval;
7110 printf("?New name required for /RENAME\n");
7116 /* If name given is wild, rename string must contain variables */
7117 if (mget && !getone) {
7121 if (!strcmp(tmpbuf,p)) {
7123 "?/RENAME for file group must contain variables such as \\v(filename)\n"
7131 makestr(&rcv_rename,p);
7132 debug(F110,"FTP rcv_rename",rcv_rename,0);
7134 if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
7135 printf("?Filename required but not given\n");
7138 } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
7139 printf("?You can't give both /LISTFILE and a remote filename\n");
7143 CHECKCONN(); /* Check connection */
7145 if (pv[SND_COL].ival > -1)
7146 x_fnc = pv[SND_COL].ival;
7149 /* If as-name given for MGET, as-name must contain variables */
7150 if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
7153 zzstring(asnambuf,&s,&x);
7154 if (!strcmp(tmpbuf,asnambuf)) {
7156 "?As-name for MGET must contain variables such as \\v(filename)\n"
7166 if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
7170 if (mdel || ftp_deb)
7174 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
7176 if (pv[SND_EXC].ival > 0)
7177 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
7178 if (pv[SND_SMA].wval > -1)
7179 getsmaller = pv[SND_SMA].wval;
7180 if (pv[SND_LAR].wval > -1)
7181 getlarger = pv[SND_LAR].wval;
7182 if (pv[SND_NAM].ival > -1)
7183 x_cnv = pv[SND_NAM].ival;
7184 if (pv[SND_ERR].ival > -1)
7185 geterror = pv[SND_ERR].ival;
7186 if (pv[SND_MAI].ival > -1)
7189 if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
7190 mgetmethod = SND_NLS;
7192 } else if (pv[SND_MLS].ival > 0) {
7193 mgetmethod = SND_MLS;
7198 if (pv[SND_RES].ival > 0) {
7200 printf("?Sorry, GET /RECOVER requires binary mode\n");
7204 /* Not true - the fact that the initial REST fails does not mean */
7205 /* it will fail here. */
7206 } else if (!okrestart) {
7207 printf("WARNING: Server might not support restart...\n");
7208 #endif /* COMMENT */
7212 #endif /* FTP_RESTART */
7215 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
7217 printf("?Switch conflict: /FILTER and /COMMAND\n");
7221 makestr(&rcvfilter,pv[SND_FLT].sval);
7222 debug(F110,"ftp get /FILTER", rcvfilter, 0);
7224 if (rcvfilter || pipesend) { /* /RESTART */
7226 if (restart) { /* with pipes or filters */
7227 printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
7231 #endif /* FTP_RESTART */
7232 if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
7234 "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
7239 #endif /* PIPESEND */
7241 tfc = (CK_OFF_T)0; /* Initialize stats and counters */
7246 if (pv[SND_FIL].ival > 0) {
7247 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
7248 debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
7249 printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
7253 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
7254 zclose(ZMFILE); /* Failed */
7255 debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
7256 printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
7261 debug(F110,"ftp get listfile first",tmpbuf,0);
7262 makestr(&(mgetlist[0]),tmpbuf);
7264 t0 = gmstimer(); /* Record starting time */
7266 updating = 0; /* Checking dates? */
7267 if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
7269 if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
7271 if (updating) /* These switches force FTP DATES ON */
7274 what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
7276 cancelgroup = 0; /* Group not canceled yet */
7277 if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
7278 changetype(ftp_typ,0); /* Change to requested type */
7279 binary = ftp_typ; /* For file-transfer display */
7280 first = 1; /* For MGET list */
7281 done = 0; /* Loop control */
7284 if (dldir && !f_tmpdir) { /* If they have a download directory */
7285 if ((s = zgtdir())) { /* Get current directory */
7286 if (zchdir(dldir)) { /* Change to download directory */
7287 ckstrncpy(savdir,s,TMPDIRLEN);
7288 f_tmpdir = 1; /* Remember that we did this */
7292 #endif /* CK_TMPDIR */
7294 if (ftp_nml) { /* /NAMELIST */
7295 debug(F110,"ftp GET ftp_nml",ftp_nml,0);
7296 if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
7299 fp_nml = fopen(ftp_nml, "wb");
7301 printf("?%s: %s\n",ftp_nml,ck_errstr());
7305 while (!done && !cancelgroup) { /* Loop for all files */
7306 /* or until canceled. */
7308 /* do something here if proxy */
7309 #endif /* FTP_PROXY */
7311 rs_len = (CK_OFF_T)0; /* REGET position */
7312 cancelfile = 0; /* This file not canceled yet */
7313 haspath = 0; /* Recalculate this each time thru */
7315 if (getone) { /* GET */
7318 src = line; /* Server name */
7320 debug(F111,"ftp get file",s,0);
7321 } else if (mget) { /* MGET */
7322 src = mgetlist[mgetx];
7323 debug(F111,"ftp mget remote_files A",src,first);
7324 s = (char *)remote_files(first,
7325 (CHAR *)mgetlist[mgetx],
7326 (CHAR *)pv[SND_PAT].sval,
7329 debug(F110,"ftp mget remote_files B",s,0);
7333 if (listfile) { /* Names from listfile */
7336 while (!tmpbuf[0]) {
7337 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7339 debug(F110,"ftp get listfile EOF",
7340 pv[SND_FIL].sval,0);
7341 makestr(&(mgetlist[0]),NULL);
7350 makestr(&(mgetlist[0]),tmpbuf);
7351 debug(F110,"ftp get listfile next",tmpbuf,0);
7352 s = (char *)remote_files(first,
7353 (CHAR *)mgetlist[0],
7354 (CHAR *)pv[SND_PAT].sval,
7357 debug(F110,"ftp mget remote_files C",s,0);
7359 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7360 ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
7361 tlog(F110,"ftp get file not found:",s,0);
7364 } else { /* Names from command line */
7367 s = (char *)remote_files(first,
7368 (CHAR *)mgetlist[mgetx],
7369 (CHAR *)pv[SND_PAT].sval,
7375 debug(F111,"ftp mget remote_files D",s,mgetx);
7378 if (!first || mgetx >= mgetn) {
7381 } else if (geterror) {
7391 debug(F111,"ftp mget remote_files E",s,0);
7393 The semantics of NLST are ill-defined. Suppose we have just sent
7394 NLST /path/[a-z]*. Most servers send back names like /path/foo,
7395 /path/bar, etc. But some send back only foo and bar, and subsequent
7396 RETR commands based on the pathless names are not going to work.
7398 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7400 if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7401 int len, left = 4096;
7402 char * tmp = xtmpbuf;
7403 len = s3 - mgetlist[mgetx] + 1;
7404 ckstrncpy(tmp,mgetlist[mgetx],left);
7407 ckstrncpy(tmp,s,left);
7409 debug(F111,"ftp mget remote_files F",s,0);
7413 skipthis = 0; /* File selection... */
7415 nam = s; /* Filename (without path) */
7416 rc = 0; /* Initial return code */
7419 if (!getone && !skipthis) { /* For MGET and MDELETE... */
7425 debug(F111,"ftp mget havetype",s,havetype);
7426 if (havetype > 0 && havetype != FTYP_FILE) {
7427 /* Server says it's not file... */
7428 debug(F110,"ftp mget not-a-file",s,0);
7432 Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7433 But if the client did not ask for a recursive list, we have to ignore any
7434 server files that include a pathname that extends beyond any path that
7435 was included in the user's request.
7437 User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
7438 get the user's path segment. Then, for each incoming file, if it begins
7439 with the same path segment, we must strip it (point past it).
7441 src = mgetlist[mgetx]; /* In case it moved! */
7443 for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7444 if (ispathsep(src[i])) /* in user's pathname */
7450 usrpath = k; /* User path segment length */
7451 debug(F111,"ftp get usrpath",src,usrpath);
7453 p = s; /* Server filename */
7454 while ((c = *p++)) { /* Look for path in server filename */
7457 nam = p; /* Pathless name (for ckmatch) */
7458 srvpath = p - s; /* Server path segment length */
7461 debug(F111,"ftp get srvpath",s,srvpath);
7465 Here we handle the case where the user said "mget foo" where foo is a
7466 directory name, and the server is sending back names like "foo/file1",
7467 "foo/file2", etc. This is a nasty trick but it's necessary because the
7468 user can't compensate by typing "mget foo/" because then the server is
7469 likely to send back "foo//file1, foo//file2" etc, and we still won't
7472 int srclen = 0, srvlen = 0;
7473 if (src) srclen = strlen(src);
7474 if (s) srvlen = strlen(s);
7475 if (src && (srvlen > srclen)) {
7476 if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7477 char * tmpsrc = NULL;
7478 tmpsrc = (char *)malloc(srclen + 2);
7479 strncpy(tmpsrc,src,srclen);
7480 tmpsrc[srclen] = s[srclen];
7481 tmpsrc[srclen+1] = NUL;
7482 free(mgetlist[mgetx]);
7483 mgetlist[mgetx] = tmpsrc;
7485 src = mgetlist[mgetx];
7491 If as-name not given and server filename includes path that matches
7492 the pathname from the user's file specification, we must trim the common
7493 path prefix from the server's name when constructing the local name.
7495 if (src && /* Wed Sep 25 17:27:48 2002 */
7497 !recursive && /* Thu Sep 19 16:11:59 2002 */
7499 !strncmp(src,s,usrpath)) {
7500 s2 = s + usrpath; /* Local name skips past remote path */
7503 /* This doesn't work if the path prefix contains wildcards! */
7504 haspath = (srvpath > usrpath);
7506 { /* Count path segments instead */
7509 for (p = s; *p; p++)
7510 if (ispathsep(*p)) x1++;
7511 for (p = src; *p; p++) {
7512 if (ispathsep(*p)) x2++;
7514 haspath = recursive ? x1 || x2 : x1 > x2;
7515 debug(F111,"ftp get server path segments",s,x1);
7516 debug(F111,"ftp get user path segments",src,x2);
7519 #endif /* COMMENT */
7520 debug(F111,"ftp get haspath",s+usrpath,haspath);
7522 if (haspath) { /* Server file has path segments? */
7523 if (!recursive) { /* [M]GET /RECURSIVE? */
7525 We did not ask for a recursive listing, but the server is sending us one
7526 anyway (as wu-ftpd is wont to do). We get here if the current filename
7527 includes a path segment beyond any path segment we asked for in our
7528 non-recursive [M]GET command. We MUST skip this file.
7530 debug(F111,"ftp get skipping because of path",s,0);
7534 } else if (getone && !skipthis) { /* GET (not MGET) */
7536 while ((c = *p++)) { /* Handle path in local name */
7538 if (recursive) { /* If recursive, keep it */
7541 } else { /* Otherwise lose it. */
7548 if (!*nam) /* Name without path */
7551 if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7555 if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7557 for (i = 0; i < NSNDEXCEPT; i++) {
7558 if (!rcvexcept[i]) {
7561 xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7562 debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7564 tlog(F100," refused: exception list","",0);
7565 msg = "Refused: Exception List";
7571 if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7577 #endif /* CKREGEX */
7581 if (!x_xla) { /* If translation is off */
7582 x_csl = -2; /* unset the charsets */
7585 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
7586 if (!*s2) /* Local name */
7587 s2 = asnambuf; /* As-name */
7589 if (!*s2) /* Sat Nov 16 19:19:39 2002 */
7590 s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
7592 debug(F110,"ftp get filnam ",s,0);
7593 debug(F110,"ftp get asname A",s2,0);
7595 /* Receiving to real file */
7599 #endif /* PIPESEND */
7602 /* Do this here so we can decide whether to skip */
7603 if (cmd_quoting && !skipthis && asnambuf[0]) {
7607 zzstring(asnambuf,&p,&n);
7609 debug(F111,"ftp get asname B",s2,updating);
7613 local = *s2 ? s2 : s;
7615 if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7618 debug(F111,"ftp get DISCARD zchki",local,x);
7621 debug(F110,"ftp get skip name",local,0);
7622 tlog(F100," refused: name","",0);
7623 msg = "Refused: Name";
7628 if (!skipthis && updating) { /* If updating and not yet skipping */
7629 if (zchki(local) > -1) {
7630 x = chkmodtime(local,s,0);
7634 debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7636 debug(F111,"ftp get /update chkmodtime",local,x);
7639 if ((updating == 1 && x > 0) || /* /UPDATE */
7640 (updating == 2 && x == 1)) { /* /DATES-DIFFER */
7642 tlog(F100," refused: date","",0);
7643 msg = "Refused: Date";
7644 debug(F110,"ftp get skip date",local,0);
7648 #endif /* DOUPDATE */
7650 /* Initialize file size to -1 in case server doesn't understand */
7651 /* SIZE command, so xxscreen() will know we don't know the size */
7653 fsize = (CK_OFF_T)-1;
7655 /* Ask for size now only if we need it for selection */
7656 /* because if you're going thru a list 100,000 files to select */
7657 /* a small subset, 100,000 SIZE commands can take hours... */
7660 if (!mdel && !skipthis && /* Don't need size for DELE... */
7661 (getsmaller >= (CK_OFF_T)0 || getlarger >= (CK_OFF_T)0)) {
7662 if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
7665 } else { /* No - must ask server */
7667 Prior to sending the NLST command we necessarily put the
7668 server into ASCII mode. We must now put it back into the
7669 the requested mode so the upcoming SIZE command returns
7670 right kind of size; this is especially important for
7671 GET /RECOVER; otherwise the server returns the "ASCII" size
7672 of the file, rather than its true size.
7674 changetype(ftp_typ,0); /* Change to requested type */
7675 fsize = (CK_OFF_T)-1;
7677 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7678 if (x == REPLY_COMPLETE) {
7679 fsize = ckatofs(&ftp_reply_str[4]);
7685 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
7687 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
7690 debug(F111,"ftp get skip size",s,fsize);
7691 tlog(F100," refused: size","",0);
7692 msg = "Refused: Size";
7695 } else if (getone) {
7696 /* SIZE can fail for many reasons. Does the file exist? */
7697 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7698 if (x != REPLY_COMPLETE) {
7699 printf(">>> FILE NOT FOUND: %s\n",s);
7702 #endif /* COMMENT */
7705 if (skipthis) { /* Skipping this file? */
7706 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7708 ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
7710 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
7713 if (fp_nml) { /* /NAMELIST only - no transfer */
7714 fprintf(fp_nml,"%s\n",s);
7717 if (recursive && haspath && !pipesend
7720 #endif /* PIPESEND */
7727 x = zmkdir(s); /* Try to make the directory */
7728 #endif /* NOMKDIR */
7731 rc = -1; /* Failure is fatal */
7734 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7735 "Directory creation failure");
7743 selected++; /* Count this file as selected */
7746 if (!gotsize && !mdel) { /* Didn't get size yet */
7747 if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
7750 } else { /* No - must ask server */
7751 fsize = (CK_OFF_T)-1;
7753 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7754 if (x == REPLY_COMPLETE) {
7755 fsize = ckatofs(&ftp_reply_str[4]);
7761 if (mdel) { /* [M]DELETE */
7762 if (displa && !ftp_vbm)
7765 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7767 tlog(F110,"ftp mdelete",s,0);
7768 if (displa && !ftp_vbm)
7771 tlog(F110,"ftp mdelete failed:",s,0);
7777 } else if (rcvfilter) { /* [M]GET with filter */
7780 p = tmpbuf; /* Safe - no asname with filter */
7781 zzstring(rcvfilter,&p,&n);
7784 debug(F111,"ftp get rcvfilter",pn,n);
7785 #endif /* PIPESEND */
7787 if (toscreen) s2 = "-";
7788 } else if (pipesend) { /* [M]GET /COMMAND */
7791 p = tmpbuf; /* Safe - no asname with filter */
7792 zzstring(pipename,&p,&n);
7795 debug(F111,"ftp get pipename",pipename,n);
7796 if (toscreen) s2 = "-";
7797 } else { /* [M]GET with no pipes or filters */
7798 debug(F111,"ftp get s2 A",s2,x_cnv);
7800 s2 = "-"; /* (hokey convention for stdout) */
7801 } else if (!*s2) { /* No asname? */
7802 if (x_cnv) { /* If converting */
7803 nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7805 debug(F110,"ftp get nzrtol",s2,0);
7806 } else /* otherwise */
7807 s2 = s; /* use incoming file's name */
7809 debug(F110,"ftp get s2 B",s2,0);
7811 /* If local file already exists, take collision action */
7816 #endif /* PIPESEND */
7820 debug(F111,"ftp get zchki",s2,x);
7821 debug(F111,"ftp get x_fnc",s2,x_fnc);
7823 if (x > (CK_OFF_T)-1 && !restart) {
7825 char * newname = NULL;
7828 case XYFX_A: /* Append */
7831 case XYFX_R: /* Rename */
7832 case XYFX_B: /* Backup */
7833 znewn(s2,&newname); /* Make unique name */
7834 debug(F110,"ftp get znewn",newname,0);
7835 if (x_fnc == XYFX_B) { /* Backup existing file */
7836 x = zrename(s2,newname);
7837 debug(F111,"ftp get backup zrename",newname,x);
7838 } else { /* Rename incoming file */
7839 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7841 debug(F111,"ftp get rename incoming",newname,x);
7844 ftscreen(SCR_EM,0,(CK_OFF_T)0,
7845 "Backup/Rename failed");
7850 case XYFX_D: /* Discard (already handled above) */
7851 case XYFX_U: /* Update (ditto) */
7852 case XYFX_M: /* Update (ditto) */
7853 case XYFX_X: /* Overwrite */
7861 debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7862 #endif /* PIPESEND */
7863 if (pipesend && !toscreen)
7867 debug(F101,"ftp get x_xla","",x_xla);
7868 debug(F101,"ftp get x_csl","",x_csl);
7869 debug(F101,"ftp get x_csr","",x_csr);
7870 debug(F101,"ftp get append","",append);
7874 rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7878 debug(F111,"ftp get rc",s,rc);
7879 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
7880 debug(F111,"ftp get cancelfile",s,cancelfile);
7881 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7882 debug(F111,"ftp get renaming",s,renaming);
7883 debug(F111,"ftp get moving",s,moving);
7891 if (deleting) { /* GET /DELETE (source file) */
7893 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7895 tlog(F110, (rc > -1) ?
7896 " deleted" : " failed to delete", s, 0);
7898 if (renaming && rcv_rename && !toscreen) {
7899 char *p; /* Rename downloaded file */
7901 char tmpbuf[CKMAXPATH+1];
7905 debug(F111,"ftp get /rename",rcv_rename,0);
7906 zzstring(rcv_rename,&p,&n);
7907 debug(F111,"ftp get /rename",rcv_rename,0);
7912 rc = (zrename(s2,p) < 0) ? -1 : 1;
7913 debug(F111,"doftpget /RENAME zrename",p,rc);
7914 tlog(F110, (rc > -1) ?
7916 " failed to rename to",
7920 } else if (moving && rcv_move && !toscreen) {
7921 char *p; /* Move downloaded file */
7923 char tmpbuf[CKMAXPATH+1];
7927 debug(F111,"ftp get /move-to",rcv_move,0);
7928 zzstring(rcv_move,&p,&n);
7933 debug(F111,"ftp get /move-to",p,0);
7934 rc = (zrename(s2,p) < 0) ? -1 : 1;
7935 debug(F111,"doftpget /MOVE zrename",p,rc);
7936 tlog(F110, (rc > -1) ?
7937 " moved to" : " failed to move to", p, 0);
7939 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7940 char * s = pv[SND_SRN].sval;
7941 char * srvrn = pv[SND_SRN].sval;
7942 char tmpbuf[CKMAXPATH+1];
7944 int y; /* Pass it thru the evaluator */
7945 extern int cmd_quoting; /* for \v(filename) */
7946 debug(F111,"ftp get srv_renam",s,1);
7951 zzstring(srvrn,&s,&y);
7955 debug(F111,"ftp get srv_renam",s,1);
7958 x = ftp_rename(s2,s);
7959 debug(F111,"ftp get ftp_rename",s2,x);
7960 tlog(F110, (x > 0) ?
7961 " renamed source file to" :
7962 " failed to rename source file to",
7977 debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
7978 if (ftp_timed_out) {
7980 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
7982 #endif /* FTP_TIMEOUT */
7985 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
7992 debug(F101,"ftp get status","",status);
7993 debug(F101,"ftp get cancelgroup","",cancelgroup);
7994 debug(F101,"ftp get cancelfile","",cancelfile);
7995 debug(F101,"ftp get selected","",selected);
7996 debug(F101,"ftp get good","",good);
8000 if (selected == 0) { /* No files met selection criteria */
8001 status = 1; /* which is a kind of success. */
8002 } else if (status > 0) { /* Some files were selected */
8003 if (cancelgroup) /* but MGET was canceled */
8004 status = 0; /* so MGET failed */
8005 else if (cancelfile && good < 1) /* If file was canceled */
8006 status = 0; /* MGET failed if it got no files */
8010 debug(F101,"ftp get success","",success);
8013 pipesend = pipesave; /* Restore global pipe selection */
8014 if (fp_nml) { /* Close /NAMELIST */
8015 if (fp_nml != stdout)
8024 #endif /* COMMENT */
8025 ) { /* Download successful */
8027 t1 = gmstimer(); /* End time */
8028 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
8029 if (!sec) sec = 0.001;
8032 sec = (t1 - t0) / 1000;
8034 #endif /* GFTIMER */
8035 tfcps = (long) (tfc / sec);
8037 lastxfer = W_FTP|W_RECV;
8041 ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
8043 if (f_tmpdir) { /* If we changed to download dir */
8044 zchdir((char *) savdir); /* Go back where we came from */
8047 #endif /* CK_TMPDIR */
8049 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
8053 for (i = 0; i < mgetn; i++) /* MGET list too */
8054 makestr(&(mgetlist[i]),NULL);
8056 if (cancelgroup) /* Clear temp-file stack */
8059 ftreset(); /* Undo switch effects */
8064 static struct keytab ftprmt[] = {
8066 { "cdup", XZCDU, 0 },
8067 { "cwd", XZCWD, CM_INV },
8068 { "delete", XZDEL, 0 },
8069 { "directory", XZDIR, 0 },
8070 { "exit", XZXIT, 0 },
8071 { "help", XZHLP, 0 },
8072 { "login", XZLGI, 0 },
8073 { "logout", XZLGO, 0 },
8074 { "mkdir", XZMKD, 0 },
8075 { "pwd", XZPWD, 0 },
8076 { "rename", XZREN, 0 },
8077 { "rmdir", XZRMD, 0 },
8078 { "type", XZTYP, 0 },
8081 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
8084 doftpsite() { /* Send a SITE command */
8087 int lcs = -1, rcs = -1;
8088 int save_vbm = ftp_vbm;
8093 if (lcs < 0) lcs = fcharset;
8095 if (rcs < 0) rcs = ftp_csr;
8097 #endif /* NOCSETS */
8098 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8101 ckstrncpy(line,s,LINBUFSIZ);
8102 if (testing) printf(" ftp site \"%s\"...\n",line);
8104 ftp_vbm = !ckstrcmp("HELP",line,4,0);
8105 if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
8107 reply = getreply(0,lcs,rcs,ftp_vbm,0);
8108 } while (reply == REPLY_PRELIM);
8111 return(success = (reply == REPLY_COMPLETE));
8116 dosetftppsv() { /* Passive mode */
8117 x = seton(&ftp_psv);
8118 if (x > 0) passivemode = ftp_psv;
8122 /* d o f t p r m t -- Parse and execute REMOTE commands */
8125 doftprmt(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
8126 /* cx == 0 means REMOTE */
8127 /* cx != 0 is a XZxxx value */
8134 if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
8139 case XZCDU: /* CDUP */
8140 if ((x = cmcfm()) < 0) return(x);
8141 return(doftpcdup());
8143 case XZCWD: /* RCD */
8144 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8146 ckstrncpy(line,s,LINBUFSIZ);
8148 return(doftpcwd(s,1));
8149 case XZPWD: /* RPWD */
8151 case XZDEL: /* RDEL */
8152 return(doftpget(FTP_MDE,1));
8153 case XZDIR: /* RDIR */
8154 return(doftpdir(FTP_DIR));
8155 case XZHLP: /* RHELP */
8156 return(doftpxhlp());
8157 case XZMKD: /* RMKDIR */
8159 case XZREN: /* RRENAME */
8161 case XZRMD: /* RRMDIR */
8163 case XZLGO: /* LOGOUT */
8165 case XZXIT: /* EXIT */
8168 printf("?Not usable with FTP - \"%s\"\n", atmbuf);
8173 doxftp() { /* Command parser for built-in FTP */
8178 int lcs = -1, rcs = -1;
8183 if (lcs < 0) lcs = fcharset;
8185 if (rcs < 0) rcs = ftp_csr;
8187 #endif /* NOCSETS */
8189 if (inserver) /* FTP not allowed in IKSD. */
8192 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8193 ftp_typ = g_ftp_typ;
8194 /* g_ftp_typ = -1; */
8198 We'll set the collision action locally in doftpget() based on whether
8199 ftp_fnc was ever set to a value. if not, we'll use the fncact value.
8201 if (ftp_fnc < 0) /* Inherit global collision action */
8202 ftp_fnc = fncact; /* if none specified for FTP */
8203 #endif /* COMMENT */
8205 /* Restore global verbose mode */
8213 ftp_dates &= 1; /* Undo any previous /UPDATE switch */
8215 dpyactive = 0; /* Reset global transfer-active flag */
8216 printlines = 0; /* Reset printlines */
8218 if (fp_nml) { /* Reset /NAMELIST */
8219 if (fp_nml != stdout)
8223 makestr(&ftp_nml,NULL);
8225 cmfdbi(&kw, /* First FDB - commands */
8227 "Hostname; or FTP command", /* help */
8229 "", /* addtl string data */
8230 nftpcmd, /* addtl numeric data 1: tbl size */
8231 0, /* addtl numeric data 2: none */
8232 xxstring, /* Processing function */
8233 ftpcmdtab, /* Keyword table */
8234 &fl /* Pointer to next FDB */
8236 cmfdbi(&fl, /* A host name or address */
8238 "Hostname or address", /* help */
8240 "", /* addtl string data */
8241 0, /* addtl numeric data 1 */
8242 0, /* addtl numeric data 2 */
8247 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8249 printf("?ftp what? \"help ftp\" for hints\n");
8254 if (cmresult.fcode == _CMFLD) { /* If hostname */
8255 return(openftp(cmresult.sresult,0)); /* go open the connection */
8257 cx = cmresult.nresult;
8260 case FTP_ACC: /* ACCOUNT */
8261 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
8264 makestr(&ftp_acc,s);
8266 printf(" ftp account: \"%s\"\n",ftp_acc);
8267 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
8270 case FTP_GUP: /* Go UP */
8271 if ((x = cmcfm()) < 0) return(x);
8273 if (testing) printf(" ftp cd: \"(up)\"\n");
8274 return(success = doftpcdup());
8276 case FTP_CWD: /* CD */
8277 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8280 ckstrncpy(line,s,LINBUFSIZ);
8282 printf(" ftp cd: \"%s\"\n", line);
8283 return(success = doftpcwd(line,1));
8285 case FTP_CHM: /* CHMOD */
8286 if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
8288 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8289 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8292 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
8294 printf(" ftp chmod: %s\n",ftpcmdbuf);
8296 (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8299 case FTP_CLS: /* CLOSE FTP connection */
8300 if ((y = cmcfm()) < 0)
8304 printf(" ftp closing...\n");
8306 return(success = 1);
8308 case FTP_DIR: /* DIRECTORY of remote files */
8310 return(doftpdir(cx));
8312 case FTP_GET: /* GET a remote file */
8313 case FTP_RGE: /* REGET */
8314 case FTP_MGE: /* MGET */
8315 case FTP_MDE: /* MDELETE */
8316 return(doftpget(cx,1));
8318 case FTP_IDL: /* IDLE */
8319 if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
8321 if ((y = cmcfm()) < 0)
8324 if (z < 0) { /* Display idle timeout */
8326 printf(" ftp query idle timeout...\n");
8327 success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
8328 } else { /* Set idle timeout */
8330 printf(" ftp idle timeout set: %d...\n",z);
8332 (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
8336 case FTP_MKD: /* MKDIR */
8339 case FTP_MOD: /* MODTIME */
8340 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8343 ckstrncpy(line,s,LINBUFSIZ);
8345 printf(" ftp modtime \"%s\"...\n",line);
8347 if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
8355 bzero((char *)&tmremote, sizeof(struct tm));
8357 while ((c = *s++)) {
8364 if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8372 printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8389 case FTP_OPN: /* OPEN connection */
8391 x = cmfld("IP hostname or address","",&s,xxstring);
8396 ckstrncpy(line,s,LINBUFSIZ);
8398 return(openftp(s,0));
8400 { /* OPEN connection */
8401 char name[TTNAMLEN+1], *p;
8403 extern char ttname[];
8404 if (network) /* If we have a current connection */
8405 ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8407 *name = '\0'; /* as default host */
8408 for (p = name; *p; p++) /* Remove ":service" from end. */
8409 if (*p == ':') { *p = '\0'; break; }
8411 x = cmfld("IP hostname or address",name,&s,xxstring);
8413 cmfdbi(&kw, /* First FDB - commands */
8415 "Hostname or switch", /* help */
8417 "", /* addtl string data */
8418 ntlstab, /* addtl numeric data 1: tbl size */
8419 0, /* addtl numeric data 2: none */
8420 xxstring, /* Processing function */
8421 tlstab, /* Keyword table */
8422 &fl /* Pointer to next FDB */
8424 cmfdbi(&fl, /* A host name or address */
8426 "Hostname or address", /* help */
8428 "", /* addtl string data */
8429 0, /* addtl numeric data 1 */
8430 0, /* addtl numeric data 2 */
8437 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8439 printf("?ftp open what? \"help ftp\" for hints\n");
8444 if (cmresult.fcode == _CMFLD) { /* Hostname */
8445 s = cmresult.sresult;
8447 } else if (cmresult.nresult == OPN_TLS) {
8451 #endif /* USETLSTAB */
8456 ckstrncpy(line,s,LINBUFSIZ);
8458 return(openftp(s,usetls));
8460 #endif /* COMMENT */
8462 case FTP_PUT: /* PUT */
8463 case FTP_MPU: /* MPUT */
8464 case FTP_APP: /* APPEND */
8465 case FTP_REP: /* REPUT */
8466 return(doftpput(cx,1));
8468 case FTP_PWD: /* PWD */
8470 if (x > -1) success = x;
8473 case FTP_REN: /* RENAME */
8476 case FTP_RES: /* RESET */
8479 case FTP_HLP: /* (remote) HELP */
8480 return(doftpxhlp());
8482 case FTP_RMD: /* RMDIR */
8485 case FTP_STA: /* STATUS */
8486 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8489 ckstrncpy(line,s,LINBUFSIZ);
8490 if (testing) printf(" ftp status \"%s\"...\n",line);
8491 success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8494 case FTP_SIT: { /* SITE */
8495 return(doftpsite());
8498 case FTP_SIZ: /* (ask for) SIZE */
8499 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8502 ckstrncpy(line,s,LINBUFSIZ);
8504 printf(" ftp size \"%s\"...\n",line);
8505 success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8510 case FTP_SYS: /* Ask for server's SYSTEM type */
8511 if ((x = cmcfm()) < 0) return(x);
8514 printf(" ftp system...\n");
8515 success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8518 case FTP_UMA: /* Set/query UMASK */
8519 if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8522 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8523 if ((x = cmcfm()) < 0) return(x);
8527 printf(" ftp umask \"%s\"...\n",tmpbuf);
8529 printf(" ftp query umask...\n");
8531 success = ftp_umask(tmpbuf);
8538 if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8541 success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8544 case FTP_TYP: /* Type */
8545 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8547 if ((y = cmcfm()) < 0) return(y);
8551 tenex = (ftp_typ == FTT_TEN);
8552 changetype(ftp_typ,ftp_vbm);
8555 case FTP_CHK: /* Check if remote file(s) exist(s) */
8556 if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8559 success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
8562 case FTP_FEA: /* RFC2389 */
8563 if ((y = cmcfm()) < 0)
8566 success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8568 if (sfttab[0] > 0) {
8569 ftp_aut = sfttab[SFT_AUTH];
8570 sizeok = sfttab[SFT_SIZE];
8571 mdtmok = sfttab[SFT_MDTM];
8572 mlstok = sfttab[SFT_MLST];
8577 case FTP_OPT: /* RFC2389 */
8578 /* Perhaps this should be a keyword list... */
8579 if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8582 ckstrncpy(line,s,LINBUFSIZ);
8583 if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8585 success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8588 case FTP_ENA: /* FTP ENABLE */
8589 case FTP_DIS: /* FTP DISABLE */
8590 if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8592 if ((y = cmcfm()) < 0) return(y);
8594 case ENA_AUTH: /* OK to use autoauthentication */
8595 ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8596 sfttab[SFT_AUTH] = ftp_aut;
8598 case ENA_FEAT: /* OK to send FEAT command */
8599 featok = (cx == FTP_ENA) ? 1 : 0;
8601 case ENA_MLST: /* OK to use MLST/MLSD */
8602 mlstok = (cx == FTP_ENA) ? 1 : 0;
8603 sfttab[SFT_MLST] = mlstok;
8605 case ENA_MDTM: /* OK to use MDTM */
8606 mdtmok = (cx == FTP_ENA) ? 1 : 0;
8607 sfttab[SFT_MDTM] = mdtmok;
8609 case ENA_SIZE: /* OK to use SIZE */
8610 sizeok = (cx == FTP_ENA) ? 1 : 0;
8611 sfttab[SFT_SIZE] = sizeok;
8614 return(success = 1);
8623 case FPL_CLR: return("clear");
8624 case FPL_PRV: return("private");
8625 case FPL_SAF: return("safe");
8626 case 0: return("(not set)");
8627 default: return("(unknown)");
8632 shoftp(brief) int brief; {
8636 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8637 ftp_typ = g_ftp_typ;
8638 /* g_ftp_typ = -1; */
8641 printf("FTP connection: %s\n",connected ?
8648 printf("FTP server type: %s\n",
8649 ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8652 printf("Logged in as: %s\n",
8653 strval(ftp_logname,"(unknown)"));
8655 printf("Not logged in\n");
8657 if (brief) return(0);
8659 printf("\nSET FTP values:\n\n");
8662 printf(" ftp anonymous-password: %s\n",
8663 ftp_apw ? ftp_apw : "(default)"
8665 printf(" ftp auto-login: %s\n",showoff(ftp_log));
8666 printf(" ftp auto-authentication: %s\n",showoff(ftp_aut));
8668 case FTT_ASC: s = "text"; break;
8669 case FTT_BIN: s = "binary"; break;
8670 case FTT_TEN: s = "tenex"; break;
8673 printf(" ftp timeout: %ld\n",ftp_timeout);
8674 #endif /* FTP_TIMEOUT */
8675 printf(" ftp type: %s\n",s);
8676 printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
8677 printf(" ftp dates: %s\n",showoff(ftp_dates));
8678 printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
8679 printf(" ftp filenames: %s\n",
8680 ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8682 printf(" ftp debug %s\n",showoff(ftp_deb));
8684 printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
8685 printf(" ftp permissions: %s\n",showooa(ftp_prm));
8686 printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
8687 printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
8688 printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
8690 /* See note in doxftp() */
8693 #endif /* COMMENT */
8694 printf(" ftp collision: %s\n",
8695 fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8696 printf(" ftp server-time-offset: %s\n",
8697 fts_sto ? fts_sto : "(none)");
8701 printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8702 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8704 printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
8705 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8707 printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
8708 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8709 #endif /* NOCSETS */
8715 case XYFD_N: s = "none"; break;
8716 case XYFD_R: s = "serial"; break;
8717 case XYFD_C: s = "fullscreen"; break;
8718 case XYFD_S: s = "crt"; break;
8719 case XYFD_B: s = "brief"; break;
8721 printf(" ftp display: %s\n",s);
8722 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8724 if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8725 printf(" enabled: ");
8726 if (ftp_aut) printf(" AUTH");
8727 if (featok) printf(" FEAT");
8728 if (mdtmok) printf(" MDTM");
8729 if (mlstok) printf(" MLST");
8730 if (sizeok) printf(" SIZE");
8732 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8734 if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8735 printf(" disabled: ");
8736 if (!ftp_aut) printf(" AUTH");
8737 if (!featok) printf(" FEAT");
8738 if (!mdtmok) printf(" MDTM");
8739 if (!mlstok) printf(" MLST");
8740 if (!sizeok) printf(" SIZE");
8742 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8745 case 0: s = "kermit"; break;
8746 case 1: s = "ftp"; break;
8747 case 2: s = "auto"; break;
8750 printf(" get-put-remote: %s\n",s);
8751 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8754 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8757 printf("Available security methods: ");
8760 #endif /* FTP_GSSAPI */
8762 printf("Kerberos4 ");
8763 #endif /* FTP_KRB4 */
8766 #endif /* FTP_SRP */
8769 #endif /* FTP_SSL */
8773 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8774 printf(" ftp authtype: %s\n",strval(auth_type,NULL));
8775 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8776 printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
8777 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8778 printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
8779 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8780 printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
8781 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8782 printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
8783 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8784 printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
8785 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8787 printf("Available security methods: (none)\n");
8788 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8789 #endif /* FTP_SECURITY */
8791 if (n <= cmd_rows - 3)
8798 /* FTP HELP text strings */
8800 static char * fhs_ftp[] = {
8801 "Syntax: FTP subcommand [ operands ]",
8802 " Makes an FTP connection, or sends a command to the FTP server.",
8803 " To see a list of available FTP subcommands, type \"ftp ?\".",
8804 " and then use HELP FTP xxx to get help about subcommand xxx.",
8805 " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8809 static char * fhs_acc[] = { /* ACCOUNT */
8810 "Syntax: FTP ACCOUNT text",
8811 " Sends an account designator to an FTP server that needs one.",
8812 " Most FTP servers do not use accounts; some use them for other",
8813 " other purposes, such as disk-access passwords.",
8816 static char * fhs_app[] = { /* APPEND */
8817 "Syntax: FTP APPEND filname",
8818 " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
8821 static char * fhs_cls[] = { /* BYE, CLOSE */
8822 "Syntax: [ FTP ] BYE",
8823 " Logs out from the FTP server and closes the FTP connection.",
8824 " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
8827 static char * fhs_cwd[] = { /* CD, CWD */
8828 "Syntax: [ FTP ] CD directory",
8829 " Asks the FTP server to change to the given directory.",
8830 " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
8833 static char * fhs_gup[] = { /* CDUP, UP */
8835 " Asks the FTP server to change to the parent directory of its current",
8836 " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
8839 static char * fhs_chm[] = { /* CHMOD */
8840 "Syntax: FTP CHMOD filename permissions",
8841 " Asks the FTP server to change the permissions, protection, or mode of",
8842 " the given file. The given permissions must be in the syntax of the",
8843 " the server's file system, e.g. an octal number for UNIX. Also see",
8844 " FTP PUT /PERMISSIONS",
8847 static char * fhs_mde[] = { /* DELETE */
8848 "Syntax: FTP DELETE [ switches ] filespec",
8849 " Asks the FTP server to delete the given file or files.",
8850 " Synonym: MDELETE (Kermit makes no distinction between single and",
8851 " multiple file deletion). Optional switches:",
8853 " /ERROR-ACTION:{PROCEED,QUIT}",
8855 " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8856 " /LARGER-THAN:number",
8859 #endif /* UNIXOROSK */
8862 " /RECURSIVE (depends on server)",
8864 #endif /* RECURSIVE */
8865 " /SMALLER-THAN:number",
8868 static char * fhs_dir[] = { /* DIRECTORY */
8869 "Syntax: FTP DIRECTORY [ filespec ]",
8870 " Asks the server to send a directory listing of the files that match",
8871 " the given filespec, or if none is given, all the files in its current",
8872 " directory. The filespec, including any wildcards, must be in the",
8873 " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
8874 " Synonym: RDIRECTORY.",
8877 static char * fhs_vdi[] = { /* VDIRECTORY */
8878 "Syntax: FTP VDIRECTORY [ filespec ]",
8879 " Asks the server to send a directory listing of the files that match",
8880 " the given filespec, or if none is given, all the files in its current",
8881 " directory. VDIRECTORY is needed for getting verbose directory",
8882 " listings from certain FTP servers, such as on TOPS-20. Try it if",
8883 " FTP DIRECTORY lists only filenames without details.",
8886 static char * fhs_fea[] = { /* FEATURES */
8887 "Syntax: FTP FEATURES",
8888 " Asks the FTP server to list its special features. Most FTP servers",
8889 " do not recognize this command.",
8892 static char * fhs_mge[] = { /* MGET */
8893 "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8894 " Download a single file or multiple files. Asks the FTP server to send",
8895 " the given file or files. Also see FTP GET. Optional switches:",
8898 " Name under which to store incoming file.",
8899 " Pattern required for for multiple files.",
8900 " /BINARY", /* /IMAGE */
8901 " Force binary mode. Synonym: /IMAGE.",
8902 " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8903 " What to do if an incoming file has the same name as an existing file.",
8907 " Specifies that the as-name is a command to which the incoming file",
8908 " is to be piped as standard input.",
8909 #endif /* PUTPIPE */
8913 " Download only those files whose modification date-times differ from",
8914 " those of the corresponding local files, or that do not already",
8915 " exist on the local computer.",
8916 #endif /* DOUPDATE */
8919 " Specifies that each file is to be deleted from the server after,",
8920 " and only if, it is successfully downloaded.",
8921 " /ERROR-ACTION:{PROCEED,QUIT}",
8922 " When downloading a group of files, what to do upon failure to",
8923 " transfer a file: quit or proceed to the next one.",
8925 " Exception list: don't download any files that match this pattern.",
8926 " See HELP WILDCARD for pattern syntax.",
8927 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8928 " Whether to convert incoming filenames to local syntax.",
8932 " Pass incoming files through the given command.",
8934 #endif /* PIPESEND */
8935 " /LARGER-THAN:number",
8936 " Only download files that are larger than the given number of bytes.",
8937 " /LISTFILE:filename",
8938 " Obtain the list of files to download from the given file.",
8940 " /LOCAL-CHARACTER-SET:name",
8941 " When downloading in text mode and character-set conversion is",
8942 " desired, this specifies the target set.",
8943 #endif /* NOCSETS */
8945 " Specifies a pattern to be used to select filenames locally from the",
8948 " Forces sending of MLSD (rather than NLST) to get the file list.",
8950 " /MOVE-TO:directory",
8951 " Each file that is downloaded is to be moved to the given local",
8952 " directory immediately after, and only if, it has been received",
8954 #endif /* CK_TMPDIR */
8955 " /NAMELIST:filename",
8956 " Instead of downloading the files, stores the list of files that",
8957 " would be downloaded in the given local file, one filename per line.",
8959 " Forces sending of NLST (rather than MLSD) to get the file list.",
8961 " Don't download any files whose names end with .~<number>~.",
8963 " Don't download any files whose names begin with period (.).",
8965 " Suppress the file-transfer display.",
8967 " /RECOVER", /* /RESTART */
8968 " Resume a download that was previously interrupted from the point of",
8969 " failure. Works only in binary mode. Not supported by all servers.",
8970 " Synonym: /RESTART.",
8971 #endif /* FTP_RESTART */
8973 " /RECURSIVE", /* /SUBDIRECTORIES */
8974 " Create subdirectories automatically if the server sends files",
8975 " recursively and includes pathnames (most don't).",
8976 #endif /* RECURSIVE */
8978 " Each file that is downloaded is to be renamed as indicated just,",
8979 " after, and only if, it has arrived successfully.",
8981 " /SERVER-CHARACTER-SET:name",
8982 " When downloading in text mode and character-set conversion is desired"
8983 , " this specifies the original file's character set on the server.",
8984 #endif /* NOCSETS */
8985 " /SERVER-RENAME:text",
8986 " Each server source file is to be renamed on the server as indicated",
8987 " immediately after, but only if, it has arrived successfully.",
8988 " /SMALLER-THAN:number",
8989 " Download only those files smaller than the given number of bytes.",
8990 " /TEXT", /* /ASCII */
8991 " Force text mode. Synonym: /ASCII.",
8993 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8996 " When downloading in text mode, do not convert chracter-sets.",
8997 #endif /* NOCSETS */
8999 " The downloaded file is to be displayed on the screen.",
9002 " Equivalent to /COLLISION:UPDATE. Download only those files that are",
9003 " newer than than their local counterparts, or that do not exist on",
9004 " the local computer.",
9005 #endif /* DOUPDATE */
9008 static char * fhs_hlp[] = { /* HELP */
9009 "Syntax: FTP HELP [ command [ subcommand... ] ]",
9010 " Asks the FTP server for help about the given command. First use",
9011 " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
9012 " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
9015 static char * fhs_idl[] = { /* IDLE */
9016 "Syntax: FTP IDLE [ number ]",
9017 " If given without a number, this asks the FTP server to tell its",
9018 " current idle-time limit. If given with a number, it asks the server",
9019 " to change its idle-time limit to the given number of seconds.",
9022 static char * fhs_usr[] = { /* USER, LOGIN */
9023 "Syntax: FTP USER username [ password [ account ] ]",
9024 " Log in to the FTP server. To be used when connected but not yet",
9025 " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
9026 " If you omit the password, and one is required by the server, you are",
9027 " prompted for it. If you omit the account, no account is sent.",
9028 " Synonym: FTP LOGIN.",
9031 static char * fhs_get[] = { /* GET */
9032 "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
9033 " Download a single file. Asks the FTP server to send the given file.",
9034 " The optional as-name is the name to store it under when it arrives;",
9035 " if omitted, the file is stored with the name it arrived with, as",
9036 " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
9037 " value. Aside from the file list and as-name, syntax and options are",
9038 " the same as for FTP MGET, which is used for downloading multiple files."
9041 static char * fhs_mkd[] = { /* MKDIR */
9042 "Syntax: FTP MKDIR directory",
9043 " Asks the FTP server to create a directory with the given name,",
9044 " which must be in the syntax of the server's file system. Synonyms:",
9045 " REMOTE MKDIR, RMKDIR.",
9048 static char * fhs_mod[] = { /* MODTIME */
9049 "Syntax: FTP MODTIME filename",
9050 " Asks the FTP server to send the modification time of the given file,",
9051 " to be displayed on the screen. The date-time format is all numeric:",
9052 " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
9053 " fractions of seconds).",
9056 static char * fhs_mpu[] = { /* MPUT */
9057 "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
9058 " Uploads files. Sends the given file or files to the FTP server.",
9059 " Also see FTP PUT. Optional switches are:",
9061 " /AFTER:date-time",
9062 " Uploads only those files newer than the given date-time.",
9063 " HELP DATE for info about date-time formats. Synonym: /SINCE.",
9065 " /ARRAY:array-designator",
9066 " Tells Kermit to upload the contents of the given array, rather than",
9068 #endif /* PUTARRAY */
9070 " Name under which to send files.",
9071 " Pattern required for for multiple files.",
9072 " /BEFORE:date-time",
9073 " Upload only those files older than the given date-time.",
9075 " Force binary mode. Synonym: /IMAGE.",
9078 " Specifies that the filespec is a command whose standard output is",
9080 #endif /* PUTPIPE */
9085 " Upload only those files whose modification date-times differ from",
9086 " those on the server, or that don't exist on the server at all.",
9087 #endif /* DOUPDATE */
9088 #endif /* COMMENT */
9091 " Specifies that each source file is to be deleted after, and only if,",
9092 " it is successfully uploaded.",
9094 " Include files whose names begin with period (.).",
9095 " /ERROR-ACTION:{PROCEED,QUIT}",
9096 " When uploading a group of files, what to do upon failure to",
9097 " transfer a file: quit or proceed to the next one.",
9099 " Exception list: don't upload any files that match this pattern.",
9100 " See HELP WILDCARD for pattern syntax.",
9101 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
9102 " Whether to convert outbound filenames to common syntax.",
9106 " Pass outbound files through the given command.",
9108 #endif /* PIPESEND */
9111 " Send files that are pointed to by symbolic links.",
9113 " Skip over symbolic links (default).",
9114 #endif /* CKSYMLINK */
9115 " /LARGER-THAN:number",
9116 " Only upload files that are larger than the given number of bytes.",
9117 " /LISTFILE:filename",
9118 " Obtain the list of files to upload from the given file.",
9120 " /LOCAL-CHARACTER-SET:name",
9121 " When uploading in text mode and character-set conversion is",
9122 " desired, this specifies the source-file character set.",
9123 #endif /* NOCSETS */
9125 " /MOVE-TO:directory",
9126 " Each source file that is uploaded is to be moved to the given local",
9127 " directory when, and only if, the transfer is successful.",
9128 #endif /* CK_TMPDIR */
9130 " Don't upload any files whose names end with .~<number>~.",
9133 " Don't upload any files whose names begin with period (.).",
9134 #endif /* UNIXOROSK */
9135 " /NOT-AFTER:date-time",
9136 " Upload only files that are not newer than the given date-time",
9137 " /NOT-BEFORE:date-time",
9138 " Upload only files that are not older than the given date-time",
9141 " Ask the server to set the permissions of each file it receives",
9142 " according to the source file's permissions.",
9145 " Suppress the file-transfer display.",
9148 " Resume an upload that was previously interrupted from the point of",
9149 " failure. Synonym: /RESTART.",
9150 #endif /* FTP_RESTART */
9153 " Send files from the given directory and all the directories beneath",
9154 " it. Synonym: /SUBDIRECTORIES.",
9155 #endif /* RECURSIVE */
9157 " Each source file that is uploaded is to be renamed on the local",
9158 " local computer as indicated when and only if, the transfer completes",
9161 " /SERVER-CHARACTER-SET:name",
9162 " When uploading in text mode and character-set conversion is desired,",
9163 " this specifies the character set to which the file should be",
9164 " converted for storage on the server.",
9165 #endif /* NOCSETS */
9166 " /SERVER-RENAME:text",
9167 " Each file that is uploaded is to be renamed as indicated on the",
9168 " server after, and only if, if arrives successfully.",
9170 " Show which files would be sent without actually sending them.",
9171 " /SMALLER-THAN:number",
9172 " Upload only those files smaller than the given number of bytes.",
9174 " Force text mode. Synonym: /ASCII.",
9176 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
9179 " When uploading in text mode, do not convert chracter-sets.",
9180 #endif /* NOCSETS */
9181 " /TYPE:{TEXT,BINARY}",
9182 " Upload only files of the given type.",
9185 " If a file of the same name exists on the server, upload only if",
9186 " the local file is newer.",
9187 #endif /* DOUPDATE */
9188 " /UNIQUE-SERVER-NAMES",
9189 " Ask the server to compute new names for any incoming file that has",
9190 " the same name as an existing file.",
9193 static char * fhs_opn[] = { /* OPEN */
9195 "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
9196 " Opens a connection to the FTP server on the given host. The default",
9197 " TCP port is 21 (990 if SSL/TLS is used), but a different port number",
9198 " can be supplied if necessary. Optional switches are:",
9200 "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
9201 " Opens a connection to the FTP server on the given host. The default",
9202 " TCP port is 21, but a different port number can be supplied if",
9203 " necessary. Optional switches are:",
9207 " Logs you in anonymously.",
9209 " Supplies the given text as your username.",
9211 " Supplies the given text as your password. If you include a username",
9212 " but omit this switch and the server requires a password, you are",
9213 " prompted for it.",
9215 " Supplies the given text as your account, if required by the server.",
9217 " Forces an active (rather than passive) connection.",
9219 " Forces a passive (rather than active) connection.",
9221 " Inhibits sending initial REST, STRU, and MODE commands, which are",
9222 " well-known standard commands, but to which some servers react badly.",
9224 " Inhibits autologin for this connection only.",
9227 static char * fhs_opt[] = { /* OPTS, OPTIONS */
9228 "Syntax: FTP OPTIONS",
9229 " Asks the FTP server to list its current options. Advanced, new,",
9230 " not supported by most FTP servers.",
9233 static char * fhs_put[] = { /* PUT, SEND */
9234 "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
9235 " Like FTP MPUT, but only one filespec is allowed, and if it is followed",
9236 " by an additional field, this is interpreted as the name under which",
9237 " to send the file or files. See HELP FTP MPUT.",
9240 static char * fhs_reput[] = { /* REPUT, RESEND */
9241 "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
9242 " Synonym for FTP PUT /RECOVER. Recovers an interrupted binary-mode",
9243 " upload from the point of failure if the FTP server supports recovery.",
9244 " Synonym: [ FTP ] RESEND. For details see HELP FTP MPUT.",
9247 static char * fhs_pwd[] = { /* PWD */
9249 " Asks the FTP server to reveal its current working directory.",
9250 " Synonyms: REMOTE PWD, RPWD.",
9253 static char * fhs_quo[] = { /* QUOTE */
9254 "Syntax: FTP QUOTE text",
9255 " Sends an FTP protocol command to the FTP server. Use this command",
9256 " for sending commands that Kermit might not support.",
9259 static char * fhs_rge[] = { /* REGET */
9260 "Syntax: FTP REGET",
9261 " Synonym for FTP GET /RECOVER.",
9264 static char * fhs_ren[] = { /* RENAME */
9265 "Syntax: FTP RENAME name1 name1",
9266 " Asks the FTP server to change the name of the file whose name is name1",
9267 " and which resides in the FTP server's file system, to name2. Works",
9268 " only for single files; wildcards are not accepted.",
9271 static char * fhs_res[] = { /* RESET */
9272 "Syntax: FTP RESET",
9273 " Asks the server to log out your session, terminating your access",
9274 " rights, without closing the connection.",
9277 static char * fhs_rmd[] = { /* RMDIR */
9278 "Syntax: FTP RMDIR directory",
9279 " Asks the FTP server to remove the directory whose name is given.",
9280 " This usually requires the directory to be empty. Synonyms: REMOTE",
9284 static char * fhs_sit[] = { /* SITE */
9285 "Syntax: FTP SITE text",
9286 " Sends a site-specific command to the FTP server.",
9289 static char * fhs_siz[] = { /* SIZE */
9290 "Syntax: FTP SIZE filename",
9291 " Asks the FTP server to send a numeric string representing the size",
9292 " of the given file.",
9295 static char * fhs_sta[] = { /* STATUS */
9296 "Syntax: FTP STATUS [ filename ]",
9297 " Asks the FTP server to report its status. If a filename is given,",
9298 " the FTP server should report details about the file.",
9301 static char * fhs_sys[] = { /* SYSTEM */
9302 "Syntax: FTP SYSTEM",
9303 " Asks the FTP server to report its operating system type.",
9306 static char * fhs_typ[] = { /* TYPE */
9307 "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
9308 " Puts the client and server in the indicated transfer mode.",
9309 " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
9310 " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
9311 " downloading files from TENEX or TOPS-20 that have been uploaded in",
9315 static char * fhs_uma[] = { /* UMASK */
9316 "Syntax: FTP UMASK number",
9317 " Asks the FTP server to set its file creation mode mask. Applies",
9318 " only (or mainly) to UNIX-based FTP servers.",
9321 static char * fhs_chk[] = { /* CHECK */
9322 "Syntax: FTP CHECK remote-filespec",
9323 " Asks the FTP server if the given file or files exist. If the",
9324 " remote-filespec contains wildcards, this command fails if no server",
9325 " files match, and succeeds if at least one file matches. If the",
9326 " remote-filespec does not contain wildcards, this command succeeds if",
9327 " the given file exists and fails if it does not.",
9330 static char * fhs_ena[] = { /* ENABLE */
9331 "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9332 " Enables the use of the given FTP protocol command in case it has been",
9333 " disabled (but this is no guarantee that the FTP server understands it)."
9335 " Use SHOW FTP to see which of these commands is enabled and disabled.",
9336 " Also see FTP DISABLE.",
9339 static char * fhs_dis[] = { /* DISABLE */
9340 "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9341 " Disables the use of the given FTP protocol command.",
9342 " Also see FTP ENABLE.",
9351 if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
9354 if ((x = cmcfm()) < 0)
9358 printf("Sorry, no help available\n");
9362 return(hmsga(fhs_ftp));
9363 case FTP_ACC: /* ACCOUNT */
9364 return(hmsga(fhs_acc));
9365 case FTP_APP: /* APPEND */
9366 return(hmsga(fhs_app));
9367 case FTP_CLS: /* BYE, CLOSE */
9368 return(hmsga(fhs_cls));
9369 case FTP_CWD: /* CD, CWD */
9370 return(hmsga(fhs_cwd));
9371 case FTP_GUP: /* CDUP, UP */
9372 return(hmsga(fhs_gup));
9373 case FTP_CHM: /* CHMOD */
9374 return(hmsga(fhs_chm));
9375 case FTP_MDE: /* DELETE, MDELETE */
9376 return(hmsga(fhs_mde));
9377 case FTP_DIR: /* DIRECTORY */
9378 return(hmsga(fhs_dir));
9379 case FTP_VDI: /* VDIRECTORY */
9380 return(hmsga(fhs_vdi));
9381 case FTP_FEA: /* FEATURES */
9382 return(hmsga(fhs_fea));
9383 case FTP_GET: /* GET */
9384 return(hmsga(fhs_get));
9385 case FTP_HLP: /* HELP */
9386 return(hmsga(fhs_hlp));
9387 case FTP_IDL: /* IDLE */
9388 return(hmsga(fhs_idl));
9389 case FTP_USR: /* USER, LOGIN */
9390 return(hmsga(fhs_usr));
9391 case FTP_MGE: /* MGET */
9392 return(hmsga(fhs_mge));
9393 case FTP_MKD: /* MKDIR */
9394 return(hmsga(fhs_mkd));
9395 case FTP_MOD: /* MODTIME */
9396 return(hmsga(fhs_mod));
9397 case FTP_MPU: /* MPUT */
9398 return(hmsga(fhs_mpu));
9399 case FTP_OPN: /* OPEN */
9400 return(hmsga(fhs_opn));
9401 case FTP_OPT: /* OPTS, OPTIONS */
9402 return(hmsga(fhs_opt));
9403 case FTP_PUT: /* PUT, SEND */
9404 return(hmsga(fhs_put));
9405 case FTP_REP: /* REPUT, RESEND */
9406 return(hmsga(fhs_reput));
9407 case FTP_PWD: /* PWD */
9408 return(hmsga(fhs_pwd));
9409 case FTP_QUO: /* QUOTE */
9410 return(hmsga(fhs_quo));
9411 case FTP_RGE: /* REGET */
9412 return(hmsga(fhs_rge));
9413 case FTP_REN: /* RENAME */
9414 return(hmsga(fhs_ren));
9415 case FTP_RES: /* RESET */
9416 return(hmsga(fhs_res));
9417 case FTP_RMD: /* RMDIR */
9418 return(hmsga(fhs_rmd));
9419 case FTP_SIT: /* SITE */
9420 return(hmsga(fhs_sit));
9421 case FTP_SIZ: /* SIZE */
9422 return(hmsga(fhs_siz));
9423 case FTP_STA: /* STATUS */
9424 return(hmsga(fhs_sta));
9425 case FTP_SYS: /* SYSTEM */
9426 return(hmsga(fhs_sys));
9427 case FTP_TYP: /* TYPE */
9428 return(hmsga(fhs_typ));
9429 case FTP_UMA: /* UMASK */
9430 return(hmsga(fhs_uma));
9431 case FTP_CHK: /* CHECK */
9432 return(hmsga(fhs_chk));
9434 return(hmsga(fhs_ena));
9436 return(hmsga(fhs_dis));
9438 printf("Sorry, help available for this command.\n");
9442 return(success = 0);
9448 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9452 ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9453 if ((x = cmcfm()) < 0)
9457 printf("Sorry, no help available\n");
9461 printf("\nSyntax: SET FTP parameter value\n");
9462 printf(" Type \"help set ftp ?\" for a list of parameters.\n");
9463 printf(" Type \"help set ftp xxx\" for information about setting\n");
9464 printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
9468 printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9470 " Activates a workaround for the named bug in the FTP server.\n");
9471 printf(" Type SET FTP BUG ? for a list of names.\n");
9472 printf(" For each bug, the default is OFF\n\n");
9476 case FTS_ATP: /* "authtype" */
9477 printf("\nSyntax: SET FTP AUTHTYPE list\n");
9478 printf(" Specifies an ordered list of authentication methods to be\n"
9480 printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n");
9481 printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9484 case FTS_AUT: /* "autoauthentication" */
9485 printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9486 printf(" Tells whether authentication should be negotiated by the\n");
9487 printf(" FTP OPEN command. Default is ON.\n\n");
9490 case FTS_CRY: /* "autoencryption" */
9491 printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9492 printf(" Tells whether encryption (privacy) should be negotiated\n");
9493 printf(" by the FTP OPEN command. Default is ON.\n\n");
9495 #endif /* FTP_SECURITY */
9497 case FTS_LOG: /* "autologin" */
9498 printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9499 printf(" Tells Kermit whether to try to log you in automatically\n");
9500 printf(" as part of the connection process.\n\n");
9504 printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9505 printf(" Chooses the file-transfer display style for FTP.\n");
9506 printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9510 case FTS_XLA: /* "character-set-translation" */
9511 printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9512 printf(" Whether to translate character sets when transferring\n");
9513 printf(" text files with FTP. OFF by default.\n\n");
9516 #endif /* NOCSETS */
9517 case FTS_FNC: /* "collision" */
9520 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9522 printf(" Tells what do when an incoming file has the same name as\n");
9523 printf(" an existing file when downloading with FTP.\n\n");
9527 case FTS_CPL: /* "command-protection-level" */
9530 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9534 " Tells what level of protection is applied to the FTP command channel.\n\n");
9536 case FTS_CFW: /* "credential-forwarding" */
9537 printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9538 printf(" Tells whether end-user credentials are to be forwarded\n");
9539 printf(" to the server if supported by the authentication method\n");
9540 printf(" (GSSAPI-KRB5 only).\n\n");
9542 case FTS_DPL: /* "data-protection-level" */
9545 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9549 " Tells what level of protection is applied to the FTP data channel.\n\n");
9551 #endif /* FTP_SECURITY */
9553 case FTS_DBG: /* "debug" */
9554 printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9555 printf(" Whether to print FTP protocol messages.\n\n");
9558 case FTS_ERR: /* "error-action" */
9559 printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9560 printf(" What to do when an error occurs when transferring a group\n")
9562 printf(" of files: quit and fail, or proceed to the next file.\n\n");
9565 case FTS_CNV: /* "filenames" */
9566 printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9567 printf(" What to do with filenames: convert them, take and use them\n"
9569 printf(" literally; or choose what to do automatically based on the\n"
9571 printf(" OS type of the server. The default is AUTO.\n\n");
9574 case FTS_PSV: /* "passive-mode" */
9575 printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9576 printf(" Whether to use passive mode, which helps to get through\n");
9577 printf(" firewalls. ON by default.\n\n");
9580 case FTS_PRM: /* "permissions" */
9581 printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9582 printf(" Whether to try to send file permissions when uploading.\n");
9583 printf(" OFF by default. AUTO means only if client and server\n");
9584 printf(" have the same OS type.\n\n");
9587 case FTS_TST: /* "progress-messages" */
9588 printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9589 printf(" Whether Kermit should print locally-generated feedback\n");
9590 printf(" messages for each non-file-transfer command.");
9591 printf(" ON by default.\n\n");
9594 case FTS_SPC: /* "send-port-commands" */
9595 printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9596 printf(" Whether Kermit should send a new PORT command for each");
9597 printf(" task.\n\n");
9601 case FTS_CSR: /* "server-character-set" */
9602 printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9603 printf(" The name of the character set used for text files on the\n");
9604 printf(" server. Enter a name of '?' for a menu.\n\n");
9606 #endif /* NOCSETS */
9608 case FTS_STO: /* "server-time-offset */
9610 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9612 " Specifies an offset to apply to the server's file timestamps.\n");
9614 " Use this to correct for misconfigured server time or timezone.\n");
9616 " Format: must begin with + or - sign. Hours must be given; minutes\n");
9618 " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9621 case FTS_TYP: /* "type" */
9622 printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9623 printf(" Establishes the default transfer mode.\n");
9624 printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n");
9625 printf(" platforms such as TENEX and TOPS-20 and for downloading\n");
9626 printf(" them again. ASCII is a synonym for TEXT. Normally each\n");
9627 printf(" file's type is determined automatically from its contents\n"
9629 printf(" or its name; SET FTP TYPE does not prevent that, it only\n");
9630 printf(" tells which mode to use when the type can't be determined\n"
9632 printf(" automatically. To completely disable automatic transfer-\n"
9634 printf(" mode switching and force either text or binary mode, give\n"
9636 printf(" the top-level command ASCII or BINARY, as in traditional\n");
9637 printf(" FTP clients.\n\n");
9642 printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
9643 printf(" Establishes a timeout for FTP transfers.\n");
9644 printf(" The timeout applies per network read or write on the data\n");
9645 printf(" connection, not to the whole transfer. By default the\n");
9646 printf(" timeout value is 0, meaning no timeout. Use a positive\n");
9647 printf(" number to escape gracefully from hung data connections or\n");
9648 printf(" directory listings.\n\n");
9650 #endif /* FTP_TIMEOUT */
9654 printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9655 printf(" Tells whether GET and MGET should automatically switch\n");
9656 printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9657 printf(" matching the name of each incoming file with its list of\n");
9658 printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
9659 printf(" default. SHOW PATTERNS displays the current pattern\n");
9660 printf(" list. HELP SET FILE to see how to change it.\n");
9662 #endif /* PATTERNS */
9664 case FTS_USN: /* "unique-server-names" */
9665 printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9666 printf(" Tells whether to ask the server to create unique names\n");
9667 printf(" for any uploaded file that has the same name as an\n");
9668 printf(" existing file. Default is OFF.\n\n");
9671 case FTS_VBM: /* "verbose-mode" */
9672 printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9673 printf(" Whether to display all responses from the FTP server.\n");
9674 printf(" OFF by default.\n\n");
9678 printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9679 printf(" Whether to set date of incoming files from the file date\n");
9680 printf(" on the server. ON by default. Note: there is no way to\n")
9682 printf(" set the date on files uploaded to the server. Also note\n");
9683 printf(" that not all servers support this feature.\n\n");
9687 printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9688 printf(" Password to supply automatically on anonymous FTP\n");
9689 printf(" connections instead of the default user@host.\n");
9690 printf(" Omit optional text to restore default.\n\n");
9694 printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9708 char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
9711 #endif /* FTP_SRP */
9713 static int kerror; /* Needed for all auth types */
9715 static struct sockaddr_in hisctladdr;
9716 static struct sockaddr_in hisdataaddr;
9717 static struct sockaddr_in data_addr;
9718 static int data = -1;
9719 static int ptflag = 0;
9720 static struct sockaddr_in myctladdr;
9726 #endif /* COMMENT */
9729 static int cpend = 0; /* No pending replies */
9732 extern SSL *ssl_ftp_con;
9733 extern SSL_CTX *ssl_ftp_ctx;
9734 extern SSL *ssl_ftp_data_con;
9735 extern int ssl_ftp_active_flag;
9736 extern int ssl_ftp_data_active_flag;
9739 /* f t p c m d -- Send a command to the FTP server */
9742 char * cmd: The command to send.
9743 char * arg: The argument (e.g. a filename).
9744 int lcs: The local character set index.
9745 int rcs: The remote (server) character set index.
9746 int vbm: Verbose mode:
9747 0 = force verbosity off
9748 >0 = force verbosity on
9750 If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9751 and neither lcs or rcs is UCS-2, the arg is translated from the local
9752 character set to the remote one before sending the result to the server.
9755 0 on failure with ftpcode = -1
9756 >= 0 on success (getreply() result) with ftpcode = 0.
9758 static char xcmdbuf[RFNBUFSIZ];
9761 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9763 int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9766 if (ftp_deb) /* DEBUG */
9768 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
9770 else if (vbm < 0) /* VERBOSE */
9776 cmdlen = (int)strlen(cmd);
9777 len = cmdlen + (int)strlen(arg) + 1;
9779 if (ftp_deb /* && !dpyactive */ ) {
9781 if (ftp_prx) printf("%s ", ftp_host);
9782 #endif /* FTP_PROXY */
9784 if (!anonymous && strcmp("PASS",cmd) == 0)
9785 printf("PASS XXXX");
9787 printf("%s %s",cmd,arg);
9790 /* bzero(xcmdbuf,RFNBUFSIZ); */
9791 ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9795 debug(F110,"ftpcmd cmd",cmd,0);
9796 debug(F110,"ftpcmd arg",arg,0);
9797 debug(F101,"ftpcmd lcs","",lcs);
9798 debug(F101,"ftpcmd rcs","",rcs);
9802 if (csocket == -1) {
9803 perror("No control connection for command");
9808 oldintr = signal(SIGINT, cmdcancel);
9811 if (*arg && /* If an arg was given */
9812 lcs > -1 && /* and a local charset */
9813 rcs > -1 && /* and a remote charset */
9814 lcs != rcs && /* and the two are not the same */
9815 lcs != FC_UCS2 && /* and neither one is UCS-2 */
9816 rcs != FC_UCS2 /* ... */
9818 initxlate(lcs,rcs); /* Translate arg from lcs to rcs */
9819 xgnbp = arg; /* Global pointer to input string */
9820 rfnptr = rfnbuf; /* Global pointer to output buffer */
9823 if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9824 if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9827 We have to copy here instead of translating directly into
9828 xcmdbuf[] so strputc() can check length. Alternatively we could
9829 write yet another xpnbyte() output function.
9831 if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9832 printf("?FTP command too long: %s + arg\n",cmd);
9836 x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9838 #endif /* NOCSETS */
9840 s = xcmdbuf; /* Command to send to server */
9843 if (deblog) { /* Log it */
9844 if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9845 /* But don't log passwords */
9846 debug(F110,"FTP SENT ","PASS XXXX",0);
9848 debug(F110,"FTP SENT ",s,0);
9853 #ifdef CK_ENCRYPTION
9855 #endif /* CK_ENCRYPTION */
9856 if (scommand(s) == 0) { /* Send it. */
9857 signal(SIGINT, oldintr);
9861 x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */
9862 if (x) /* In case we're interrupted */
9863 connected = 0; /* while waiting for the reply... */
9865 fc = 0; /* Function code for getreply() */
9866 if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */
9868 && strncmp(cmd, "HOST ",5)
9869 #endif /* FTPHOST */
9872 } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9873 fc = GRF_FEAT; /* But FEAT not widely understood */
9874 if (!ftp_deb) /* So suppress error messages */
9877 r = getreply(x, /* Expect connection to close */
9878 lcs,rcs, /* Charsets */
9879 vbm, /* Verbosity */
9880 fc /* Function code */
9885 #ifdef CK_ENCRYPTION
9886 if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9888 "ENC command not supported at server; retrying under MIC...\n");
9892 #endif /* CK_ENCRYPTION */
9894 if (cancelfile && oldintr != SIG_IGN)
9896 #endif /* COMMENT */
9897 signal(SIGINT, oldintr);
9903 debug(F100,"lostpeer","",0);
9905 if (csocket != -1) {
9907 if (ssl_ftp_active_flag) {
9908 SSL_shutdown(ssl_ftp_con);
9909 SSL_free(ssl_ftp_con);
9911 ssl_ftp_active_flag = 0;
9916 socket_close(csocket);
9917 #else /* TCPIPLIB */
9919 shutdown(csocket, 1+1);
9920 #endif /* USE_SHUTDOWN */
9922 #endif /* TCPIPLIB */
9927 if (ssl_ftp_data_active_flag) {
9928 SSL_shutdown(ssl_ftp_data_con);
9929 SSL_free(ssl_ftp_data_con);
9930 ssl_ftp_data_active_flag = 0;
9931 ssl_ftp_data_con = NULL;
9936 #else /* TCPIPLIB */
9938 shutdown(data, 1+1);
9939 #endif /* USE_SHUTDOWN */
9941 #endif /* TCPIPLIB */
9949 ftp_cpl = ftp_dpl = FPL_CLR;
9952 #endif /* CKLOGDIAL */
9955 if (autolocus) /* Auotomatic locus switching... */
9956 setlocus(1,1); /* Switch locus to local. */
9959 DialerSend(OPT_KERMIT_HANGUP, 0);
9965 if (csocket != -1) {
9967 socket_close(csocket);
9968 #else /* TCPIPLIB */
9970 shutdown(csocket, 1+1);
9971 #endif /* USE_SHUTDOWN */
9973 #endif /* TCPIPLIB */
9980 ftp_cpl = ftp_dpl = FPL_CLR;
9984 #endif /* FTP_PROXY */
9994 extern int quitting;
9997 ftp_xfermode = xfermode;
9998 if (!ftp_vbm && !quiet)
10000 ftpcmd("QUIT",NULL,0,0,ftp_vbm);
10003 if (ssl_ftp_active_flag) {
10004 SSL_shutdown(ssl_ftp_con);
10005 SSL_free(ssl_ftp_con);
10007 ssl_ftp_active_flag = 0;
10008 ssl_ftp_con = NULL;
10010 #endif /* CK_SSL */
10012 socket_close(csocket);
10013 #else /* TCPIPLIB */
10014 #ifdef USE_SHUTDOWN
10015 shutdown(csocket, 1+1);
10016 #endif /* USE_SHUTDOWN */
10018 #endif /* TCPIPLIB */
10034 #endif /* FTP_PROXY */
10039 #endif /* CKLOGDIAL */
10041 /* Unprefixed file management commands are executed locally */
10042 if (autolocus && !ftp_cmdlin && !quitting) {
10047 DialerSend(OPT_KERMIT_HANGUP, 0);
10053 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
10057 printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
10063 #endif /* FTPHOST */
10065 ftp_srvtyp[0] = NUL;
10066 if (!service) service = "";
10067 if (!*service) service = use_tls ? "ftps" : "ftp";
10069 if (!isdigit(service[0])) {
10070 struct servent *destsp;
10071 destsp = getservbyname(service, "tcp");
10073 if (!ckstrcmp(service,"ftp",-1,0)) {
10075 } else if (!ckstrcmp(service,"ftps",-1,0)) {
10078 printf("?Bad port name - \"%s\"\n", service);
10083 ftp_port = destsp->s_port;
10084 ftp_port = ntohs((unsigned short)ftp_port); /* SMS 2007/02/15 */
10087 ftp_port = atoi(service);
10088 if (ftp_port <= 0) {
10089 printf("?Bad port name - \"%s\"\n", service);
10093 host = ftp_hookup(remote, ftp_port, use_tls);
10095 ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
10096 connected = 1; /* Set FTP defaults */
10097 ftp_cpl = ftp_dpl = FPL_CLR;
10098 curtype = FTT_ASC; /* Server uses ASCII mode */
10102 strcpy(bytename, "8");
10105 #ifdef FTP_SECURITY
10110 && ck_crypt_is_installed()
10114 printf("FTP Command channel is Private (encrypted)\n");
10116 if (setpbsz(DEFAULT_PBSZ) < 0) {
10117 /* a failure here is most likely caused by a mixup */
10118 /* in the session key used by client and server */
10119 printf("?Protection buffer size negotiation failed\n");
10122 if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
10124 printf("FTP Data channel is Private (encrypted)\n");
10127 printf("?Unable to enable encryption on data channel\n");
10135 #endif /* FTP_SECURITY */
10136 if (ftp_log) /* ^^^ */
10142 ftp_xfermode = xfermode;
10146 #endif /* CKLOGDIAL */
10148 DialerSend(OPT_KERMIT_CONNECT, 0);
10150 passivemode = ftp_psv;
10151 sendport = ftp_spc;
10157 if (ucbuf == NULL) {
10158 actualbuf = DEFAULT_PBSZ;
10159 while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
10163 ucbufsiz = actualbuf - FUDGE_FACTOR;
10164 debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
10168 printf("?Can't FTP connect to %s:%s\n",remote,service);
10178 CONST SSL_METHOD *client_method;
10180 if (ssl_debug_flag) {
10181 fprintf(stderr,"SSL DEBUG ACTIVE\n");
10183 /* for the moment I want the output on screen */
10185 if (ssl_ftp_data_con != NULL) {
10186 SSL_free(ssl_ftp_data_con);
10187 ssl_ftp_data_con = NULL;
10189 if (ssl_ftp_con != NULL) {
10190 SSL_free(ssl_ftp_con);
10193 if (ssl_ftp_ctx != NULL) {
10194 SSL_CTX_free(ssl_ftp_ctx);
10195 ssl_ftp_ctx = NULL;
10198 /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10199 * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous
10202 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10203 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
10206 Pick allowed SSL/TLS versions according to enabled bugs.
10207 Modified 5 Feb 2015 to default to TLS 1.0 if no bugs are enabled,
10208 instead of to SSL 3.0, which has the POODLE vulnerability.
10210 if (ftp_bug_use_ssl_v2) {
10211 /* allow SSL 2.0 or later */
10212 client_method = SSLv23_client_method();
10213 #ifndef DISABLE_SSLV3
10214 } else if (ftp_bug_use_ssl_v3) {
10215 /* allow SSL 3.0 ONLY - previous default */
10216 client_method = SSLv3_client_method();
10217 #endif /* DISABLE_SSLV3 */
10219 /* default - allow TLS 1.0 or later */
10220 client_method = TLSv1_client_method();
10222 if (auth_type && !strcmp(auth_type,"TLS")) {
10223 ssl_ftp_ctx=SSL_CTX_new(client_method);
10226 SSL_CTX_set_options(ssl_ftp_ctx,
10227 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10228 #ifdef DISABLE_SSLV3
10229 |SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3
10230 #endif /* DISABLE_SSLV3 */
10233 ssl_ftp_ctx = SSL_CTX_new(client_method);
10236 SSL_CTX_set_options(ssl_ftp_ctx,
10237 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10238 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10239 #ifdef DISABLE_SSLV3
10240 |SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3
10241 #endif /* DISABLE_SSLV3 */
10244 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10245 (pem_password_cb *)ssl_passwd_callback);
10246 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10247 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10251 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10253 char path[CKMAXPATH];
10254 extern char exedir[];
10256 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10257 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10258 debug(F110,"ftp ssl_auth unable to load path",path,0);
10259 if (ssl_debug_flag)
10260 printf("?Unable to load verify-dir: %s\r\n",path);
10263 ckmakmsg(path,CKMAXPATH,
10264 (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
10265 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10266 debug(F110,"ftp ssl_auth unable to load path",path,0);
10267 if (ssl_debug_flag)
10268 printf("?Unable to load verify-dir: %s\r\n",path);
10271 ckmakmsg(path,CKMAXPATH,
10272 (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
10273 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10274 debug(F110,"ftp ssl_auth unable to load path",path,0);
10275 if (ssl_debug_flag)
10276 printf("?Unable to load verify-dir: %s\r\n",path);
10279 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10280 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10281 debug(F110,"ftp ssl_auth unable to load path",path,0);
10282 if (ssl_debug_flag)
10283 printf("?Unable to load verify-file: %s\r\n",path);
10286 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10287 "kermit 95/ca_certs.pem",NULL,NULL);
10288 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10289 debug(F110,"ftp ssl_auth unable to load path",path,0);
10290 if (ssl_debug_flag)
10291 printf("?Unable to load verify-file: %s\r\n",path);
10294 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10295 "kermit 95/ca_certs.pem",NULL,NULL);
10296 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10297 debug(F110,"ftp ssl_auth unable to load path",path,0);
10298 if (ssl_debug_flag)
10299 printf("?Unable to load verify-file: %s\r\n",path);
10303 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10306 char path[CKMAXPATH];
10307 extern char exedir[];
10309 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10310 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10311 debug(F110,"ftp ssl_auth unable to load path",path,0);
10312 if (ssl_debug_flag)
10313 printf("?Unable to load verify-dir: %s\r\n",path);
10315 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10316 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10317 debug(F110,"ftp ssl_auth unable to load path",path,0);
10318 if (ssl_debug_flag)
10319 printf("?Unable to load verify-file: %s\r\n",path);
10324 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10327 if (ssl_verify_file &&
10328 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10330 "ftp ssl auth unable to load ssl_verify_file",
10334 if (ssl_debug_flag)
10335 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10337 if (ssl_verify_dir &&
10338 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10340 "ftp ssl auth unable to load ssl_verify_dir",
10344 if (ssl_debug_flag)
10345 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10348 /* set up the new CRL Store */
10349 crl_store = (X509_STORE *)X509_STORE_new();
10352 char path[CKMAXPATH];
10353 extern char exedir[];
10355 ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
10356 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10357 debug(F110,"ftp ssl auth unable to load dir",path,0);
10358 if (ssl_debug_flag)
10359 printf("?Unable to load crl-dir: %s\r\n",path);
10362 ckmakmsg(path,CKMAXPATH,
10363 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
10364 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10365 debug(F110,"ftp ssl auth unable to load dir",path,0);
10366 if (ssl_debug_flag)
10367 printf("?Unable to load crl-dir: %s\r\n",path);
10369 ckmakmsg(path,CKMAXPATH,
10370 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10371 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10372 debug(F110,"ftp ssl auth unable to load dir",path,0);
10373 if (ssl_debug_flag)
10374 printf("?Unable to load crl-dir: %s\r\n",path);
10378 ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
10379 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10380 debug(F110,"ftp ssl auth unable to load file",path,0);
10381 if (ssl_debug_flag)
10382 printf("?Unable to load crl-file: %s\r\n",path);
10385 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10386 "kermit 95/ca_crls.pem",NULL,NULL);
10387 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10388 debug(F110,"ftp ssl auth unable to load file",path,0);
10389 if (ssl_debug_flag)
10390 printf("?Unable to load crl-file: %s\r\n",path);
10392 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10393 "kermit 95/ca_crls.pem",NULL,NULL);
10394 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10395 debug(F110,"ftp ssl auth unable to load file",path,0);
10396 if (ssl_debug_flag)
10397 printf("?Unable to load crl-file: %s\r\n",path);
10402 if (ssl_crl_file || ssl_crl_dir) {
10403 if (ssl_crl_file &&
10404 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10406 "ftp ssl auth unable to load ssl_crl_file",
10410 if (ssl_debug_flag)
10411 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10414 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10416 "ftp ssl auth unable to load ssl_crl_dir",
10420 if (ssl_debug_flag)
10421 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10424 X509_STORE_set_default_paths(crl_store);
10427 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10428 ssl_client_verify_callback);
10429 ssl_verify_depth = -1;
10430 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10431 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10432 SSL_set_fd(ssl_ftp_con,csocket);
10433 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10434 if (ssl_cipher_list) {
10435 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10438 if (p = getenv("SSL_CIPHER")) {
10439 SSL_set_cipher_list(ssl_ftp_con,p);
10441 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10444 if (ssl_debug_flag) {
10445 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10448 if (SSL_connect(ssl_ftp_con) <= 0) {
10449 static char errbuf[1024];
10450 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10451 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10452 fprintf(stderr,"%s\n", errbuf);
10454 ssl_ftp_active_flag=0;
10455 SSL_free(ssl_ftp_con);
10456 ssl_ftp_con = NULL;
10458 ssl_ftp_active_flag = 1;
10460 if (!ssl_certsok_flag &&
10461 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
10463 char *subject = ssl_get_subject_name(ssl_ftp_con);
10466 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10467 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10468 return(ssl_ftp_active_flag = 0);
10470 if (uq_ok("Warning: Server didn't provide a certificate\n",
10471 "Continue? (Y/N)",3,NULL,0) <= 0) {
10472 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10473 return(ssl_ftp_active_flag = 0);
10476 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10477 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10478 return(ssl_ftp_active_flag = 0);
10481 debug(F110,"ssl_auth","[SSL - OK]",0);
10482 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10484 if (ssl_debug_flag) {
10485 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10488 return(ssl_ftp_active_flag);
10490 #endif /* CK_SSL */
10493 cmdcancel(sig) int sig; {
10495 /* In Unix we "chain" to trap(), which prints this */
10498 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10500 secure_getc(0,1); /* Initialize net input buffers */
10506 if (ptflag) /* proxy... */
10507 longjmp(ptcancel,1);
10508 #endif /* FTP_PROXY */
10509 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10512 debug(F100,"ftp cmdcancel return from trap()...","",0);
10514 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10521 scommand(char * s) /* Was secure_command() */
10523 scommand(s) char * s;
10524 #endif /* CK_ANSIC */
10526 int length = 0, len2;
10527 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10529 if (ssl_ftp_active_flag) {
10531 length = strlen(s) + 2;
10532 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10533 rc = SSL_write(ssl_ftp_con,out,length);
10534 error = SSL_get_error(ssl_ftp_con,rc);
10536 case SSL_ERROR_NONE:
10538 case SSL_ERROR_WANT_WRITE:
10539 case SSL_ERROR_WANT_READ:
10540 case SSL_ERROR_SYSCALL:
10543 int gle = GetLastError();
10546 case SSL_ERROR_WANT_X509_LOOKUP:
10547 case SSL_ERROR_SSL:
10548 case SSL_ERROR_ZERO_RETURN:
10554 #endif /* CK_SSL */
10556 if (auth_type && ftp_cpl != FPL_CLR) {
10558 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10559 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10563 fprintf(stderr, "SRP failed to encode message\n");
10566 #endif /* FTP_SRP */
10568 if (ck_krb4_is_installed() &&
10569 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10570 if (ftp_cpl == FPL_PRV) {
10572 krb_mk_priv((CHAR *)s, (CHAR *)out,
10573 strlen(s), ftp_sched,
10578 #endif /* KRB524 */
10579 &myctladdr, &hisctladdr);
10582 krb_mk_safe((CHAR *)s,
10589 #endif /* KRB524 */
10590 &myctladdr, &hisctladdr);
10592 if (length == -1) {
10593 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10594 ftp_cpl == FPL_PRV ? "priv" : "safe");
10598 #endif /* FTP_KRB4 */
10600 /* Scommand (based on level) */
10601 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10602 gss_buffer_desc in_buf, out_buf;
10603 OM_uint32 maj_stat, min_stat;
10606 in_buf.length = strlen(s) + 1;
10607 maj_stat = gss_seal(&min_stat, gcontext,
10608 (ftp_cpl==FPL_PRV), /* private */
10610 &in_buf, &conf_state,
10612 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10613 user_gss_error(maj_stat, min_stat,
10614 (ftp_cpl==FPL_PRV)?
10615 "gss_seal ENC didn't complete":
10616 "gss_seal MIC didn't complete");
10617 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10618 fprintf(stderr, "GSSAPI didn't encrypt message");
10621 fprintf(stderr, "sealed (%s) %d bytes\n",
10622 ftp_cpl==FPL_PRV?"ENC":"MIC",
10624 memcpy(out, out_buf.value,
10625 length=out_buf.length);
10626 gss_release_buffer(&min_stat, &out_buf);
10629 #endif /* FTP_GSSAPI */
10630 /* Other auth types go here ... */
10633 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10634 length, &len2, RADIX_ENCODE))
10636 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10637 radix_error(kerror));
10641 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10642 len2 = ckmakmsg(out,
10644 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10649 send(csocket,(SENDARG2TYPE)out,len2,0);
10651 char out[FTP_BUFSIZ];
10652 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10653 send(csocket,(SENDARG2TYPE)out,len,0);
10660 static char inbuf[4096];
10661 static int bp = 0, ep = 0;
10667 if (ssl_ftp_active_flag) {
10669 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10670 error = SSL_get_error(ssl_ftp_con,rc);
10672 case SSL_ERROR_NONE:
10674 case SSL_ERROR_WANT_WRITE:
10675 case SSL_ERROR_WANT_READ:
10677 case SSL_ERROR_SYSCALL:
10678 if (rc == 0) { /* EOF */
10682 int gle = GetLastError();
10686 case SSL_ERROR_WANT_X509_LOOKUP:
10687 case SSL_ERROR_SSL:
10688 case SSL_ERROR_ZERO_RETURN:
10693 #endif /* CK_SSL */
10694 rc = recv(csocket,(char *)inbuf,4096,0);
10699 return(inbuf[bp++]);
10702 /* x l a t e c -- Translate a character */
10705 fc = Function code: 0 = translate, 1 = initialize.
10706 c = Character (as int).
10707 incs = Index of charset to translate from.
10708 outcs = Index of charset to translate to.
10715 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10719 static char buf[128];
10723 if (fc == 1) { /* Initialize */
10724 cx = 0; /* Catch-up buffer write index */
10725 xgnbp = buf; /* Catch-up buffer read pointer */
10726 buf[0] = NUL; /* Buffer is empty */
10729 if (cx >= 127) { /* Catch-up buffer full */
10730 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10731 printf("?Translation buffer overflow\n");
10734 /* Add char to buffer. */
10735 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10737 debug(F000,"xlatec buf",ckitoa(cx),c);
10741 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10742 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10745 /* If we're caught up, reinitialize the buffer */
10746 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10747 #endif /* NOCSETS */
10751 /* p a r s e f e a t */
10753 /* Note: for convenience we align keyword values with table indices */
10754 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10756 static struct keytab feattab[] = {
10757 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10758 { "AUTH", SFT_AUTH, 0 },
10759 { "LANG", SFT_LANG, 0 },
10760 { "MDTM", SFT_MDTM, 0 },
10761 { "MLST", SFT_MLST, 0 },
10762 { "PBSZ", SFT_PBSZ, 0 },
10763 { "PROT", SFT_PROT, 0 },
10764 { "REST", SFT_REST, 0 },
10765 { "SIZE", SFT_SIZE, 0 },
10766 { "TVFS", SFT_TVFS, 0 },
10767 { "UTF8", SFT_UTF8, 0 }
10769 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10771 #define FACT_CSET 1
10772 #define FACT_CREA 2
10773 #define FACT_LANG 3
10774 #define FACT_MTYP 4
10775 #define FACT_MDTM 5
10776 #define FACT_PERM 6
10777 #define FACT_SIZE 7
10778 #define FACT_TYPE 8
10779 #define FACT_UNIQ 9
10781 static struct keytab facttab[] = {
10782 { "CHARSET", FACT_CSET, 0 },
10783 { "CREATE", FACT_CREA, 0 },
10784 { "LANG", FACT_LANG, 0 },
10785 { "MEDIA-TYPE", FACT_MTYP, 0 },
10786 { "MODIFY", FACT_MDTM, 0 },
10787 { "PERM", FACT_PERM, 0 },
10788 { "SIZE", FACT_SIZE, 0 },
10789 { "TYPE", FACT_TYPE, 0 },
10790 { "UNIQUE", FACT_UNIQ, 0 }
10792 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10794 static struct keytab ftyptab[] = {
10795 { "CDIR", FTYP_CDIR, 0 },
10796 { "DIR", FTYP_DIR, 0 },
10797 { "FILE", FTYP_FILE, 0 },
10798 { "PDIR", FTYP_PDIR, 0 }
10800 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10803 parsefeat(s) char * s; { /* Parse a FEATURE response */
10810 for (i = 0; i < 4; i++) {
10815 if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10818 /* xlookup requires a full (but case independent) match */
10819 i = xlookup(feattab,kwbuf,nfeattab,&x);
10820 debug(F111,"ftp parsefeat",s,i);
10821 if (i < 0 || i > 15)
10825 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10826 sfttab[i] = mdtmok;
10827 if (mdtmok) sfttab[0]++;
10829 case SFT_MLST: /* ditto */
10830 sfttab[i] = mlstok;
10831 if (mlstok) sfttab[0]++;
10833 case SFT_SIZE: /* ditto */
10834 sfttab[i] = sizeok;
10835 if (sizeok) sfttab[0]++;
10837 case SFT_AUTH: /* ditto */
10838 sfttab[i] = ftp_aut;
10839 if (ftp_aut) sfttab[0]++;
10841 default: /* Others */
10848 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10851 if (!s) return(NULL);
10852 if (!*s) return(NULL);
10854 /* Maybe we should make a copy of s so we can poke it... */
10856 while ((p = ckstrchr(s,'='))) {
10857 *p = NUL; /* s points to fact */
10858 i = xlookup(facttab,s,nfacttab,&x);
10859 debug(F111,"ftp parsefact fact",s,i);
10861 s = p+1; /* Now s points to arg */
10862 p = ckstrchr(s,';');
10864 p = ckstrchr(s,SP);
10866 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10870 debug(F110,"ftp parsefact valu",s,0);
10872 case FACT_CSET: /* Ignore these for now */
10879 case FACT_MDTM: /* Modtime */
10880 makestr(&havemdtm,s);
10881 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10883 case FACT_SIZE: /* Size */
10884 havesize = ckatofs(s);
10885 debug(F101,"ftp parsefact size","",havesize);
10887 case FACT_TYPE: /* Type */
10888 j = xlookup(ftyptab,s,nftyptab,NULL);
10889 debug(F111,"ftp parsefact type",s,j);
10890 havetype = (j < 1) ? 0 : j;
10894 s = p+1; /* s points next fact or name */
10896 while (*s == SP) /* Skip past spaces. */
10898 if (!*s) /* Make sure we still have a name */
10900 debug(F110,"ftp parsefact name",s,0);
10904 /* g e t r e p l y -- (to an FTP command sent to server) */
10906 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10909 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10910 /* lcs, rcs, vbm parameters as in ftpcmd() */
10911 register int i, c, n;
10917 int originalcode = 0, continuation = 0;
10921 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10925 auth = (fc == GRF_AUTH);
10928 debug(F101,"ftp getreply lcs","",lcs);
10929 debug(F101,"ftp getreply rcs","",rcs);
10930 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10932 initxlate(rcs,lcs);
10933 xlatec(1,0,rcs,lcs);
10935 #endif /* NOCSETS */
10936 debug(F101,"ftp getreply fc","",fc);
10944 if (ftp_deb) /* DEBUG */
10946 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10948 else if (vbm < 0) /* VERBOSE */
10953 reply_ptr = reply_buf;
10955 oldintr = signal(SIGINT, cmdcancel);
10956 for (count = 0;; count++) {
10958 dig = n = ftpcode = i = 0;
10959 cp = ftp_reply_str;
10960 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10961 if (c == IAC) { /* Handle telnet commands */
10962 switch (c = mygetc()) {
10971 if (ssl_ftp_active_flag) {
10973 rc = SSL_write(ssl_ftp_con,obuf,3);
10974 error = SSL_get_error(ssl_ftp_con,rc);
10976 case SSL_ERROR_NONE:
10978 case SSL_ERROR_WANT_WRITE:
10979 case SSL_ERROR_WANT_READ:
10981 case SSL_ERROR_SYSCALL:
10982 if (rc == 0) { /* EOF */
10986 int gle = GetLastError();
10990 case SSL_ERROR_WANT_X509_LOOKUP:
10991 case SSL_ERROR_SSL:
10992 case SSL_ERROR_ZERO_RETURN:
10997 #endif /* CK_SSL */
10998 send(csocket,(SENDARG2TYPE)obuf,3,0);
11008 if (ssl_ftp_active_flag) {
11010 rc = SSL_write(ssl_ftp_con,obuf,3);
11011 error = SSL_get_error(ssl_ftp_con,rc);
11013 case SSL_ERROR_NONE:
11015 case SSL_ERROR_WANT_WRITE:
11016 case SSL_ERROR_WANT_READ:
11017 signal(SIGINT,oldintr);
11019 case SSL_ERROR_SYSCALL:
11020 if (rc == 0) { /* EOF */
11024 int gle = GetLastError();
11028 case SSL_ERROR_WANT_X509_LOOKUP:
11029 case SSL_ERROR_SSL:
11030 case SSL_ERROR_ZERO_RETURN:
11035 #endif /* CK_SSL */
11036 send(csocket,(SENDARG2TYPE)obuf,3,0);
11046 signal(SIGINT,oldintr);
11048 debug(F101,"ftp getreply EOF","",ftpcode);
11056 "Service not available, connection closed by server\n");
11059 signal(SIGINT,oldintr);
11061 debug(F101,"ftp getreply EOF","",ftpcode);
11064 if (n == 0) { /* First digit */
11065 n = c; /* Save it */
11069 !ssl_ftp_active_flag &&
11070 #endif /* CK_SSL */
11071 !ibuf[0] && (n == '6' || continuation)) {
11072 if (c != '\r' && dig > 4)
11077 !ssl_ftp_active_flag &&
11078 #endif /* CK_SSL */
11079 !ibuf[0] && dig == 1 && vbm)
11080 printf("Unauthenticated reply received from server:\n");
11085 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11088 (ftp_deb || ((vbm || (!auth && n == '5')) &&
11089 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11093 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11094 printf("%s:",ftp_host);
11095 #endif /* FTP_PROXY */
11102 xlatec(0,c,rcs,lcs);
11106 #endif /* NOCSETS */
11113 !ssl_ftp_active_flag &&
11114 #endif /* CK_SSL */
11115 !ibuf[0] && n != '6')
11117 if (dig < 4 && isdigit(c))
11118 ftpcode = ftpcode * 10 + (c - '0');
11119 if (!pflag && ftpcode == 227)
11121 if (dig > 4 && pflag == 1 && isdigit(c))
11124 if (c != '\r' && c != ')')
11131 if (dig == 4 && c == '-' && n != '6') {
11136 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11144 Sometimes we need to print the server reply. printlines is nonzero for any
11145 command where the results are sent back on the control connection rather
11146 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
11147 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
11148 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
11149 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11150 lines from UNIX. Further experimentation needed with other servers. Of
11151 course RFC959 is mute as to the format of the server reply.
11153 'printlines' is also true for PWD and BYE.
11155 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11157 /* No, we can't be that clever -- it breaks other things like RPWD... */
11159 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11160 #endif /* COMMENT */
11163 char *r = ftp_reply_str;
11164 *q-- = NUL; /* NUL-terminate */
11165 while (*q < '!' && q > r) /* Strip CR, etc */
11167 if (!ftp_deb && printlines) { /* If printing */
11168 if (ftpcode != 0) /* strip ftpcode if any */
11171 printf("%s\n",r); /* and print */
11175 } else { /* Translating */
11176 xgnbp = r; /* Set up strgetc() */
11177 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11178 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
11179 signal(SIGINT,oldintr);
11185 #endif /* NOCSETS */
11188 debug(F110,"FTP RCVD ",ftp_reply_str,0);
11190 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
11191 if (count == 0 && n == '2') {
11192 int i; /* (Re)-init server FEATure table */
11193 debug(F100,"ftp getreply clearing feature table","",0);
11194 for (i = 0; i < 16; i++)
11197 parsefeat((char *)ftp_reply_str);
11202 !ssl_ftp_active_flag &&
11203 #endif /* CK_SSL */
11204 !ibuf[0] && n != '6') {
11205 signal(SIGINT,oldintr);
11206 return(getreply(expecteof,lcs,rcs,vbm,auth));
11208 ibuf[0] = obuf[i] = '\0';
11209 if (ftpcode && n == '6')
11210 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11211 printf("Unknown reply: %d %s\n", ftpcode, obuf);
11213 } else safe = (ftpcode == 631);
11214 if (obuf[0] /* if there is a string to decode */
11216 && !ssl_ftp_active_flag /* and not SSL/TLS */
11217 #endif /* CK_SSL */
11220 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11223 #ifndef CK_ENCRYPTION
11224 else if (ftpcode == 632) {
11225 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11228 #endif /* CK_ENCRYPTION */
11229 #ifdef NOCONFIDENTIAL
11230 else if (ftpcode == 633) {
11231 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11234 #endif /* NOCONFIDENTIAL */
11236 int len = FTP_BUFSIZ;
11237 if ((kerror = radix_encode((CHAR *)obuf,
11243 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11244 ftpcode, radix_error(kerror), obuf);
11248 else if (strcmp(auth_type, "SRP") == 0) {
11250 outlen = srp_decode(!safe, (CHAR *)ibuf,
11251 (CHAR *) ibuf, len);
11253 printf("Warning: %d reply %s!\n",
11254 ftpcode, safe ? "modified" : "garbled");
11257 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11259 printf("%c:", safe ? 'S' : 'P');
11263 #endif /* FTP_SRP */
11265 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11267 kerror = krb_rd_safe((CHAR *)ibuf, len,
11272 #endif /* KRB524 */
11278 kerror = krb_rd_priv((CHAR *)ibuf, len,
11284 #endif /* KRB524 */
11290 if (kerror != KSUCCESS) {
11291 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11292 safe ? "modified" : "garbled",
11293 safe ? "safe" : "priv",
11294 krb_get_err_text(kerror));
11296 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11299 printf("reply data too large for buffer\n");
11302 printf("%c:", safe ? 'S' : 'P');
11303 memcpy(ibuf,ftp_msg_data.app_data,
11304 ftp_msg_data.app_length);
11305 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11306 FTP_BUFSIZ - ftp_msg_data.app_length);
11310 #endif /* FTP_KRB4 */
11312 else if (strcmp(auth_type, "GSSAPI") == 0) {
11313 gss_buffer_desc xmit_buf, msg_buf;
11314 OM_uint32 maj_stat, min_stat;
11316 xmit_buf.value = ibuf;
11317 xmit_buf.length = len;
11318 /* decrypt/verify the message */
11320 maj_stat = gss_unseal(&min_stat, gcontext,
11321 &xmit_buf, &msg_buf,
11322 &conf_state, NULL);
11323 if (maj_stat != GSS_S_COMPLETE) {
11324 user_gss_error(maj_stat, min_stat,
11325 "failed unsealing reply");
11328 memcpy(ibuf, msg_buf.value, msg_buf.length);
11329 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11330 FTP_BUFSIZ-msg_buf.length);
11331 gss_release_buffer(&min_stat,&msg_buf);
11333 printf("%c:", safe ? 'S' : 'P');
11337 #endif /* FTP_GSSAPI */
11338 /* Other auth types go here... */
11340 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11341 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11346 xlatec(0,c,rcs,lcs);
11350 #endif /* NOCSETS */
11353 if (continuation && ftpcode != originalcode) {
11354 if (originalcode == 0)
11355 originalcode = ftpcode;
11361 signal(SIGINT,oldintr);
11362 if (ftpcode == 421 || originalcode == 421) {
11364 if (!xquiet && !ftp_deb)
11365 printf("%s\n",reply_buf);
11367 if ((cancelfile != 0) &&
11369 /* Ultrix 3.0 cc objects violently to this clause */
11370 (oldintr != cmdcancel) &&
11371 #endif /* ULTRIX3 */
11372 (oldintr != SIG_IGN)) {
11374 (*oldintr)(SIGINT);
11378 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11379 reply_parse = reply_ptr + strlen(reply_parse);
11380 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11383 reply_parse = reply_ptr;
11385 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11387 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11395 empty(fd_set * mask, int sec)
11397 empty(mask, sec) fd_set * mask; int sec;
11398 #endif /* CK_ANSIC */
11401 t.tv_sec = (long) sec;
11403 debug(F100,"ftp empty calling select...","",0);
11405 x = select(32, (int *)mask, NULL, NULL, &t);
11407 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11408 #endif /* INTSELECT */
11409 debug(F101,"ftp empty select","",x);
11412 #else /* BSDSELECT */
11415 empty(mask, cnt, sec) int * mask, sec;
11418 return(select(mask,cnt,0,0,sec*1000));
11420 #endif /* IBMSELECT */
11421 #endif /* BSDSELECT */
11424 cancelsend(sig) int sig; {
11428 printf(" Canceled...\n");
11429 secure_getc(0,1); /* Initialize net input buffers */
11430 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11433 longjmp(sendcancel, 1);
11441 secure_error(char *fmt, ...)
11444 secure_error(fmt, p1, p2, p3, p4, p5)
11445 char *fmt; int p1, p2, p3, p4, p5;
11446 #endif /* CK_ANSIC */
11452 vfprintf(stderr, fmt, ap);
11455 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11457 fprintf(stderr, "\n");
11461 * Internal form of settype; changes current type in use with server
11462 * without changing our notion of the type for data transfers.
11463 * Used to change to and from ascii for listings.
11466 changetype(newtype, show) int newtype, show; {
11470 if ((newtype == curtype) && typesent++)
11486 rc = ftpcmd("TYPE",s,-1,-1,show);
11487 if (rc == REPLY_COMPLETE)
11491 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11495 doftpsend(void * threadinfo)
11497 doftpsend(threadinfo) VOID * threadinfo;
11501 if (threadinfo) { /* Thread local storage... */
11502 TlsSetValue(TlsIndex,threadinfo);
11503 debug(F100, "doftpsend called with threadinfo block","", 0);
11504 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11513 #endif /* CK_LOGIN */
11518 /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11520 /* If the connection failed and we are using an HTTP Proxy
11521 * and the reason for the failure was an authentication
11522 * error, then we need to give the user to ability to
11523 * enter a username and password, just like a browser.
11525 * I tried to do all of this within the netopen() call
11526 * but it is much too much work.
11528 while (y != 0 && tcp_http_proxy != NULL ) {
11530 if (tcp_http_proxy_errno == 401 ||
11531 tcp_http_proxy_errno == 407 ) {
11532 char uid[UIDBUFLEN];
11534 struct txtbox tb[2];
11538 tb[0].t_len = UIDBUFLEN;
11539 tb[0].t_lbl = "Proxy Userid: ";
11540 tb[0].t_dflt = NULL;
11544 tb[1].t_lbl = "Proxy Passphrase: ";
11545 tb[1].t_dflt = NULL;
11548 ok = uq_mtxt("Proxy Server Authentication Required\n",
11550 if (ok && uid[0]) {
11551 char * proxy_user, * proxy_pwd;
11553 proxy_user = tcp_http_proxy_user;
11554 proxy_pwd = tcp_http_proxy_pwd;
11556 tcp_http_proxy_user = uid;
11557 tcp_http_proxy_pwd = pwd;
11561 debug(F101,"doftpsend","initconn",y);
11562 memset(pwd,0,PWDSIZ);
11563 tcp_http_proxy_user = proxy_user;
11564 tcp_http_proxy_pwd = proxy_pwd;
11572 #endif /* NOHTTP */
11573 signal(SIGINT, ftpsnd.oldintr);
11575 if (ftpsnd.oldintp)
11576 signal(SIGPIPE, ftpsnd.oldintp);
11577 #endif /* SIGPIPE */
11582 ckThreadEnd(threadinfo);
11587 #endif /* NOHTTP */
11591 ckThreadEnd(threadinfo);
11597 failftpsend(void * threadinfo)
11599 failftpsend(threadinfo) VOID * threadinfo;
11600 #endif /* CK_ANSIC */
11603 if (threadinfo) { /* Thread local storage... */
11604 TlsSetValue(TlsIndex,threadinfo);
11605 debug(F100, "docmdfile called with threadinfo block","", 0);
11606 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11615 #endif /* CK_LOGIN */
11618 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11619 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11623 if (ssl_ftp_data_active_flag) {
11624 SSL_shutdown(ssl_ftp_data_con);
11625 SSL_free(ssl_ftp_data_con);
11626 ssl_ftp_data_active_flag = 0;
11627 ssl_ftp_data_con = NULL;
11629 #endif /* CK_SSL */
11631 socket_close(data);
11632 #else /* TCPIPLIB */
11633 #ifdef USE_SHUTDOWN
11634 shutdown(data, 1+1);
11635 #endif /* USE_SHUTDOWN */
11637 #endif /* TCPIPLIB */
11641 if (ftpsnd.oldintr)
11642 signal(SIGINT,ftpsnd.oldintr);
11644 if (ftpsnd.oldintp)
11645 signal(SIGPIPE,ftpsnd.oldintp);
11646 #endif /* SIGPIPE */
11649 /* TEST ME IN K95 */
11652 debug(F100,"ftp failftpsend chain to trap()...","",0);
11653 if (ftpsnd.oldintr != SIG_IGN)
11654 (*ftpsnd.oldintr)(SIGINT);
11655 /* NOTREACHED (I hope!) */
11656 debug(F100,"ftp failftpsend return from trap()...","",0);
11663 failftpsend2(void * threadinfo)
11665 failftpsend2(threadinfo) VOID * threadinfo;
11666 #endif /* CK_ANSIC */
11669 if (threadinfo) { /* Thread local storage... */
11670 TlsSetValue(TlsIndex,threadinfo);
11671 debug(F100, "docmdfile called with threadinfo block","", 0);
11672 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11681 #endif /* CK_LOGIN */
11683 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11686 fpfsecs = gftimer();
11687 #endif /* GFTIMER */
11692 #endif /* PIPESEND */
11693 signal(SIGINT, ftpsnd.oldintr);
11695 if (ftpsnd.oldintp)
11696 signal(SIGPIPE, ftpsnd.oldintp);
11697 #endif /* SIGPIPE */
11702 ckThreadEnd(threadinfo);
11708 if (ssl_ftp_data_active_flag) {
11709 SSL_shutdown(ssl_ftp_data_con);
11710 SSL_free(ssl_ftp_data_con);
11711 ssl_ftp_data_active_flag = 0;
11712 ssl_ftp_data_con = NULL;
11714 #endif /* CK_SSL */
11716 socket_close(data);
11717 #else /* TCPIPLIB */
11718 #ifdef USE_SHUTDOWN
11719 shutdown(data, 1+1);
11720 #endif /* USE_SHUTDOWN */
11722 #endif /* TCPIPLIB */
11728 socket_close(dout);
11729 #else /* TCPIPLIB */
11730 #ifdef USE_SHUTDOWN
11731 shutdown(dout, 1+1);
11732 #endif /* USE_SHUTDOWN */
11734 #endif /* TCPIPLIB */
11736 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11741 /* TEST ME IN K95 */
11744 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11745 if (ftpsnd.oldintr != SIG_IGN)
11746 (*ftpsnd.oldintr)(SIGINT);
11747 /* NOTREACHED (I hope!) */
11748 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11755 doftpsend2(void * threadinfo)
11757 doftpsend2(threadinfo) VOID * threadinfo;
11760 register int c, d = 0;
11761 int n, t, x, notafile, unique = 0;
11765 if (threadinfo) { /* Thread local storage... */
11766 TlsSetValue(TlsIndex,threadinfo);
11767 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11768 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11777 #endif /* CK_LOGIN */
11779 buf = ftpsndbuf; /* (not on stack) */
11781 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11782 notafile = sndarray || pipesend;
11785 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11787 changetype(FTT_BIN,0); /* Change to binary */
11789 /* Ask for remote file's size */
11790 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11792 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11793 p = &ftp_reply_str[4]; /* Parse it */
11794 while (isdigit(*p)) {
11795 sendstart = sendstart * 10 + (int)(*p - '0');
11798 if (*p && *p != CR) { /* Bad number */
11799 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11800 sendstart = (CK_OFF_T)0;
11801 } else if (sendstart > fsize) { /* Remote file bigger than local */
11802 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11803 sendstart = (CK_OFF_T)0;
11805 /* Local is newer */
11806 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11807 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11808 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11809 sendstart = (CK_OFF_T)0; /* Send the whole file */
11812 changetype(ftp_typ,0); /* Change back to appropriate type */
11813 if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
11814 if (sendstart == fsize) { /* Same size - no need to send */
11815 debug(F111,"doftpsend2 /restart SKIP",
11816 ckfstoa(fsize),sendstart);
11818 ftpsndret = SKP_RES;
11820 ckThreadEnd(threadinfo);
11824 errno = 0; /* Restart needed, seek to the spot */
11825 if (zfseek((long)sendstart) < 0) {
11826 debug(F111,"doftpsend2 zfseek fails",
11827 ftpsnd.local,sendstart);
11828 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11833 ckThreadEnd(threadinfo);
11838 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11839 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11840 if (x != REPLY_CONTINUE) {
11845 ckThreadEnd(threadinfo);
11849 ftpsnd.cmd = "STOR";
11852 sendmode = SM_RESEND;
11853 ftpsnd.cmd = "APPE";
11854 #endif /* COMMENT */
11855 /* sendstart = (CK_OFF_T)0; */
11858 #endif /* FTP_RESTART */
11860 if (unique && !stouarg) /* If we know STOU accepts no arg */
11861 ftpsnd.remote = NULL; /* don't include one. */
11863 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11864 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11865 debug(F101,"doftpsend2 ftpcmd","",x);
11867 if (x != REPLY_PRELIM && unique) {
11869 RFC959 says STOU does not take an argument. But every FTP server
11870 I've encountered but one accepts the arg and constructs the unique
11871 name from it, which is better than making up a totally random name
11872 for the file, which is what RFC959 calls for. Especially because
11873 there is no way for the client to find out the name chosen by the
11874 server. So we try STOU with the argument first, which works with
11875 most servers, and if it fails we retry it without the arg, for
11876 the benefit of the one picky server that is not "liberal in what
11877 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11878 which means STOU is not accepted, period.
11880 if ((x == 5) && stouarg && (ftpcode != 502)) {
11881 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11882 if (x == REPLY_PRELIM) /* If accepted */
11883 stouarg = 0; /* flag no STOU arg for this server */
11886 if (x != REPLY_PRELIM) {
11887 signal(SIGINT, ftpsnd.oldintr);
11889 if (ftpsnd.oldintp)
11890 signal(SIGPIPE, ftpsnd.oldintp);
11891 #endif /* SIGPIPE */
11892 debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11897 #endif /* PIPESEND */
11900 ckThreadEnd(threadinfo);
11904 debug(F100,"doftpsend2 getting data connection...","",0);
11905 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11906 debug(F101,"doftpsend2 dataconn","",dout);
11908 failftpsend2(threadinfo);
11910 ckThreadEnd(threadinfo);
11914 /* Initialize per-file stats */
11915 ffc = (CK_OFF_T)0; /* Character counter */
11916 cps = oldcps = 0L; /* Thruput */
11919 rftimer(); /* reset f.p. timer */
11920 #endif /* GFTIMER */
11923 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11924 #endif /* SIGPIPE */
11925 debug(F101,"doftpsend2 curtype","",curtype);
11927 case FTT_BIN: /* Binary mode */
11932 This is because VMS zxin() is C-Library fread()
11933 but the file was opened with zopeni(), which is RMS.
11935 while (((c = zminchar()) > -1) && !cancelfile) {
11937 if (zzout(dout,c) < 0)
11941 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11944 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11945 ckhexdump("doftpsend2 zxin",buf,16);
11947 if (ssl_ftp_data_active_flag) {
11948 for (bufp = buf; n > 0; n -= d, bufp += d) {
11949 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11953 if (fdispla != XYFD_B) {
11955 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11959 #endif /* CK_SSL */
11960 for (bufp = buf; n > 0; n -= d, bufp += d) {
11961 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11966 if (fdispla != XYFD_B) {
11968 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11973 #endif /* CK_SSL */
11979 debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11981 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11982 if (d < 0 || (d = secure_flush(dout)) < 0) {
11983 if (d == -1 && errno && errno != EPIPE)
11989 case FTT_ASC: /* Text mode */
11991 if (ftpsnd.xlate) { /* With translation */
11992 initxlate(ftpsnd.incs,ftpsnd.outcs);
11993 while (!cancelfile) {
11994 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11995 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11998 #endif /* NOCSETS */
11999 /* Text mode, no translation */
12000 while (((c = zminchar()) > -1) && !cancelfile) {
12008 #endif /* NOCSETS */
12009 if (dout == -1 || (d = secure_flush(dout)) < 0) {
12010 if (d == -1 && errno && errno != EPIPE)
12016 tfc += ffc; /* Total file chars */
12018 fpfsecs = gftimer();
12019 #endif /* GFTIMER */
12020 zclose(ZIFILE); /* Close input file */
12022 if (sndfilter) /* Undo this (it's per file) */
12024 #endif /* PIPESEND */
12027 if (ssl_ftp_data_active_flag) {
12028 SSL_shutdown(ssl_ftp_data_con);
12029 SSL_free(ssl_ftp_data_con);
12030 ssl_ftp_data_active_flag = 0;
12031 ssl_ftp_data_con = NULL;
12033 #endif /* CK_SSL */
12036 socket_close(dout); /* Close data connection */
12037 #else /* TCPIPLIB */
12038 #ifdef USE_SHUTDOWN
12039 shutdown(dout, 1+1);
12040 #endif /* USE_SHUTDOWN */
12042 #endif /* TCPIPLIB */
12043 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12044 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
12046 if (ftpsnd.oldintp)
12047 signal(SIGPIPE, ftpsnd.oldintp);
12048 #endif /* SIGPIPE */
12049 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12050 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12053 ckThreadEnd(threadinfo);
12056 } else if (cancelfile) {
12057 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12060 ckThreadEnd(threadinfo);
12064 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12067 ckThreadEnd(threadinfo);
12072 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12073 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12075 if (!remote) remote = ""; /* Check args */
12076 if (!*remote) remote = local;
12077 if (!local) local = "";
12078 if (!*local) return(-1);
12079 if (!cmd) cmd = "";
12080 if (!*cmd) cmd = "STOR";
12082 debug(F111,"ftp sendrequest restart",local,restart);
12084 nout = 0; /* Init output buffer count */
12085 ftpsnd.bytes = 0; /* File input byte count */
12090 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12093 #endif /* FTP_PROXY */
12095 changetype(ftp_typ,0); /* Change type for this file */
12097 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
12098 ftpsnd.oldintp = NULL;
12099 ftpsnd.restart = restart;
12100 ftpsnd.xlate = xlate;
12101 ftpsnd.lmode = "wb";
12103 #ifdef PIPESEND /* Use Kermit API for file i/o... */
12105 char * p = NULL, * q;
12108 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12110 debug(F110,"sendrequest pipesend filter",sndfilter,0);
12111 zzstring(sndfilter,&p,&n);
12112 debug(F111,"sendrequest pipename",q,n);
12114 printf("?Sorry, send filter + filename too long, %d max.\n",
12120 ckstrncpy(filnam,q,CKMAXPATH+1);
12127 if (sndfilter) /* If sending thru a filter */
12128 pipesend = 1; /* set this for open and i/o */
12129 #endif /* PIPESEND */
12132 debug(F101,"XXX before openi binary","",binary);
12133 debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12136 if (openi(local) == 0) /* Try to open the input file */
12140 debug(F101,"XXX after openi binary","",binary);
12141 debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12143 if (binary != ftp_typ) { /* VMS zopeni() sets binary */
12144 debug(F101,"XXX changing type","",binary);
12146 debug(F101,"XXX after doftptyp","",ftp_typ);
12149 if (displa && fdispla) { /* Update file type display */
12150 ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12156 ftpsnd.incs = incs;
12157 ftpsnd.outcs = outcs;
12159 ftpsnd.local = local;
12160 ftpsnd.remote = remote;
12161 ftpsnd.oldintr = signal(SIGINT, cancelsend);
12164 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12168 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12175 cancelrecv(sig) int sig; {
12179 secure_getc(0,1); /* Initialize net input buffers */
12180 printf(" Canceling...\n");
12181 debug(F100,"ftp cancelrecv caught SIGINT","",0);
12184 if (fp_nml != stdout)
12189 longjmp(recvcancel, 1);
12195 /* Argumentless front-end for secure_getc() */
12199 return(secure_getc(globaldin,0));
12202 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12205 Sets ftpcode < 0 on failure if failure reason is not server reply code:
12206 -1: interrupted by user.
12207 -2: error opening or writing output file (reason in errno).
12208 -3: failure to make data connection.
12209 -4: network read error (reason in errno).
12212 struct xx_ftprecv {
12220 sig_t oldintr, oldintp;
12227 CK_OFF_T localsize;
12229 static struct xx_ftprecv ftprecv;
12231 static int ftprecvret = 0;
12235 failftprecv(VOID * threadinfo)
12237 failftprecv(threadinfo) VOID * threadinfo;
12238 #endif /* CK_ANSIC */
12241 if (threadinfo) { /* Thread local storage... */
12242 TlsSetValue(TlsIndex,threadinfo);
12243 debug(F100, "docmdfile called with threadinfo block","", 0);
12244 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12254 #endif /* CK_LOGIN */
12257 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12261 if (ssl_ftp_data_active_flag) {
12262 SSL_shutdown(ssl_ftp_data_con);
12263 SSL_free(ssl_ftp_data_con);
12264 ssl_ftp_data_active_flag = 0;
12265 ssl_ftp_data_con = NULL;
12267 #endif /* CK_SSL */
12269 socket_close(data);
12270 #else /* TCPIPLIB */
12271 #ifdef USE_SHUTDOWN
12272 shutdown(data, 1+1);
12273 #endif /* USE_SHUTDOWN */
12275 #endif /* TCPIPLIB */
12279 if (ftprecv.oldintr)
12280 signal(SIGINT, ftprecv.oldintr);
12285 /* TEST ME IN K95 */
12288 debug(F100,"ftp failftprecv chain to trap()...","",0);
12289 if (ftprecv.oldintr != SIG_IGN)
12290 (*ftprecv.oldintr)(SIGINT);
12291 /* NOTREACHED (I hope!) */
12292 debug(F100,"ftp failftprecv return from trap()...","",0);
12300 doftprecv(VOID * threadinfo)
12302 doftprecv(threadinfo) VOID * threadinfo;
12303 #endif /* CK_ANSIC */
12306 if (threadinfo) { /* Thread local storage... */
12307 TlsSetValue(TlsIndex,threadinfo);
12308 debug(F100, "docmdfile called with threadinfo block","", 0);
12309 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12318 #endif /* CK_LOGIN */
12321 if (!out2screen && !ftprecv.pipename) {
12324 local = ftprecv.local;
12327 if ((!dpyactive || ftp_deb))
12329 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12330 signal(SIGINT, ftprecv.oldintr);
12334 ckThreadEnd(threadinfo);
12339 #endif /* COMMENT */
12340 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12341 if (initconn()) { /* Initialize the data connection */
12342 signal(SIGINT, ftprecv.oldintr);
12346 ckThreadEnd(threadinfo);
12350 secure_getc(0,1); /* Initialize net input buffers */
12354 ckThreadEnd(threadinfo);
12360 failftprecv2(VOID * threadinfo)
12362 failftprecv2(threadinfo) VOID * threadinfo;
12363 #endif /* CK_ANSIC */
12366 if (threadinfo) { /* Thread local storage... */
12367 TlsSetValue(TlsIndex,threadinfo);
12368 debug(F100, "docmdfile called with threadinfo block","", 0);
12369 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12378 #endif /* CK_LOGIN */
12380 /* Cancel using RFC959 recommended IP,SYNC sequence */
12382 debug(F100,"ftp recvrequest CANCEL","",0);
12384 fpfsecs = gftimer();
12385 #endif /* GFTIMER */
12387 if (ftprecv.oldintp)
12388 signal(SIGPIPE, ftprecv.oldintr);
12389 #endif /* SIGPIPE */
12390 signal(SIGINT, SIG_IGN);
12393 signal(SIGINT, ftprecv.oldintr);
12396 ckThreadEnd(threadinfo);
12400 cancel_remote(ftprecv.din);
12403 if (ftp_timed_out && out2screen && !quiet)
12404 printf("\n?Timed out.\n");
12405 #endif /* FTP_TIMEOUT */
12411 if (ssl_ftp_data_active_flag) {
12412 SSL_shutdown(ssl_ftp_data_con);
12413 SSL_free(ssl_ftp_data_con);
12414 ssl_ftp_data_active_flag = 0;
12415 ssl_ftp_data_con = NULL;
12417 #endif /* CK_SSL */
12419 socket_close(data);
12420 #else /* TCPIPLIB */
12421 #ifdef USE_SHUTDOWN
12422 shutdown(data, 1+1);
12423 #endif /* USE_SHUTDOWN */
12425 #endif /* TCPIPLIB */
12431 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12433 switch (keep) { /* which is... */
12434 case SET_AUTO: /* AUTO */
12435 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12438 case SET_OFF: /* DISCARD */
12439 x = 1; /* Delete file, period. */
12441 default: /* KEEP */
12445 x = zdelet(ftprecv.local);
12446 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12451 socket_close(ftprecv.din);
12452 #else /* TCPIPLIB */
12453 #ifdef USE_SHUTDOWN
12454 shutdown(ftprecv.din, 1+1);
12455 #endif /* USE_SHUTDOWN */
12456 close(ftprecv.din);
12457 #endif /* TCPIPLIB */
12459 signal(SIGINT, ftprecv.oldintr);
12464 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12466 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12469 if (ftprecv.oldintr != SIG_IGN)
12470 (*ftprecv.oldintr)(SIGINT);
12471 /* NOTREACHED (I hope!) */
12472 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12479 doftprecv2(VOID * threadinfo)
12481 doftprecv2(threadinfo) VOID * threadinfo;
12482 #endif /* CK_ANSIC */
12485 CK_OFF_T bytes = (CK_OFF_T)0;
12488 ULONG start = 0L, stop;
12490 static char * rcvbuf = NULL;
12491 static int rcvbufsiz = 0;
12493 char newname[CKMAXPATH+1]; /* For file dialog */
12494 #endif /* CK_URL */
12495 extern int adl_ask;
12499 #endif /* FTP_TIMEOUT */
12503 if (threadinfo) { /* Thread local storage... */
12504 TlsSetValue(TlsIndex,threadinfo);
12505 debug(F100, "docmdfile called with threadinfo block","", 0);
12506 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12515 #endif /* CK_LOGIN */
12517 if (ftprecv.recover) { /* Initiate recovery */
12518 x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12519 debug(F111,"ftp reply","REST",x);
12520 if (x == REPLY_CONTINUE) {
12521 ftprecv.lmode = "ab";
12522 rs_len = ftprecv.localsize;
12524 ftprecv.recover = 0;
12527 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12529 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12531 /* Send the command and get reply */
12532 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12533 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12535 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12537 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12538 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12540 ckThreadEnd(threadinfo);
12544 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12545 globaldin = ftprecv.din; /* Global copy of file descriptor */
12546 if (ftprecv.din == -1) { /* Check for failure */
12547 ftpcode = -3; /* Code for no data connection */
12550 ckThreadEnd(threadinfo);
12555 /* In K95 GUI put up a file box */
12556 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12559 "\r\nIncoming file from FTP server...\r\n\
12560 Please confirm output file specification or supply an alternative:";
12562 x = uq_file(preface, /* K95 GUI: Put up file box. */
12566 ftprecv.local ? ftprecv.local : ftprecv.remote,
12571 ftprecv.local = newname; /* Substitute user's file name */
12572 if (x == 2) /* And append if user said to */
12573 ftprecv.lmode = "ab";
12576 #endif /* CK_URL */
12577 x = 1; /* Output file open OK? */
12578 if (ftprecv.pipename) { /* Command */
12579 x = zxcmd(ZOFILE,ftprecv.pipename);
12580 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12581 } else if (!out2screen) { /* File */
12583 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12584 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12585 /* Append or New */
12586 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12587 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12588 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12590 if (x < 1) { /* Failure to open output file */
12591 if ((!dpyactive || ftp_deb))
12592 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12595 ckThreadEnd(threadinfo);
12599 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12601 debug(F101,"ftp recvrequest blksize","",blksize);
12602 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12604 if (rcvbufsiz < blksize) { /* if necessary */
12609 rcvbuf = (char *)malloc((unsigned)blksize);
12611 debug(F100,"ftp get rcvbuf malloc failed","",0);
12615 #endif /* ENOMEM */
12616 if ((!dpyactive || ftp_deb))
12621 ckThreadEnd(threadinfo);
12625 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12626 rcvbufsiz = blksize;
12628 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12630 ffc = (CK_OFF_T)0; /* Character counter */
12631 cps = oldcps = 0L; /* Thruput */
12632 start = gmstimer(); /* Start time (msecs) */
12634 rftimer(); /* Start time (float) */
12635 #endif /* GFTIMER */
12637 debug(F111,"ftp get type",ftprecv.local,curtype);
12638 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12640 case FTT_BIN: /* Binary mode */
12641 case FTT_TEN: /* TENEX mode */
12645 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12647 failftprecv2(threadinfo);
12649 ckThreadEnd(threadinfo);
12655 #ifdef printf /* (What if it isn't?) */
12656 if (out2screen && !ftprecv.pipename) {
12658 for (i = 0; i < c; i++)
12659 printf("%c",rcvbuf[i]);
12661 #endif /* printf */
12667 if (zmchout(rcvbuf[i++]) < 0) {
12678 debug(F100,"ftp recvrequest timeout","",0);
12679 bytes = (CK_OFF_T)-1;
12683 #endif /* FTP_TIMEOUT */
12685 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12686 if (c == -1 && errno != EPIPE)
12687 if ((!dpyactive || ftp_deb))
12689 bytes = (CK_OFF_T)-1;
12694 if ((!dpyactive || ftp_deb)) {
12696 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12699 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12702 "%s: short write\n", ftprecv.local);
12707 case FTT_ASC: /* Text mode */
12708 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12710 if (ftprecv.xlate) {
12716 #endif /* CK_ANSIC */
12717 debug(F110,"ftp recvrequest (data)","initxlate",0);
12718 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12719 if (ftprecv.pipename) {
12721 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12723 fn = out2screen ? scrnout : putfil;
12724 debug(F110,"ftp recvrequest ASCII",
12725 out2screen ? "scrnout" : "putfil",0);
12728 /* Get byte from net */
12729 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12731 failftprecv2(threadinfo);
12733 ckThreadEnd(threadinfo);
12739 /* Second byte from net */
12740 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12742 failftprecv2(threadinfo);
12744 ckThreadEnd(threadinfo);
12751 /* K95: Check whether we need this */
12752 if (fileorder > 0) /* Little Endian */
12753 bytswap(&c0,&c1); /* swap bytes*/
12754 #endif /* COMMENT */
12757 if ( out2screen && /* we're translating to UCS-2 */
12758 !k95stdout && !inserver) /* for the real screen... */
12765 output.bytes[0] = c1;
12766 output.bytes[1] = c0;
12768 VscrnWrtUCS2StrAtt(VCMD,
12779 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12780 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12784 #endif /* NOCSETS */
12786 c = secure_getc(ftprecv.din,0);
12790 #endif /* FTP_TIMEOUT */
12792 failftprecv2(threadinfo);
12794 ckThreadEnd(threadinfo);
12798 if (c < 0 || c == EOF)
12801 /* Record format conversion for Unix */
12802 /* SKIP THIS FOR WINDOWS! */
12805 while (c == '\r') {
12807 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12810 failftprecv2(threadinfo);
12812 ckThreadEnd(threadinfo);
12816 if (c < 0 || c == EOF)
12828 if (out2screen && !ftprecv.pipename)
12830 printf("%c",(char)c);
12833 #endif /* printf */
12835 if ((d = zmchout(c)) < 0)
12843 if (bare_lfs && (!dpyactive || ftp_deb)) {
12844 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12846 printf("File might not have transferred correctly.\n");
12848 if (ftprecv.din == -1) {
12849 bytes = (CK_OFF_T)-1;
12852 bytes = (CK_OFF_T)-1;
12856 #endif /* NOCSETS */
12858 if (ftprecv.pipename || !out2screen) {
12859 zclose(ZOFILE); /* Close the file */
12860 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12861 if (ftpcode < 0) { /* If download failed */
12863 switch (keep) { /* which is... */
12864 case SET_AUTO: /* AUTO */
12865 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12868 case SET_OFF: /* DISCARD */
12869 x = 1; /* Delete file, period. */
12871 default: /* KEEP */
12875 x = zdelet(ftprecv.local);
12876 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12880 signal(SIGINT, ftprecv.oldintr);
12882 if (ftprecv.oldintp)
12883 signal(SIGPIPE, ftprecv.oldintp);
12884 #endif /* SIGPIPE */
12887 fpfsecs = gftimer();
12888 #endif /* GFTIMER */
12892 socket_close(ftprecv.din);
12893 #else /* TCPIPLIB */
12894 #ifdef USE_SHUTDOWN
12895 shutdown(ftprecv.din, 1+1);
12896 #endif /* USE_SHUTDOWN */
12897 close(ftprecv.din);
12898 #endif /* TCPIPLIB */
12899 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12900 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12901 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12903 ckThreadEnd(threadinfo);
12908 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12910 char *cmd, *local, *remote, *lmode, *pipename;
12911 int printnames, recover, xlate, fcs, rcs;
12914 struct _stat stbuf;
12921 debug(F111,"ftp recvrequest cmd",cmd,recover);
12922 debug(F110,"ftp recvrequest local ",local,0);
12923 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12924 debug(F110,"ftp recvrequest pipename ",pipename,0);
12925 debug(F101,"ftp recvrequest xlate","",xlate);
12926 debug(F101,"ftp recvrequest fcs","",fcs);
12927 debug(F101,"ftp recvrequest rcs","",rcs);
12931 ftprecv.localsize = (CK_OFF_T)0;
12933 if (remfile) { /* See remcfm(), remtxt() */
12935 pipename = remdest;
12938 if (remappd) lmode = "ab";
12942 if (!cmd) cmd = ""; /* Core dump prevention */
12943 if (!remote) remote = "";
12944 if (!lmode) lmode = "";
12946 if (pipename) { /* No recovery for pipes. */
12951 if (!local) /* Output to screen? */
12953 out2screen = !strcmp(local,"-");
12955 debug(F101,"ftp recvrequest out2screen","",out2screen);
12958 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12962 if (out2screen) /* No recovery to screen */
12964 if (!ftp_typ) /* No recovery in text mode */
12966 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12968 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12972 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12973 if (recursive && ckstrchr(local,'/')) {
12977 #endif /* COMMENT */
12979 ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
12980 rs_len = (CK_OFF_T)0; /* Recovery point */
12982 debug(F101,"ftp recvrequest recover","",recover);
12983 if (recover) { /* Recovering... */
12984 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12985 debug(F101,"ftp recvrequest recover stat failed","",errno);
12986 recover = 0; /* So cancel recovery */
12987 } else { /* Have local file info */
12988 ftprecv.localsize = stbuf.st_size; /* Get size */
12989 /* Remote file smaller than local */
12990 if (fsize < ftprecv.localsize) {
12991 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12992 recover = 0; /* Recovery can't work */
12993 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12994 debug(F111,"ftp recvrequest recover equal size",
12995 remote,ftprecv.localsize);
13000 The problem here is that the original partial file never got its date
13001 set, either because FTP DATES was OFF, or because the partial file was
13002 downloaded by some other program that doesn't set local file dates, or
13003 because Kermit only sets the file's date when the download was complete
13004 and successful. In all these cases, the local file has a later time
13007 if (recover) { /* Remote is bigger */
13008 x = chkmodtime(local,remote,0); /* Check file dates */
13009 debug(F111,"ftp recvrequest chkmodtime",remote,x);
13010 if (x != 1) /* Dates must be equal! */
13011 recover = 0; /* If not, get whole file */
13013 #endif /* COMMENT */
13015 debug(F111,"ftp recvrequest recover",remote,recover);
13019 if (proxy && ftprecv.is_retr)
13020 return(proxtrans(cmd, local ? local : remote, remote));
13021 #endif /* FTP_PROXY */
13023 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
13028 ftprecv.recover = recover;
13029 ftprecv.xlate = xlate;
13031 ftprecv.local = local;
13032 ftprecv.remote = remote;
13033 ftprecv.lmode = lmode;
13034 ftprecv.pipename = pipename;
13035 ftprecv.oldintp = NULL;
13039 ftprecv.oldintr = signal(SIGINT, cancelrecv);
13040 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13044 debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13045 debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13048 #endif /* FTP_TIMEOUT */
13050 if (ftprecvret < 0)
13053 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13059 * Need to start a listen on the data channel before we send the command,
13060 * otherwise the server's connect may fail.
13064 register char *p, *a;
13065 int result, tmpno = 0;
13069 #ifndef NO_PASSIVE_MODE
13070 int a1,a2,a3,a4,p1,p2;
13073 data = socket(AF_INET, SOCK_STREAM, 0);
13076 perror("ftp: socket");
13079 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13080 printf("Passive mode refused\n");
13082 return(initconn());
13085 Now we have a string of comma-separated one-byte unsigned integer values,
13086 The first four are the an IP address. The fifth is the MSB of the port
13087 number, the sixth is the LSB. From that we can make a sockaddr_in.
13089 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13090 printf("Passive mode address scan failure\n");
13094 if (tcp_http_proxy) {
13096 char * agent = "Kermit 95"; /* Default user agent */
13098 char * agent = "C-Kermit";
13100 register struct hostent *hp = 0;
13101 struct servent *destsp;
13102 char host[512], *p, *q;
13104 #ifdef IPTOS_THROUGHPUT
13106 #endif /* IPTOS_THROUGHPUT */
13107 #endif /* IP_TOS */
13116 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13117 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13120 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13121 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13125 hisctladdr.sin_addr.s_addr = inet_addr(host);
13126 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13128 debug(F110,"initconn A",host,0);
13129 hisctladdr.sin_family = AF_INET;
13131 debug(F110,"initconn B",host,0);
13132 hp = gethostbyname(host);
13134 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13135 #endif /* HADDRLIST */
13137 fprintf(stderr, "ftp: %s: Unknown host\n", host);
13144 hisctladdr.sin_family = hp->h_addrtype;
13146 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13147 sizeof(hisctladdr.sin_addr));
13148 #else /* HADDRLIST */
13149 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13150 sizeof(hisctladdr.sin_addr));
13151 #endif /* HADDRLIST */
13153 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13154 debug(F101,"initconn socket","",data);
13156 perror("ftp: socket");
13168 destsp = getservbyname(p,"tcp");
13170 hisctladdr.sin_port = destsp->s_port;
13172 hisctladdr.sin_port = htons(atoi(p));
13174 hisctladdr.sin_port = htons(80);
13177 debug(F100,"initconn HADDRLIST","",0);
13180 debug(F100,"initconn no HADDRLIST","",0);
13182 #endif /* HADDRLIST */
13183 (connect(data, (struct sockaddr *)&hisctladdr,
13184 sizeof (hisctladdr)) < 0) {
13185 debug(F101,"initconn connect failed","",errno);
13187 if (hp && hp->h_addr_list[1]) {
13188 int oerrno = errno;
13191 "ftp: connect to address %s: ",
13192 inet_ntoa(hisctladdr.sin_addr)
13195 perror("ftphookup");
13197 memcpy((char *)&hisctladdr.sin_addr,
13198 hp->h_addr_list[0],
13199 sizeof(hisctladdr.sin_addr));
13200 fprintf(stdout, "Trying %s...\n",
13201 inet_ntoa(hisctladdr.sin_addr));
13203 socket_close(data);
13204 #else /* TCPIPLIB */
13206 #endif /* TCPIPLIB */
13207 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13209 perror("ftp: socket");
13218 #endif /* HADDRLIST */
13219 perror("ftp: connect");
13223 if (http_connect(data,
13224 tcp_http_proxy_agent ?
13225 tcp_http_proxy_agent :
13228 tcp_http_proxy_user,
13229 tcp_http_proxy_pwd,
13234 socket_close(data);
13235 #else /* TCPIPLIB */
13237 #endif /* TCPIPLIB */
13238 perror("ftp: connect");
13243 #endif /* NOHTTP */
13245 data_addr.sin_family = AF_INET;
13246 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13247 data_addr.sin_port = htons((p1<<8)|p2);
13250 (struct sockaddr *)&data_addr,
13251 sizeof(data_addr)) < 0
13253 perror("ftp: connect");
13257 debug(F100,"initconn connect ok","",0);
13259 #ifdef IPTOS_THROUGHPUT
13260 on = IPTOS_THROUGHPUT;
13261 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13262 perror("ftp: setsockopt TOS (ignored)");
13263 #endif /* IPTOS_THROUGHPUT */
13264 #endif /* IP_TOS */
13265 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13268 #endif /* NO_PASSIVE_MODE */
13271 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13273 data_addr.sin_port = 0; /* let system pick one */
13276 socket_close(data);
13277 #else /* TCPIPLIB */
13278 #ifdef USE_SHUTDOWN
13279 shutdown(data, 1+1);
13280 #endif /* USE_SHUTDOWN */
13282 #endif /* TCPIPLIB */
13284 data = socket(AF_INET, SOCK_STREAM, 0);
13287 perror("ftp: socket");
13293 if (setsockopt(data,
13300 perror("ftp: setsockopt (reuse address)");
13304 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13305 perror("ftp: bind");
13308 len = sizeof (data_addr);
13309 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13310 perror("ftp: getsockname");
13313 if (listen(data, 1) < 0) {
13314 perror("ftp: listen");
13318 a = (char *)&data_addr.sin_addr;
13319 p = (char *)&data_addr.sin_port;
13320 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13321 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13322 UC(p[0]),",", UC(p[1]));
13323 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13324 if (result == REPLY_ERROR && sendport) {
13329 return(result != REPLY_COMPLETE);
13334 #ifdef IPTOS_THROUGHPUT
13335 on = IPTOS_THROUGHPUT;
13336 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13337 perror("ftp: setsockopt TOS (ignored)");
13343 socket_close(data);
13344 #else /* TCPIPLIB */
13345 #ifdef USE_SHUTDOWN
13346 shutdown(data, 1+1);
13347 #endif /* USE_SHUTDOWN */
13349 #endif /* TCPIPLIB */
13360 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
13361 SSL_free(ssl_ftp_data_con);
13362 ssl_ftp_data_con=NULL;
13364 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13366 SSL_set_fd(ssl_ftp_data_con,data);
13367 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13369 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13371 if (ssl_debug_flag) {
13372 fprintf(stderr,"=>START SSL connect on DATA\n");
13375 if (SSL_connect(ssl_ftp_data_con) <= 0) {
13376 static char errbuf[1024];
13377 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13378 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13379 fprintf(stderr,"%s\n", errbuf);
13382 socket_close(data);
13383 #else /* TCPIPLIB */
13384 #ifdef USE_SHUTDOWN
13385 shutdown(data, 1+1);
13386 #endif /* USE_SHUTDOWN */
13388 #endif /* TCPIPLIB */
13393 ssl_ftp_data_active_flag=1;
13395 if (!ssl_certsok_flag &&
13396 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
13398 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13401 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13402 debug(F110,"dataconn","[SSL _- FAILED]",0);
13404 ssl_ftp_data_active_flag = 0;
13406 socket_close(data);
13407 #else /* TCPIPLIB */
13408 #ifdef USE_SHUTDOWN
13409 shutdown(data, 1+1);
13410 #endif /* USE_SHUTDOWN */
13412 #endif /* TCPIPLIB */
13417 if (!out2screen && displa && fdispla) {
13418 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13419 /* fdispla = XYFD_B; */
13423 "Warning: Server didn't provide a certificate on data connection\n",
13424 "Continue with file transfer? (Y/N)",
13426 debug(F110, "dataconn","[SSL - FAILED]",0);
13427 ssl_ftp_data_active_flag = 0;
13429 socket_close(data);
13430 #else /* TCPIPLIB */
13431 #ifdef USE_SHUTDOWN
13432 shutdown(data, 1+1);
13433 #endif /* USE_SHUTDOWN */
13435 #endif /* TCPIPLIB */
13442 if (!out2screen && displa && fdispla == XYFD_C) {
13443 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13444 /* fdispla = XYFD_B; */
13447 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13448 debug(F110,"dataconn","[SSL - FAILED]",0);
13449 ssl_ftp_data_active_flag = 0;
13451 socket_close(data);
13452 #else /* TCPIPLIB */
13453 #ifdef USE_SHUTDOWN
13454 shutdown(data, 1+1);
13455 #endif /* USE_SHUTDOWN */
13457 #endif /* TCPIPLIB */
13464 debug(F110,"dataconn","[SSL - OK]",0);
13466 /* This messes up the full screen file transfer display */
13467 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13468 #endif /* COMMENT */
13470 if (ssl_debug_flag) {
13471 fprintf(stderr,"=>DONE SSL connect on DATA\n");
13476 #endif /* CK_SSL */
13479 dataconn(lmode) char *lmode; {
13483 #endif /* IP_TOS */
13485 static u_int fromlen;
13487 static SOCKOPT_T fromlen;
13490 fromlen = sizeof(hisdataaddr);
13492 #ifndef NO_PASSIVE_MODE
13495 ssl_ftp_data_active_flag=0;
13496 if (ssl_ftp_active_flag &&
13497 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13498 return(ssl_dataconn());
13499 #endif /* CK_SSL */
13502 #endif /* NO_PASSIVE_MODE */
13504 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13506 perror("ftp: accept");
13508 socket_close(data);
13509 #else /* TCPIPLIB */
13510 #ifdef USE_SHUTDOWN
13511 shutdown(data, 1+1);
13512 #endif /* USE_SHUTDOWN */
13514 #endif /* TCPIPLIB */
13520 socket_close(data);
13521 #else /* TCPIPLIB */
13522 #ifdef USE_SHUTDOWN
13523 shutdown(data, 1+1);
13524 #endif /* USE_SHUTDOWN */
13526 #endif /* TCPIPLIB */
13530 #ifdef IPTOS_THROUGHPUT
13531 tos = IPTOS_THROUGHPUT;
13532 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13533 perror("ftp: setsockopt TOS (ignored)");
13534 #endif /* IPTOS_THROUGHPUT */
13535 #endif /* IP_TOS */
13538 ssl_ftp_data_active_flag=0;
13539 if (ssl_ftp_active_flag &&
13540 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13541 return(ssl_dataconn());
13542 #endif /* CK_SSL */
13548 pscancel(sig) int sig; {
13553 pswitch(flag) int flag; {
13556 static struct comvars {
13558 char name[MAXHOSTNAMELEN];
13559 struct sockaddr_in mctl;
13560 struct sockaddr_in hctl;
13573 char mi[CKMAXPATH];
13574 char mo[CKMAXPATH];
13579 des_cblock session;
13580 des_key_schedule ftp_sched;
13581 #endif /* FTP_KRB4 */
13583 gss_ctx_id_t gcontext;
13584 #endif /* GSSAPI */
13585 } proxstruct, tmpstruct;
13586 struct comvars *ip, *op;
13589 oldintr = signal(SIGINT, pscancel);
13603 ip->connect = connected;
13604 connected = op->connect;
13606 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13607 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13608 ip->name[strlen(ip->name)] = '\0';
13611 ftp_host = op->name;
13612 ip->hctl = hisctladdr;
13613 hisctladdr = op->hctl;
13614 ip->mctl = myctladdr;
13615 myctladdr = op->mctl;
13622 ip->curtpe = curtype;
13623 curtype = op->curtpe;
13626 ip->sunqe = ftp_usn;
13627 ftp_usn = op->sunqe;
13630 ip->ntflg = ntflag;
13631 ntflag = op->ntflg;
13632 strncpy(ip->nti, ntin, 16);
13633 (ip->nti)[strlen(ip->nti)] = '\0';
13634 strcpy(ntin, op->nti);
13635 strncpy(ip->nto, ntout, 16);
13636 (ip->nto)[strlen(ip->nto)] = '\0';
13637 strcpy(ntout, op->nto);
13638 ip->mapflg = mapflag;
13639 mapflag = op->mapflg;
13640 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13641 (ip->mi)[strlen(ip->mi)] = '\0';
13642 strcpy(mapin, op->mi);
13643 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13644 (ip->mo)[strlen(ip->mo)] = '\0';
13645 strcpy(mapout, op->mo);
13646 ip->authtype = auth_type;
13647 auth_type = op->authtype;
13648 ip->clvl = ftp_cpl;
13649 ftp_cpl = op->clvl;
13650 ip->dlvl = ftp_dpl;
13651 ftp_dpl = op->dlvl;
13657 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13658 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13659 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13660 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13661 #endif /* FTP_KRB4 */
13663 ip->gcontext = gcontext;
13664 gcontext = op->gcontext;
13665 #endif /* GSSAPI */
13666 signal(SIGINT, oldintr);
13669 debug(F101,"pswitch cancelfile B","",cancelfile);
13670 (*oldintr)(SIGINT);
13675 cancelpt(sig) int sig; {
13681 longjmp(ptcancel, 1);
13688 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13690 int secndflag = 0, prox_type, nfnd;
13694 #endif /* BSDSELECT */
13695 sigtype cancelpt();
13697 if (strcmp(cmd, "RETR"))
13700 cmd2 = unique ? "STOU" : "STOR";
13701 if ((prox_type = type) == 0) {
13702 if (servertype == SYS_UNIX && unix_proxy)
13703 prox_type = FTT_BIN;
13705 prox_type = FTT_ASC;
13707 if (curtype != prox_type)
13708 changetype(prox_type, 1);
13709 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13710 printf("Proxy server does not support third party transfers.\n");
13715 printf("No primary connection\n");
13720 if (curtype != prox_type)
13721 changetype(prox_type, 1);
13723 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13728 /* Replace with calls to cc_execute() */
13729 if (setjmp(ptcancel))
13731 oldintr = signal(SIGINT, cancelpt);
13732 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13733 signal(SIGINT, oldintr);
13740 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13743 getreply(0,-1,-1,ftp_vbm,0);
13745 getreply(0,-1,-1,ftp_vbm,0);
13746 signal(SIGINT, oldintr);
13752 signal(SIGINT, SIG_IGN);
13754 if (strcmp(cmd, "RETR") && !proxy)
13756 else if (!strcmp(cmd, "RETR") && proxy)
13758 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13759 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13767 signal(SIGINT, oldintr);
13773 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13774 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13781 signal(SIGINT, oldintr);
13791 FD_SET(csocket, &mask);
13792 if ((nfnd = empty(&mask, 10)) <= 0) {
13800 #else /* BSDSELECT */
13802 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13810 #endif /* IBMSELECT */
13811 #endif /* BSDSELECT */
13812 getreply(0,-1,-1,ftp_vbm,0);
13813 getreply(0,-1,-1,ftp_vbm,0);
13820 signal(SIGINT, oldintr);
13822 #endif /* FTP_PROXY */
13824 #ifdef FTP_SECURITY
13828 /* ck_gss_mech_krb5 is not declared anywhere */
13830 CONST gss_OID_desc * CONST * mech_type;
13831 char *service_name;
13833 { &ck_gss_mech_krb5, "ftp" },
13834 { &ck_gss_mech_krb5, "host" },
13837 /* This matches what is declared above */
13839 CONST gss_OID_desc * CONST * mech_type;
13840 char *service_name;
13842 { &gss_mech_krb5, "ftp" },
13843 { &gss_mech_krb5, "host" },
13845 #endif /* COMMENT */
13848 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13849 #endif /* FTP_GSSAPI */
13853 extern int setsafe();
13856 char *service, inst[INST_SZ];
13858 ULONG checksum = (ULONG) getpid();
13859 CHAR out_buf[FTP_BUFSIZ];
13861 #else /* FTP_KRB4 */
13863 CHAR out_buf[FTP_BUFSIZ];
13865 #endif /* FTP_GSSAPI */
13866 #endif /* FTP_KRB4 */
13868 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13872 return(1); /* auth already succeeded */
13874 /* Try each auth type as specified by the end user */
13875 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13877 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13878 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13879 if (n == REPLY_CONTINUE) {
13880 OM_uint32 maj_stat, min_stat;
13881 gss_name_t target_name;
13882 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13883 char stbuf[FTP_BUFSIZ];
13884 int comcode, trial;
13885 struct gss_channel_bindings_struct chan;
13886 char * realm = NULL;
13889 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13890 chan.initiator_address.length = 4;
13891 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13892 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13893 chan.acceptor_address.length = 4;
13894 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13895 chan.application_data.length = 0;
13896 chan.application_data.value = 0;
13899 printf("GSSAPI accepted as authentication type\n");
13901 realm = ck_krb5_realmofhost(ftp_user_host);
13903 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13904 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13905 if ( krb5_autoget &&
13906 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13907 (ck_krb5_is_tgt_valid() > 0)) )
13908 ck_krb5_autoget_TGT(realm);
13911 /* Blob from gss-client */
13912 for (trial = 0; trial < n_gss_trials; trial++) {
13913 /* ftp@hostname first, the host@hostname */
13914 /* the V5 GSSAPI binding canonicalizes this for us... */
13915 ckmakmsg(stbuf,FTP_BUFSIZ,
13916 gss_trials[trial].service_name,
13923 "Authenticating to <%s>...\n", stbuf);
13924 send_tok.value = stbuf;
13925 send_tok.length = strlen(stbuf);
13926 maj_stat = gss_import_name(&min_stat, &send_tok,
13927 gss_nt_service_name,
13930 if (maj_stat != GSS_S_COMPLETE) {
13931 user_gss_error(maj_stat, min_stat, "parsing name");
13932 secure_error("name parsed <%s>\n", stbuf);
13935 token_ptr = GSS_C_NO_BUFFER;
13936 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13940 fprintf(stderr, "calling gss_init_sec_context\n");
13942 gss_init_sec_context(&min_stat,
13943 GSS_C_NO_CREDENTIAL,
13947 gss_trials[trial].mech_type,
13948 GSS_C_MUTUAL_FLAG |
13949 GSS_C_REPLAY_FLAG |
13951 GSS_C_DELEG_FLAG : 0),
13953 /* channel bindings */
13954 (krb5_d_no_addresses ?
13955 GSS_C_NO_CHANNEL_BINDINGS :
13958 NULL, /* ignore mech type */
13960 NULL, /* ignore ret_flags */
13962 ); /* ignore time_rec */
13964 if (maj_stat != GSS_S_COMPLETE &&
13965 maj_stat != GSS_S_CONTINUE_NEEDED) {
13966 if (trial == n_gss_trials-1)
13967 user_gss_error(maj_stat,
13969 "initializing context"
13971 gss_release_name(&min_stat, &target_name);
13972 /* maybe we missed on the service name */
13975 if (send_tok.length != 0) {
13977 reply_parse = "ADAT="; /* for ftpcmd() later */
13980 radix_encode(send_tok.value,
13988 "Base 64 encoding failed: %s\n",
13989 radix_error(kerror)
13991 goto gss_complete_loop;
13993 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13994 if (comcode != REPLY_COMPLETE
13995 && comcode != REPLY_CONTINUE /* (335) */
13997 if (trial == n_gss_trials-1) {
13998 fprintf(stderr, "GSSAPI ADAT failed\n");
13999 /* force out of loop */
14000 maj_stat = GSS_S_FAILURE;
14003 Backoff to the v1 gssapi is still possible.
14004 Send a new AUTH command. If that fails,
14005 terminate the loop.
14007 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
14008 != REPLY_CONTINUE) {
14010 "GSSAPI ADAT failed, AUTH restart failed\n");
14011 /* force out of loop */
14012 maj_stat = GSS_S_FAILURE;
14016 if (!reply_parse) {
14018 "No authentication data received from server\n");
14019 if (maj_stat == GSS_S_COMPLETE) {
14021 "...but no more was needed\n");
14022 goto gss_complete_loop;
14024 user_gss_error(maj_stat,
14028 goto gss_complete_loop;
14032 kerror = radix_encode(reply_parse,out_buf,i,&len,
14036 "Base 64 decoding failed: %s\n",
14037 radix_error(kerror));
14038 goto gss_complete_loop;
14041 /* everything worked */
14042 token_ptr = &recv_tok;
14043 recv_tok.value = out_buf;
14044 recv_tok.length = len;
14047 /* get out of loop clean */
14049 trial = n_gss_trials-1;
14050 gss_release_buffer(&min_stat, &send_tok);
14051 gss_release_name(&min_stat, &target_name);
14054 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14057 if (maj_stat == GSS_S_COMPLETE)
14060 if (maj_stat == GSS_S_COMPLETE) {
14061 printf("GSSAPI authentication succeeded\n");
14062 reply_parse = NULL;
14063 auth_type = "GSSAPI";
14066 fprintf(stderr, "GSSAPI authentication failed\n");
14067 reply_parse = NULL;
14071 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14072 if (ftpcode == 500 || ftpcode == 502)
14076 #endif /* FTP_GSSAPI */
14078 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14079 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14081 else if (ftpcode == 500 || ftpcode == 502)
14084 #endif /* FTP_SRP */
14086 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14087 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14088 if (n == REPLY_CONTINUE) {
14089 char tgt[4*REALM_SZ+1];
14093 printf("KERBEROS_V4 accepted as authentication type\n");
14094 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14095 ckstrncpy(ftp_realm,
14096 (char *)ck_krb4_realmofhost(ftp_user_host),
14100 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14101 rc = ck_krb4_tkt_isvalid(tgt);
14103 if (rc <= 0 && krb4_autoget)
14104 ck_krb4_autoget_TGT(ftp_realm);
14107 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14108 if (kerror == KDC_PR_UNKNOWN) {
14110 kerror = krb_mk_req(&ftp_tkt,
14118 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14119 krb_get_err_text(kerror));
14121 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14123 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14124 krb_get_err_text(kerror));
14128 rc = des_key_sched(ftp_cred.session, ftp_sched);
14130 printf("?Invalid DES key specified in credentials\r\n");
14131 debug(F110,"ftp_auth",
14132 "invalid DES Key specified in credentials",0);
14133 } else if ( rc == -2 ) {
14134 printf("?Weak DES key specified in credentials\r\n");
14135 debug(F110,"ftp_auth",
14136 "weak DES Key specified in credentials",0);
14137 } else if ( rc != 0 ) {
14138 printf("?DES Key Schedule not set by credentials\r\n");
14139 debug(F110,"ftp_auth",
14140 "DES Key Schedule not set by credentials",0);
14142 reply_parse = "ADAT=";
14144 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14147 fprintf(stderr, "Base 64 encoding failed: %s\n",
14148 radix_error(kerror));
14151 if (i > FTP_BUFSIZ - 6)
14152 printf("?ADAT data too long\n");
14153 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14155 fprintf(stderr, "Kerberos V4 authentication failed\n");
14158 if (!reply_parse) {
14160 "No authentication data received from server\n");
14163 i = sizeof(out_buf);
14165 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14167 fprintf(stderr, "Base 64 decoding failed: %s\n",
14168 radix_error(kerror));
14171 kerror = krb_rd_safe(out_buf, i,
14176 #endif /* KRB524 */
14182 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14183 krb_get_err_text(kerror));
14187 /* fetch the (modified) checksum */
14188 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14189 if (ntohl(cksum) == checksum + 1) {
14191 printf("Kerberos V4 authentication succeeded\n");
14192 reply_parse = NULL;
14193 auth_type = "KERBEROS_V4";
14197 "Kerberos V4 mutual authentication failed\n");
14199 reply_parse = NULL;
14204 "KERBEROS_V4 rejected as an authentication type\n");
14205 if (ftpcode == 500 || ftpcode == 502)
14209 #endif /* FTP_KRB4 */
14211 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14214 ftpcmd("HOST",ftp_user_host,0,0,0);
14217 #endif /* FTPHOST */
14218 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14219 if (n != REPLY_COMPLETE)
14220 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14221 if (n == REPLY_COMPLETE) {
14223 printf("TLS accepted as authentication type\n");
14227 if (ssl_ftp_active_flag ) {
14232 fprintf(stderr,"TLS authentication failed\n");
14235 socket_close(csocket);
14236 #else /* TCPIPLIB */
14237 #ifdef USE_SHUTDOWN
14238 shutdown(csocket, 1+1);
14239 #endif /* USE_SHUTDOWN */
14241 #endif /* TCPIPLIB */
14243 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14248 fprintf(stderr,"TLS rejected as an authentication type\n");
14249 if (ftpcode == 500 || ftpcode == 502)
14253 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14256 ftpcmd("HOST",ftp_user_host,0,0,0);
14259 #endif /* FTPHOST */
14260 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14261 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14263 printf("SSL accepted as authentication type\n");
14266 if (ssl_ftp_active_flag) {
14272 fprintf(stderr,"SSL authentication failed\n");
14275 socket_close(csocket);
14276 #else /* TCPIPLIB */
14277 #ifdef USE_SHUTDOWN
14278 shutdown(csocket, 1+1);
14279 #endif /* USE_SHUTDOWN */
14281 #endif /* TCPIPLIB */
14283 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14288 fprintf(stderr, "SSL rejected as an authentication type\n");
14289 if (ftpcode == 500 || ftpcode == 502)
14293 #endif /* CK_SSL */
14294 /* Other auth types go here ... */
14298 #endif /* FTP_SECURITY */
14302 setprotbuf(unsigned int size)
14304 setprotbuf(size) unsigned int size;
14305 #endif /* CK_ANSIC */
14312 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14318 ucbufsiz = actualbuf - FUDGE_FACTOR;
14319 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14320 if (ucbufsiz < 128) {
14321 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14322 } else if (ucbufsiz < 0) {
14323 printf("ERROR: ucbuf allocation failure\n");
14326 maxbuf = actualbuf;
14332 setpbsz(unsigned int size)
14334 setpbsz(size) unsigned int size;
14335 #endif /* CK_ANSIC */
14337 if (!setprotbuf(size)) {
14338 perror("?Error while trying to malloc PROT buffer:");
14341 #endif /* FTP_SRP */
14345 reply_parse = "PBSZ=";
14346 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14348 ssl_ftp_active_flag ? "0" :
14349 #endif /* CK_SSL */
14350 ckuitoa(actualbuf),NULL,NULL);
14351 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14353 printf("?Unable to negotiate PROT buffer size with FTP server\n");
14359 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14360 maxbuf = actualbuf;
14362 maxbuf = actualbuf;
14363 ucbufsiz = maxbuf - FUDGE_FACTOR;
14364 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14365 reply_parse = NULL;
14370 cancel_remote(din) int din; {
14371 CHAR buf[FTP_BUFSIZ];
14375 #endif /* BSDSELECT */
14377 int fds[2], fdcnt = 0;
14378 #endif /* IBMSELECT */
14385 debug(F100,"ftp cancel_remote entry","",0);
14387 if (ssl_ftp_active_flag) {
14389 * Send Telnet IP, Telnet DM but do so inline and within the
14400 count = SSL_write(ssl_ftp_con, buf, 4);
14401 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14402 error = SSL_get_error(ssl_ftp_con,count);
14403 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14405 case SSL_ERROR_NONE:
14407 case SSL_ERROR_WANT_WRITE:
14408 case SSL_ERROR_WANT_READ:
14409 case SSL_ERROR_SYSCALL:
14412 int gle = GetLastError();
14415 case SSL_ERROR_WANT_X509_LOOKUP:
14416 case SSL_ERROR_SSL:
14417 case SSL_ERROR_ZERO_RETURN:
14423 #endif /* CK_SSL */
14426 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14427 * after urgent byte rather than before as is protocol now.
14433 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14435 debug(F101,"ftp cancel_remote send 1","",x);
14437 x = send(csocket,(SENDARG2TYPE)buf,1,0);
14438 debug(F101,"ftp cancel_remote send 2","",x);
14440 x = scommand("ABOR");
14441 debug(F101,"ftp cancel_remote scommand","",x);
14444 FD_SET(csocket, &mask);
14446 FD_SET(din, &mask);
14448 nfnd = empty(&mask, 10);
14449 debug(F101,"ftp cancel_remote empty","",nfnd);
14457 #endif /* FTP_PROXY */
14460 debug(F110,"ftp cancel_remote","D",0);
14461 if (din && FD_ISSET(din, &mask)) {
14462 /* Security: No threat associated with this read. */
14463 /* But you can't simply read the TLS data stream */
14465 if (ssl_ftp_data_active_flag) {
14467 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14470 #endif /* CK_SSL */
14472 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14476 debug(F110,"ftp cancel_remote","E",0);
14477 #else /* BSDSELECT */
14485 nfnd = empty(fds, fdcnt, 10);
14486 debug(F101,"ftp cancel_remote empty","",nfnd);
14494 #endif /* FTP_PROXY */
14497 debug(F110,"ftp cancel_remote","D",0);
14498 if (din && select(&din, 1,0,0,1) ) {
14500 if (ssl_ftp_data_active_flag) {
14502 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14505 #endif /* CK_SSL */
14507 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14511 debug(F110,"ftp cancel_remote","E",0);
14512 #else /* IBMSELECT */
14513 Some form of select is required.
14514 #endif /* IBMSELECT */
14515 #endif /* BSDSELECT */
14516 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14517 debug(F110,"ftp cancel_remote","F",0);
14518 /* 552 needed for NIC style cancel */
14519 getreply(0,-1,-1,ftp_vbm,0);
14520 debug(F110,"ftp cancel_remote","G",0);
14522 debug(F110,"ftp cancel_remote","H",0);
14523 getreply(0,-1,-1,ftp_vbm,0);
14524 debug(F110,"ftp cancel_remote","I",0);
14531 fts_dpl(x) int x; {
14534 || !ck_crypt_is_installed()
14539 printf("?Cannot set protection level to PRIVATE\n");
14542 printf("?Cannot set protection level to SAFE\n");
14550 if (x == FPL_SAF &&
14551 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14552 printf("Cannot set protection level to safe\n");
14555 #endif /* CK_SSL */
14556 /* Start with a PBSZ of 1 meg */
14557 if (x != FPL_CLR) {
14558 if (setpbsz(DEFAULT_PBSZ) < 0)
14561 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14562 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14563 if (y == REPLY_COMPLETE) {
14571 fts_cpl(x) int x; {
14574 || !ck_crypt_is_installed()
14579 printf("?Cannot set protection level to PRIVATE\n");
14582 printf("?Cannot set protection level to SAFE\n");
14588 if (x == FPL_CLR) {
14589 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14590 if (y == REPLY_COMPLETE) {
14602 user_gss_error(maj_stat, min_stat, s)
14603 OM_uint32 maj_stat, min_stat;
14606 /* a lot of work just to report the error */
14607 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14608 gss_buffer_desc msg;
14611 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14617 if ((gmaj_stat == GSS_S_COMPLETE)||
14618 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14619 fprintf(stderr, "GSSAPI error major: %s\n",
14621 gss_release_buffer(&gmin_stat, &msg);
14623 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14628 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14634 if ((gmaj_stat == GSS_S_COMPLETE)||
14635 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14636 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14637 gss_release_buffer(&gmin_stat, &msg);
14639 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14642 fprintf(stderr, "GSSAPI error: %s\n", s);
14644 #endif /* FTP_GSSAPI */
14652 #endif /* HPUX5WINTCP */
14653 #endif /* datageneral */
14654 #endif /* NOMHHOST */
14657 static struct in_addr inaddrx;
14658 #endif /* INADDRX */
14661 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14662 register struct hostent *hp = 0;
14664 #ifdef IPTOS_THROUGHPUT
14666 #endif /* IPTOS_THROUGHPUT */
14667 #endif /* IP_TOS */
14670 static char hostnamebuf[MAXHOSTNAMELEN];
14671 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14680 debug(F111,"ftp_hookup",host,port);
14683 if (tcp_http_proxy) {
14684 struct servent *destsp;
14687 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14688 for (p = tcp_http_proxy, q = hostname;
14689 *p != '\0' && *p != ':';
14700 destsp = getservbyname(p,"tcp");
14702 cport = ntohs(destsp->s_port);
14708 #endif /* NOHTTP */
14710 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14713 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14714 hisctladdr.sin_addr.s_addr = inet_addr(host);
14715 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14717 debug(F110,"ftp hookup A",hostname,0);
14718 hisctladdr.sin_family = AF_INET;
14719 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14721 debug(F110,"ftp hookup B",hostname,0);
14722 hp = gethostbyname(hostname);
14724 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14725 #endif /* HADDRLIST */
14727 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14732 return((char *) 0);
14734 hisctladdr.sin_family = hp->h_addrtype;
14736 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14737 sizeof(hisctladdr.sin_addr));
14738 #else /* HADDRLIST */
14739 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14740 sizeof(hisctladdr.sin_addr));
14741 #endif /* HADDRLIST */
14742 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14744 debug(F110,"ftp hookup C",hostnamebuf,0);
14745 ftp_host = hostnamebuf;
14746 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14747 debug(F101,"ftp hookup socket","",s);
14749 perror("ftp: socket");
14756 hisctladdr.sin_port = htons(cport);
14760 printf("hisctladdr=%d\n",sizeof(hisctladdr));
14761 printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14762 printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14763 printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14764 #endif /* COMMENT */
14767 debug(F100,"ftp hookup HADDRLIST","",0);
14770 debug(F100,"ftp hookup no HADDRLIST","",0);
14772 #endif /* HADDRLIST */
14773 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14774 debug(F101,"ftp hookup connect failed","",errno);
14776 if (hp && hp->h_addr_list[1]) {
14777 int oerrno = errno;
14779 fprintf(stderr, "ftp: connect to address %s: ",
14780 inet_ntoa(hisctladdr.sin_addr));
14782 perror((char *) 0);
14784 memcpy((char *)&hisctladdr.sin_addr,
14785 hp->h_addr_list[0],
14786 sizeof(hisctladdr.sin_addr));
14787 fprintf(stdout, "Trying %s...\n",
14788 inet_ntoa(hisctladdr.sin_addr));
14791 #else /* TCPIPLIB */
14793 #endif /* TCPIPLIB */
14794 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14796 perror("ftp: socket");
14805 #endif /* HADDRLIST */
14806 perror("ftp: connect");
14810 debug(F100,"ftp hookup connect ok","",0);
14812 len = sizeof (myctladdr);
14814 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14815 debug(F101,"ftp hookup getsockname failed","",errno);
14816 perror("ftp: getsockname");
14820 debug(F100,"ftp hookup getsockname ok","",0);
14823 if (tcp_http_proxy) {
14825 char * agent = "Kermit 95"; /* Default user agent */
14827 char * agent = "C-Kermit";
14830 if (http_connect(s,agent,NULL,
14831 tcp_http_proxy_user,
14832 tcp_http_proxy_pwd,
14839 #else /* TCPIPLIB */
14841 #endif /* TCPIPLIB */
14843 while (foo == NULL && tcp_http_proxy != NULL ) {
14845 if (tcp_http_proxy_errno == 401 ||
14846 tcp_http_proxy_errno == 407 ) {
14847 char uid[UIDBUFLEN];
14849 struct txtbox tb[2];
14853 tb[0].t_len = UIDBUFLEN;
14854 tb[0].t_lbl = "Proxy Userid: ";
14855 tb[0].t_dflt = NULL;
14859 tb[1].t_lbl = "Proxy Passphrase: ";
14860 tb[1].t_dflt = NULL;
14863 ok = uq_mtxt("Proxy Server Authentication Required\n",
14866 if (ok && uid[0]) {
14867 char * proxy_user, * proxy_pwd;
14869 proxy_user = tcp_http_proxy_user;
14870 proxy_pwd = tcp_http_proxy_pwd;
14872 tcp_http_proxy_user = uid;
14873 tcp_http_proxy_pwd = pwd;
14875 foo = ftp_hookup(host, port, 0);
14877 debug(F110,"ftp_hookup()",foo,0);
14878 memset(pwd,0,PWDSIZ);
14879 tcp_http_proxy_user = proxy_user;
14880 tcp_http_proxy_pwd = proxy_pwd;
14888 perror("ftp: connect");
14892 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14894 #endif /* NOHTTP */
14901 * If the connection is over an SSL proxy then the
14902 * auth_type will be NULL. However, I'm not sure
14903 * whether we should protect the data channel in
14904 * that case or not.
14907 debug(F100,"ftp hookup use_tls","",0);
14909 debug(F100,"ftp hookup ssl_auth failed","",0);
14917 #endif /* CK_SSL */
14920 #ifdef IPTOS_LOWDELAY
14921 tos = IPTOS_LOWDELAY;
14922 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14923 perror("ftp: setsockopt TOS (ignored)");
14927 printf("Connected to %s.\n", host);
14929 /* Read greeting from server */
14930 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14931 debug(F100,"ftp hookup bad reply","",0);
14933 socket_close(csocket);
14934 #else /* TCPIPLIB */
14936 #endif /* TCPIPLIB */
14940 #ifdef SO_OOBINLINE
14944 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14946 perror("ftp: setsockopt");
14947 debug(F101,"ftp hookup setsockopt failed","",errno);
14951 debug(F100,"ftp hookup setsockopt ok","",0);
14954 #endif /* SO_OOBINLINE */
14962 debug(F100,"ftp hookup bad","",0);
14965 #else /* TCPIPLIB */
14967 #endif /* TCPIPLIB */
14979 /* The purpose of the initial REST 0 is not clear, but other FTP */
14980 /* clients do it. In any case, failure of this command is not a */
14981 /* reliable indication that the server does not support Restart. */
14985 n = ftpcmd("REST 0",NULL,0,0,0);
14986 if (n == REPLY_COMPLETE)
14990 printf("WARNING: Unable to restore file pointer.\n");
14991 #endif /* COMMENT */
14993 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14994 if (n == REPLY_COMPLETE) {
14995 register char *cp, c = NUL;
14996 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14998 cp = ckstrchr(ftp_reply_str+4,'\r');
15002 c = *cp; /* Save this char */
15003 *cp = '\0'; /* Replace it with NUL */
15006 printf("Remote system type is %s.\n",ftp_reply_str+4);
15007 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
15008 if (cp) /* Put back saved char */
15011 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
15013 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
15014 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
15015 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
15016 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
15017 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
15018 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
15019 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
15023 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
15024 #endif /* FTP_PROXY */
15026 if (ftp_cmdlin && ftp_xfermode == XMODE_M)
15027 ftp_typ = binary; /* Type given on command line */
15028 else /* Otherwise set it automatically */
15029 ftp_typ = alike ? FTT_BIN : FTT_ASC;
15030 changetype(ftp_typ,0); /* Change to this type */
15031 g_ftp_typ = ftp_typ; /* Make it the global type */
15033 printf("Default transfer mode is %s\n",
15034 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
15036 for (i = 0; i < 16; i++) /* Init server FEATure table */
15039 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15041 if (n != REPLY_COMPLETE)
15042 printf("WARNING: Server does not accept MODE S(TREAM)\n");
15043 #endif /* COMMENT */
15044 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15046 if (n != REPLY_COMPLETE)
15047 printf("WARNING: Server does not accept STRU F(ILE)\n");
15048 #endif /* COMMENT */
15050 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15051 if (n == REPLY_COMPLETE) {
15052 debug(F101,"ftp_init FEAT","",sfttab[0]);
15053 if (deblog || ftp_deb) {
15055 for (i = 1; i < 16 && i < nfeattab; i++) {
15056 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15058 printf(" Server %s %s\n",
15059 sfttab[i] ? "supports" : "does not support",
15063 /* Deal with disabled MLST opts here if necessary */
15064 /* But why would it be? */
15072 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
15073 static char ftppass[PASSBUFSIZ]="";
15074 char tmp[PASSBUFSIZ];
15075 char *user = NULL, *pass = NULL, *acct = NULL;
15077 extern char uidbuf[];
15078 extern char pwbuf[];
15079 extern int pwflg, pwcrypt;
15081 debug(F111,"ftp_login",ftp_logname,ftp_log);
15083 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15085 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15089 if (auth_type && !strcmp(auth_type, "SRP")) {
15094 #endif /* FTP_SRP */
15096 user = "anonymous";
15097 if (ftp_tmp) { /* They gave a password */
15099 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
15101 } else { /* Supply user@host */
15102 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15105 debug(F110,"ftp anonymous",pass,0);
15107 #ifdef USE_RUSERPASS
15108 if (ruserpass(host, &user, &pass, &acct) < 0) {
15112 #endif /* USE_RUSERPASS */
15114 user = ftp_logname;
15116 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15120 } else if (pwbuf[0] && pwflg) {
15121 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15124 ck_encrypt((char *)ftppass);
15130 while (user == NULL) {
15131 char *myname, prompt[PROMPTSIZ];
15136 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15137 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15139 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15142 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15143 DEFAULT_UQ_TIMEOUT);
15144 if (!ok || *tmp == '\0')
15147 user = brstrip(tmp);
15150 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15151 if (n == REPLY_COMPLETE) {
15152 /* determine if we need to send a dummy password */
15153 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15154 ftpcmd("PASS dummy",NULL,0,0,1);
15155 } else if (n == REPLY_CONTINUE) {
15156 #ifdef CK_ENCRYPTION
15158 #endif /* CK_ENCRYPTION */
15160 if (pass == NULL) {
15163 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15164 DEFAULT_UQ_TIMEOUT);
15166 pass = brstrip(ftppass);
15169 #ifdef CK_ENCRYPTION
15170 oldftp_cpl = ftp_cpl;
15172 #endif /* CK_ENCRYPTION */
15173 n = ftpcmd("PASS",pass,-1,-1,1);
15174 if (!anonymous && pass) {
15176 while (*p++) *(p-1) = NUL;
15177 makestr(&ftp_tmp,NULL);
15179 #ifdef CK_ENCRYPTION
15180 /* level may have changed */
15181 if (ftp_cpl == FPL_PRV)
15182 ftp_cpl = oldftp_cpl;
15183 #endif /* CK_ENCRYPTION */
15185 if (n == REPLY_CONTINUE) {
15187 if (acct == NULL) {
15188 static char ftpacct[80];
15191 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15192 DEFAULT_UQ_TIMEOUT);
15194 acct = brstrip(ftpacct);
15196 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15198 if (n != REPLY_COMPLETE) {
15199 fprintf(stderr, "FTP login failed.\n");
15201 doexit(BAD_EXIT,-1);
15204 if (!aflag && acct != NULL) {
15205 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15207 makestr(&ftp_logname,user);
15210 /* Unprefixed file management commands go to server */
15211 if (autolocus && !ftp_cmdlin) {
15217 if (anonymous && !quiet) {
15218 printf(" Logged in as anonymous (%s)\n",pass);
15219 memset(pass, 0, strlen(pass));
15222 if (doftpcwd(ftp_rdir,-1) < 1)
15223 doexit(BAD_EXIT,-1);
15229 #endif /* FTP_PROXY */
15241 FD_SET(csocket, &mask);
15242 if ((nfnd = empty(&mask,0)) < 0) {
15248 getreply(0,-1,-1,ftp_vbm,0);
15251 #else /* BSDSELECT */
15255 if ((nfnd = empty(&csocket,1,0)) < 0) {
15261 getreply(0,-1,-1,ftp_vbm,0);
15264 #endif /* IBMSELECT */
15265 #endif /* BSDSELECT */
15266 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15273 ftp_rename(from, to) char * from, * to; {
15274 int lcs = -1, rcs = -1;
15278 if (lcs < 0) lcs = fcharset;
15280 if (rcs < 0) rcs = ftp_csr;
15282 #endif /* NOCSETS */
15283 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15284 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15286 return(0); /* Failure */
15290 ftp_umask(mask) char * mask; {
15292 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15297 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15298 int n = 0, aflag = 0;
15301 if (!auth_type && ftp_aut) {
15303 if (ck_srp_is_installed()) {
15304 if (srp_ftp_auth( NULL, user, pass)) {
15305 makestr(&pass,srp_pass);
15308 #endif /* FTP_SRP */
15310 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15311 if (n == REPLY_COMPLETE)
15312 n = ftpcmd("PASS dummy",NULL,0,0,1);
15313 else if (n == REPLY_CONTINUE) {
15314 #ifdef CK_ENCRYPTION
15316 #endif /* CK_ENCRYPTION */
15317 if (pass == NULL || !pass[0]) {
15321 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15322 DEFAULT_UQ_TIMEOUT);
15324 pass = brstrip(pwd);
15327 #ifdef CK_ENCRYPTION
15328 if ((oldftp_cpl = ftp_cpl) == PROT_S)
15330 #endif /* CK_ENCRYPTION */
15331 n = ftpcmd("PASS",pass,-1,-1,1);
15332 memset(pass, 0, strlen(pass));
15333 #ifdef CK_ENCRYPTION
15334 /* level may have changed */
15335 if (ftp_cpl == PROT_P)
15336 ftp_cpl = oldftp_cpl;
15337 #endif /* CK_ENCRYPTION */
15339 if (n == REPLY_CONTINUE) {
15340 if (acct == NULL || !acct[0]) {
15344 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15345 DEFAULT_UQ_TIMEOUT);
15349 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15352 if (n != REPLY_COMPLETE) {
15353 printf("Login failed.\n");
15356 if (!aflag && acct != NULL && acct[0]) {
15357 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15359 if (n == REPLY_COMPLETE) {
15360 makestr(&ftp_logname,user);
15372 return(auth_type ? auth_type : "NULL");
15385 return("confidential");
15401 return("confidential");
15408 /* remote_files() */
15410 Returns next remote filename on success;
15411 NULL on error or no more files with global rfrc set to:
15413 -2: Server error response to NLST, e.g. file not found
15417 #define FTPNAMBUFLEN CKMAXPATH+1024
15419 /* Check: ckmaxfiles CKMAXOPEN */
15421 #define MLSDEPTH 128 /* Stack of open temp files */
15422 static int mlsdepth = 0; /* Temp file stack depth */
15423 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15424 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15427 mlsreset() { /* Reset MGET temp-file stack */
15429 for (i = 0; i <= mlsdepth; i++) {
15430 if (tmpfilptr[i]) {
15431 fclose(tmpfilptr[i]);
15432 tmpfilptr[i] = NULL;
15433 if (tmpfilnam[i]) {
15435 unlink(tmpfilnam[i]);
15437 free(tmpfilnam[i]);
15446 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15447 #else /* CK_ANSIC */
15448 remote_files(new_query, arg, pattern, proxy_switch)
15450 CHAR * arg; /* That we send to the server */
15451 CHAR * pattern; /* That we use locally */
15453 #endif /* CK_ANSIC */
15454 /* remote_files */ {
15455 static CHAR buf[FTPNAMBUFLEN];
15456 CHAR *cp, *whicharg;
15457 char * cdto = NULL;
15459 int i, x, forced = 0;
15460 int lcs = 0, rcs = 0, xlate = 0;
15462 debug(F101,"ftp remote_files new_query","",new_query);
15463 debug(F110,"ftp remote_files arg",arg,0);
15464 debug(F110,"ftp remote_files pattern",pattern,0);
15467 if (pattern) /* Treat empty pattern same as NULL */
15470 if (arg) /* Ditto for arg */
15477 if (tmpfilptr[mlsdepth]) {
15478 fclose(tmpfilptr[mlsdepth]);
15479 tmpfilptr[mlsdepth] = NULL;
15481 if (!ftp_deb && !deblog)
15482 unlink(tmpfilnam[mlsdepth]);
15486 if (tmpfilptr[mlsdepth] == NULL) {
15487 extern char * tempdir;
15489 debug(F110,"ftp remote_files tempdir",tempdir,0);
15495 p = getenv("K95TMP");
15497 p = getenv("K2TMP");
15501 p = getenv("CK_TMP");
15503 p = getenv("TMPDIR");
15504 if (!p) p = getenv("TEMP");
15505 if (!p) p = getenv("TMP");
15508 int len = strlen(p);
15509 if (p[len-1] != '/'
15511 && p[len-1] != '\\'
15514 static char foo[CKMAXPATH];
15515 ckstrncpy(foo,p,CKMAXPATH);
15516 ckstrncat(foo,"/",CKMAXPATH);
15520 #else /* OS2ORUNIX */
15522 #endif /* OS2ORUNIX */
15523 #ifdef UNIX /* Systems that have a standard */
15524 p = "/tmp/"; /* temporary directory... */
15530 #endif /* datageneral */
15533 debug(F110,"ftp remote_files p",p,0);
15535 /* Get temp file */
15537 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15538 ckmakmsg((char *)tmpfilnam[mlsdepth],
15539 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15541 printf("?Malloc failure: remote_files()\n");
15547 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15549 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15554 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15555 if (x > -1) close(x); /* We just want the name. */
15557 mktemp((char *)tmpfilnam[mlsdepth]);
15558 #endif /* MKSTEMP */
15559 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15560 #endif /* MKTEMP */
15563 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15564 tmpfilnam[mlsdepth],mlsdepth);
15567 if (proxy_switch) {
15570 #endif /* FTP_PROXY */
15572 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15573 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15574 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15577 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15578 if (xlate) { /* ON? */
15579 lcs = ftp_csl; /* Local charset */
15580 if (lcs < 0) lcs = fcharset;
15581 if (lcs < 0) xlate = 0;
15583 if (xlate) { /* Still ON? */
15584 rcs = ftp_csx; /* Remote (Server) charset */
15585 if (rcs < 0) rcs = ftp_csr;
15586 if (rcs < 0) xlate = 0;
15588 #endif /* NOCSETS */
15590 forced = mgetforced; /* MGET method forced? */
15591 if (!forced || !mgetmethod) /* Not forced... */
15592 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15596 User's Command: Result:
15597 mget /nlst NLST (NULL)
15598 mget /nlst foo NLST foo
15599 mget /nlst *.txt NLST *.txt
15600 mget /nlst /match:*.txt NLST (NULL)
15601 mget /nlst /match:*.txt foo NLST foo
15602 mget /mlsd MLSD (NULL)
15603 mget /mlsd foo MLSD foo
15604 mget /mlsd *.txt MLSD (NULL)
15605 mget /mlsd /match:*.txt MLSD (NULL)
15606 mget /mlsd /match:*.txt foo MLSD foo
15610 if (pattern) { /* Don't simplify this! */
15612 } else if (mgetmethod == SND_MLS) {
15614 whicharg = iswild((char *)arg) ? NULL : arg;
15620 debug(F110,"ftp remote_files mgetmethod",
15621 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15622 debug(F110,"ftp remote_files whicharg",whicharg,0);
15624 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15625 (char *)tmpfilnam[mlsdepth],
15635 if (x < 0) { /* Chosen method wasn't accepted */
15637 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15638 printf("?%s: Not supported by server\n",
15639 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15641 rfrc = -2; /* Fail */
15644 /* Not forced - if MLSD failed, try NLST */
15645 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15646 sfttab[SFT_MLST] = 0; /* So disable it */
15647 mlstok = 0; /* and */
15648 mgetmethod = SND_NLS; /* try NLST */
15656 if (proxy_switch) {
15659 #endif /* FTP_PROXY */
15660 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15662 if (tmpfilptr[mlsdepth]) {
15663 if (!ftp_deb && !deblog)
15664 unlink(tmpfilnam[mlsdepth]);
15668 if (!tmpfilptr[mlsdepth]) {
15669 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15670 if ((!dpyactive || ftp_deb))
15671 printf("?Can't find list of remote files, oops\n");
15676 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15679 buf[FTPNAMBUFLEN-1] = NUL;
15680 buf[FTPNAMBUFLEN-2] = NUL;
15682 /* We have to redo all this because the first time was only for */
15683 /* for getting the file list, now it's for getting each file */
15685 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15686 if (!pattern && iswild((char *)arg)) {
15687 pattern = arg; /* Wild arg is really a pattern */
15691 arg = NULL; /* and not an arg */
15693 if (new_query) { /* Initial query? */
15694 cdto = (char *)arg; /* (nonwild) arg given? */
15698 if (cdto) /* If so, then CD to it */
15704 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15705 fclose(tmpfilptr[mlsdepth]);
15706 tmpfilptr[mlsdepth] = NULL;
15709 if (!ftp_deb && !deblog)
15710 unlink(tmpfilnam[mlsdepth]);
15712 if (ftp_deb && !deblog) {
15713 printf("(Temporary file %s NOT deleted)\n",
15714 (char *)tmpfilnam[mlsdepth]);
15716 if (mlsdepth <= 0) { /* EOF at depth 0 */
15717 rfrc = -3; /* means we're done */
15720 printf("POPPING(%d)...\n",mlsdepth-1);
15721 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15724 zchdir(".."); /* <-- Not portable */
15727 if (buf[FTPNAMBUFLEN-1]) {
15728 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15731 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15734 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15735 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15737 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15739 debug(F110,"ftp remote_files buf",buf,0);
15743 printf("[%s]\n",(char *)buf);
15745 havesize = (CK_OFF_T)-1; /* Initialize file facts... */
15747 makestr(&havemdtm,NULL);
15750 if (mgetmethod == SND_NLS) { /* NLST... */
15752 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15755 } else { /* MLSD... */
15756 p = parsefacts((char *)buf);
15757 switch (havetype) {
15758 case FTYP_FILE: /* File: Get it if it matches */
15760 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15764 case FTYP_CDIR: /* Current directory */
15765 case FTYP_PDIR: /* Parent directory */
15766 goto again; /* Skip */
15767 case FTYP_DIR: /* (Sub)Directory */
15768 if (!recursive) /* If not /RECURSIVE */
15769 goto again; /* Skip */
15770 if (mlsdepth < MLSDEPTH) {
15773 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15774 if (doftpcwd(p,0) > 0) {
15776 if (!ckstrchr(p,'/')) {
15777 /* zmkdir() needs dirsep */
15778 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15779 strcpy(p2,p); /* SAFE */
15780 strcat(p2,"/"); /* SAFE */
15788 #endif /* NOMKDIR */
15791 p = (char *)remote_files(1,arg,pattern,0);
15794 printf("?mkdir failed: [%s] Depth=%d\n",
15803 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15808 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15819 debug(F101,"remote_files havesize","",havesize);
15820 debug(F101,"remote_files havetype","",havetype);
15821 debug(F110,"remote_files havemdtm",havemdtm,0);
15822 debug(F110,"remote_files name",p,0);
15828 /* N O T P O R T A B L E !!! */
15830 #if (SIZEOF_SHORT == 4)
15831 typedef unsigned short ftp_uint32;
15832 typedef short ftp_int32;
15834 #if (SIZEOF_INT == 4)
15835 typedef unsigned int ftp_uint32;
15836 typedef int ftp_int32;
15838 #if (SIZEOF_LONG == 4)
15839 typedef ULONG ftp_uint32;
15840 typedef long ftp_int32;
15845 /* Perhaps use these in general, certainly use them for GSSAPI */
15847 #ifndef looping_write
15848 #define ftp_int32 int
15849 #define ftp_uint32 unsigned int
15851 looping_write(fd, buf, len)
15853 register CONST char *buf;
15857 register int wrlen = len;
15859 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15861 if (errno == EINTR)
15868 } while (wrlen > 0);
15872 #ifndef looping_read
15874 looping_read(fd, buf, len)
15876 register char *buf;
15882 cc = recv(fd, (char *)buf, len,0);
15884 if (errno == EINTR)
15886 return(cc); /* errno is already set */
15887 } else if (cc == 0) {
15897 #endif /* looping_read */
15903 secure_putbyte(fd, c) int fd; CHAR c; {
15907 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15909 if (!ftpissecure())
15910 ret = send(fd, (SENDARG2TYPE)ucbuf,
15911 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15913 ret = secure_putbuf(fd,
15915 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15921 #endif /* COMMENT */
15925 * -1 on error (errno set)
15926 * -2 on security error
15929 secure_flush(fd) int fd; {
15935 if (!ftpissecure()) {
15936 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15940 rc = secure_putbuf(fd, ucbuf, nout);
15945 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15948 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15951 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15956 #ifdef COMMENT /* (not used) */
15960 * -2 on security error
15964 secure_putc(char c, int fd)
15966 secure_putc(c, fd) char c; int fd;
15967 #endif /* CK_ANSIC */
15968 /* secure_putc */ {
15969 return(secure_putbyte(fd, (CHAR) c));
15971 #endif /* COMMENT */
15975 * -1 on error (errno set)
15976 * -2 on security error
15980 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15982 secure_write(fd, buf, nbyte)
15985 unsigned int nbyte;
15986 #endif /* CK_ANSIC */
15992 if (check_data_connection(fd,1) < 0) {
15996 #endif /* FTP_TIMEOUT */
15998 if (!ftpissecure()) {
16000 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
16004 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
16006 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
16009 while (bsent < nbyte) {
16010 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
16011 (ucbuflen - nout) : (nbyte - bsent));
16014 debug(F101,"secure_write ucbuflen","",ucbuflen);
16015 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
16016 debug(F101,"secure_write bsent","",bsent);
16017 debug(F101,"secure_write b2cp","",b2cp);
16020 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
16024 if (nout == ucbuflen) {
16026 ret = secure_putbuf(fd, ucbuf, ucbuflen);
16037 * -1 on error (errno set)
16038 * -2 on security error
16042 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16044 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16045 #endif /* CK_ANSIC */
16047 static char *outbuf = NULL; /* output ciphertext */
16048 #ifdef FTP_SECURITY
16049 static unsigned int bufsize = 0; /* size of outbuf */
16050 #endif /* FTP_SECURITY */
16051 ftp_int32 length = 0;
16052 ftp_uint32 net_len = 0;
16054 /* Other auth types go here ... */
16056 if (ssl_ftp_data_active_flag) {
16059 /* there is no need to send an empty buffer when using SSL/TLS */
16063 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16064 error = SSL_get_error(ssl_ftp_data_con,count);
16066 case SSL_ERROR_NONE:
16068 case SSL_ERROR_WANT_WRITE:
16069 case SSL_ERROR_WANT_READ:
16070 case SSL_ERROR_SYSCALL:
16073 int gle = GetLastError();
16076 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16079 case SSL_ERROR_WANT_X509_LOOKUP:
16080 case SSL_ERROR_SSL:
16081 case SSL_ERROR_ZERO_RETURN:
16083 SSL_shutdown(ssl_ftp_data_con);
16084 SSL_free(ssl_ftp_data_con);
16085 ssl_ftp_data_active_flag = 0;
16086 ssl_ftp_data_con = NULL;
16088 socket_close(data);
16089 #else /* TCPIPLIB */
16090 #ifdef USE_SHUTDOWN
16091 shutdown(data, 1+1);
16092 #endif /* USE_SHUTDOWN */
16094 #endif /* TCPIPLIB */
16101 #endif /* CK_SSL */
16104 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16105 if (bufsize < nbyte + FUDGE_FACTOR) {
16107 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16108 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16109 bufsize = nbyte + FUDGE_FACTOR;
16112 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16117 srp_encode(ftp_dpl == FPL_PRV,
16123 secure_error ("srp_encode failed");
16127 #endif /* FTP_SRP */
16129 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16130 struct sockaddr_in myaddr, hisaddr;
16132 len = sizeof(myaddr);
16133 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16134 secure_error("secure_putbuf: getsockname failed");
16137 len = sizeof(hisaddr);
16138 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16139 secure_error("secure_putbuf: getpeername failed");
16142 if (bufsize < nbyte + FUDGE_FACTOR) {
16144 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16145 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16146 bufsize = nbyte + FUDGE_FACTOR;
16149 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16153 if (ftp_dpl == FPL_PRV) {
16154 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16160 #endif /* KRB524 */
16165 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16170 #endif /* KRB524 */
16175 if (length == -1) {
16176 secure_error("krb_mk_%s failed for KERBEROS_V4",
16177 ftp_dpl == FPL_PRV ? "priv" : "safe");
16181 #endif /* FTP_KRB4 */
16183 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16184 gss_buffer_desc in_buf, out_buf;
16185 OM_uint32 maj_stat, min_stat;
16188 in_buf.value = buf;
16189 in_buf.length = nbyte;
16190 maj_stat = gss_seal(&min_stat, gcontext,
16191 (ftp_dpl == FPL_PRV), /* confidential */
16197 if (maj_stat != GSS_S_COMPLETE) {
16198 /* generally need to deal */
16199 /* ie. should loop, but for now just fail */
16200 user_gss_error(maj_stat, min_stat,
16201 ftp_dpl == FPL_PRV?
16202 "GSSAPI seal failed":
16203 "GSSAPI sign failed");
16206 if (bufsize < out_buf.length) {
16208 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16209 (outbuf = malloc((unsigned) out_buf.length))) {
16210 bufsize = out_buf.length;
16213 secure_error("%s (in malloc of PROT buffer)",
16218 memcpy(outbuf, out_buf.value, length=out_buf.length);
16219 gss_release_buffer(&min_stat, &out_buf);
16221 #endif /* FTP_GSSAPI */
16222 net_len = htonl((ULONG) length);
16223 if (looping_write(fd, (char *)&net_len, 4) == -1)
16225 if (looping_write(fd, outbuf, length) != length)
16231 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16234 secure_getbyte(fd,fc) int fd,fc; {
16235 /* number of chars in ucbuf, pointer into ucbuf */
16236 static unsigned int nin = 0, bufp = 0;
16250 if (check_data_connection(fd,0) < 0)
16252 #endif /* FTP_TIMEOUT */
16255 if (ssl_ftp_data_active_flag) {
16257 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16258 error = SSL_get_error(ssl_ftp_data_con,count);
16260 if (error != SSL_ERROR_NONE)
16261 debug(F101,"ftp secure_getbyte error","",error);
16263 debug(F101,"ftp secure_getbyte count","",count);
16266 case SSL_ERROR_NONE:
16268 nin = bufp = count;
16271 if (fdispla != XYFD_B) {
16273 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16277 case SSL_ERROR_WANT_WRITE:
16278 case SSL_ERROR_WANT_READ:
16279 case SSL_ERROR_SYSCALL:
16282 int gle = GetLastError();
16285 case SSL_ERROR_WANT_X509_LOOKUP:
16286 case SSL_ERROR_SSL:
16287 case SSL_ERROR_ZERO_RETURN:
16289 nin = bufp = count = 0;
16290 SSL_shutdown(ssl_ftp_data_con);
16291 SSL_free(ssl_ftp_data_con);
16292 ssl_ftp_data_active_flag = 0;
16293 ssl_ftp_data_con = NULL;
16295 socket_close(data);
16296 #else /* TCPIPLIB */
16297 #ifdef USE_SHUTDOWN
16298 shutdown(data, 1+1);
16299 #endif /* USE_SHUTDOWN */
16301 #endif /* TCPIPLIB */
16307 #endif /* CK_SSL */
16309 kerror = looping_read(fd, (char *)&length, sizeof(length));
16310 if (kerror != sizeof(length)) {
16311 secure_error("Couldn't read PROT buffer length: %d/%s",
16313 kerror == -1 ? ck_errstr()
16318 debug(F101,"secure_getbyte length","",length);
16319 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16321 length = (ULONG) ntohl(length);
16322 if (length > maxbuf) {
16323 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16329 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16330 secure_error("Couldn't read %u byte PROT buffer: %s",
16332 kerror == -1 ? ck_errstr() : "premature EOF"
16337 /* Other auth types go here ... */
16339 if (strcmp(auth_type, "SRP") == 0) {
16340 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16346 secure_error ("srp_encode failed" );
16350 #endif /* FTP_SRP */
16352 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16353 struct sockaddr_in myaddr, hisaddr;
16355 len = sizeof(myaddr);
16356 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16357 secure_error("secure_putbuf: getsockname failed");
16360 len = sizeof(hisaddr);
16361 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16362 secure_error("secure_putbuf: getpeername failed");
16366 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16371 #endif /* KRB524 */
16372 &hisaddr, &myaddr, &ftp_msg_data);
16374 kerror = krb_rd_safe(ucbuf, length,
16379 #endif /* KRB524 */
16380 &hisaddr, &myaddr, &ftp_msg_data);
16383 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16384 ftp_dpl == FPL_PRV ? "priv" : "safe",
16385 krb_get_err_text(kerror));
16388 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16389 nin = bufp = ftp_msg_data.app_length;
16391 #endif /* FTP_KRB4 */
16393 if (strcmp(auth_type, "GSSAPI") == 0) {
16394 gss_buffer_desc xmit_buf, msg_buf;
16395 OM_uint32 maj_stat, min_stat;
16398 xmit_buf.value = ucbuf;
16399 xmit_buf.length = length;
16400 conf_state = (ftp_dpl == FPL_PRV);
16401 /* decrypt/verify the message */
16402 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16403 &msg_buf, &conf_state, NULL);
16404 if (maj_stat != GSS_S_COMPLETE) {
16405 user_gss_error(maj_stat, min_stat,
16406 (ftp_dpl == FPL_PRV)?
16407 "failed unsealing ENC message":
16408 "failed unsealing MIC message");
16411 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16412 gss_release_buffer(&min_stat, &msg_buf);
16414 #endif /* FTP_GSSAPI */
16415 /* Other auth types go here ... */
16417 /* Update file transfer display */
16420 if (fdispla != XYFD_B) {
16422 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16429 return(ucbuf[bufp - nin--]);
16432 /* secure_getc(fd,fc)
16434 * fd = file descriptor for connection.
16435 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16437 * c>=0 on success (character value)
16439 * -2 on security error
16440 * -3 on timeout (if built with FTP_TIMEOUT defined)
16443 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
16445 if (!ftpissecure()) {
16446 static unsigned int nin = 0, bufp = 0;
16457 if (check_data_connection(fd,0) < 0) {
16458 debug(F100,"secure_getc TIMEOUT","",0);
16463 #endif /* FTP_TIMEOUT */
16465 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16466 if ((nin == 0) || (nin == (unsigned int)-1)) {
16467 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16468 debug(F101,"secure_getc returns EOF","",EOF);
16472 debug(F101,"ftp secure_getc recv","",nin);
16473 ckhexdump("ftp secure_getc recv",ucbuf,16);
16476 if (fdispla != XYFD_B) {
16478 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16481 return(ucbuf[bufp - nin--]);
16483 return(secure_getbyte(fd,fc));
16487 * n>0 on success (n == # of bytes read)
16489 * -1 on error (errno set), only for FPL_CLR
16490 * -2 on security error
16493 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16497 debug(F101,"secure_read bytes requested","",nbyte);
16500 for (i = 0; nbyte > 0; nbyte--) {
16501 c = secure_getc(fd,0);
16503 case -9: /* Canceled from keyboard */
16504 debug(F101,"ftp secure_read interrupted","",c);
16507 debug(F101,"ftp secure_read error","",c);
16510 debug(F101,"ftp secure_read EOF","",c);
16516 debug(F101,"ftp secure_read timeout","",c);
16518 #endif /* FTP_TIMEOUT */
16526 #ifdef USE_RUSERPASS
16529 * Copyright (c) 1985 Regents of the University of California.
16530 * All rights reserved.
16532 * Redistribution and use in source and binary forms, with or without
16533 * modification, are permitted provided that the following conditions
16535 * 1. Redistributions of source code must retain the above copyright
16536 * notice, this list of conditions and the following disclaimer.
16537 * 2. Redistributions in binary form must reproduce the above copyright
16538 * notice, this list of conditions and the following disclaimer in the
16539 * documentation and/or other materials provided with the distribution.
16540 * 3. All advertising materials mentioning features or use of this software
16541 * must display the following acknowledgement:
16542 * This product includes software developed by the University of
16543 * California, Berkeley and its contributors.
16544 * 4. Neither the name of the University nor the names of its contributors
16545 * may be used to endorse or promote products derived from this software
16546 * without specific prior written permission.
16548 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16549 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16550 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16551 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16552 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16553 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16554 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16555 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16556 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16557 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16562 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16563 #endif /* not lint */
16565 #ifndef MAXHOSTNAMELEN
16566 #define MAXHOSTNAMELEN 64
16570 static FILE * cfile;
16580 static char tokval[100];
16582 static struct toktab {
16586 "default", DEFAULT,
16588 "password", PASSWD,
16590 "account", ACCOUNT,
16604 while ((c = getc(cfile)) != EOF &&
16605 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16611 while ((c = getc(cfile)) != EOF && c != '"') {
16618 while ((c = getc(cfile)) != EOF
16619 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16626 if (tokval[0] == 0)
16628 for (t = toktab; t->tokstr; t++)
16629 if (!strcmp(t->tokstr, tokval))
16634 ruserpass(host, aname, apass, aacct)
16635 char *host, **aname, **apass, **aacct;
16637 char *hdir, buf[FTP_BUFSIZ], *tmp;
16638 char myname[MAXHOSTNAMELEN], *mydomain;
16639 int t, i, c, usedefault = 0;
16646 hdir = getenv("HOME");
16649 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16650 cfile = fopen(buf, "r");
16651 if (cfile == NULL) {
16652 if (errno != ENOENT)
16656 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16658 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16662 while ((t = token())) switch(t) {
16673 * Allow match either for user's input host name
16674 * or official hostname. Also allow match of
16675 * incompletely-specified host in local domain.
16677 if (ckstrcmp(host, tokval,-1,1) == 0)
16679 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16681 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16682 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16683 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16684 tokval[tmp - ftp_host] == '\0')
16686 if ((tmp = ckstrchr(host, '.')) != NULL &&
16687 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16688 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16689 tokval[tmp - host] == '\0')
16695 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16700 *aname = malloc((unsigned) strlen(tokval) + 1);
16701 strcpy(*aname, tokval); /* safe */
16703 if (strcmp(*aname, tokval))
16708 if (strcmp(*aname, "anonymous") &&
16709 fstat(fileno(cfile), &stb) >= 0 &&
16710 (stb.st_mode & 077) != 0) {
16711 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16712 fprintf(stderr, "Remove password or correct mode.\n");
16715 if (token() && *apass == 0) {
16716 *apass = malloc((unsigned) strlen(tokval) + 1);
16717 strcpy(*apass, tokval); /* safe */
16721 if (fstat(fileno(cfile), &stb) >= 0
16722 && (stb.st_mode & 077) != 0) {
16723 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16724 fprintf(stderr, "Remove account or correct mode.\n");
16727 if (token() && *aacct == 0) {
16728 *aacct = malloc((unsigned) strlen(tokval) + 1);
16729 strcpy(*aacct, tokval); /* safe */
16734 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16748 #endif /* USE_RUSERPASS */
16750 static char *radixN =
16751 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16753 static char pad = '=';
16756 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16757 CHAR inbuf[], outbuf[];
16758 int inlen, *outlen, decode;
16765 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16766 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16774 outbuf[j++] |= D>>4;
16775 outbuf[j] = (D&15)<<4;
16778 outbuf[j++] |= D>>2;
16779 outbuf[j] = (D&3)<<6;
16789 case 2: if (D&15) return(3);
16790 if (strcmp((char *)&inbuf[i], "==")) return(2);
16792 case 3: if (D&3) return(3);
16793 if (strcmp((char *)&inbuf[i], "=")) return(2);
16797 for (i = 0, j = 0; i < inlen; i++) {
16800 outbuf[j++] = radixN[inbuf[i]>>2];
16801 c = (inbuf[i]&3)<<4;
16804 outbuf[j++] = radixN[c|inbuf[i]>>4];
16805 c = (inbuf[i]&15)<<2;
16808 outbuf[j++] = radixN[c|inbuf[i]>>6];
16809 outbuf[j++] = radixN[inbuf[i]&63];
16815 if (i%3) outbuf[j++] = radixN[c];
16817 case 1: outbuf[j++] = pad;
16818 case 2: outbuf[j++] = pad;
16820 outbuf[*outlen = j] = '\0';
16826 radix_error(e) int e;
16829 case 0: return("Success");
16830 case 1: return("Bad character in encoding");
16831 case 2: return("Encoding not properly padded");
16832 case 3: return("Decoded # of bits not a multiple of 8");
16833 case 4: return("Output buffer too small");
16834 default: return("Unknown error");
16837 /* END_RUSERPASS */
16840 /*---------------------------------------------------------------------------+
16842 | Package: srpftp |
16843 | Author: Eugene Jhong |
16845 +---------------------------------------------------------------------------*/
16848 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16849 * All Rights Reserved.
16851 * Permission is hereby granted, free of charge, to any person obtaining
16852 * a copy of this software and associated documentation files (the
16853 * "Software"), to deal in the Software without restriction, including
16854 * without limitation the rights to use, copy, modify, merge, publish,
16855 * distribute, sublicense, and/or sell copies of the Software, and to
16856 * permit persons to whom the Software is furnished to do so, subject to
16857 * the following conditions:
16859 * The above copyright notice and this permission notice shall be
16860 * included in all copies or substantial portions of the Software.
16862 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16863 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16864 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16866 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16867 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16868 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16869 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16870 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16872 * In addition, the following conditions apply:
16874 * 1. Any software that incorporates the SRP authentication technology
16875 * must display the following acknowlegment:
16876 * "This product uses the 'Secure Remote Password' cryptographic
16877 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16879 * 2. Any software that incorporates all or part of the SRP distribution
16880 * itself must also display the following acknowledgment:
16881 * "This product includes software developed by Tom Wu and Eugene
16882 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16884 * 3. Redistributions in source or binary form must retain an intact copy
16885 * of this copyright notice and list of conditions.
16888 #define SRP_PROT_VERSION 1
16890 #ifdef CK_ENCRYPTION
16891 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16893 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16894 #endif /* CK_ENCRYPTION */
16896 #define SRP_DEFAULT_HASH HASH_ID_SHA
16898 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16899 CHAR srp_pref_hash = HASH_ID_SHA;
16901 static struct t_client *tc = NULL;
16902 static CHAR *skey = NULL;
16903 static krypto_context *incrypt = NULL;
16904 static krypto_context *outcrypt = NULL;
16906 typedef unsigned int srp_uint32;
16908 /*--------------------------------------------------------------+
16909 | srp_selcipher: select cipher |
16910 +--------------------------------------------------------------*/
16912 srp_selcipher (cname) char *cname; {
16915 if (!(cd = cipher_getdescbyname (cname))) {
16917 CHAR *list = cipher_getlist ();
16919 fprintf (stderr, "ftp: supported ciphers:\n\n");
16920 for (i = 0; i < strlen (list); i++)
16921 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16922 fprintf (stderr, "\n");
16925 srp_pref_cipher = cd->id;
16929 /*--------------------------------------------------------------+
16930 | srp_selhash: select hash |
16931 +--------------------------------------------------------------*/
16933 srp_selhash (hname) char *hname; {
16936 if (!(hd = hash_getdescbyname (hname))) {
16938 CHAR *list = hash_getlist ();
16940 fprintf (stderr, "ftp: supported hash functions:\n\n");
16941 for (i = 0; i < strlen (list); i++)
16942 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16943 fprintf (stderr, "\n");
16946 srp_pref_hash = hd->id;
16950 /*--------------------------------------------------------------+
16951 | srp_userpass: get username and password |
16952 +--------------------------------------------------------------*/
16954 srp_userpass (host) char *host; {
16955 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16959 #ifdef USE_RUSERPASS
16960 ruserpass (host, &user, &srp_pass, &srp_acct);
16961 #endif /* USE_RUSERPASS */
16963 while (user == NULL) {
16968 if (!myname) myname = "";
16970 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16971 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16973 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16975 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16976 DEFAULT_UQ_TIMEOUT);
16977 if (!ok || *tmp == '\0')
16980 user = brstrip(tmp);
16982 ckstrncpy (srp_user, user,BUFSIZ);
16986 /*--------------------------------------------------------------+
16987 | srp_reset: reset srp information |
16988 +--------------------------------------------------------------*/
16991 if (tc) { t_clientclose (tc); tc = NULL; }
16992 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16993 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16997 /*--------------------------------------------------------------+
16998 | srp_ftp_auth: perform srp authentication |
16999 +--------------------------------------------------------------*/
17001 srp_ftp_auth(host, user, pass)
17011 CHAR buf[FTP_BUFSIZ];
17012 CHAR tmp[FTP_BUFSIZ];
17014 int n, e, clen, blen, len, i;
17018 srp_pass = srp_acct = 0;
17020 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
17021 if (n != REPLY_CONTINUE) {
17023 fprintf(stderr, "SRP rejected as an authentication type\n");
17025 } else { /* Send protocol version */
17027 memset (vers, 0, 4);
17028 vers[3] = SRP_PROT_VERSION;
17030 printf ("SRP accepted as authentication type.\n");
17031 bp = tmp; blen = 0;
17032 srp_put (vers, &bp, 4, &blen);
17034 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17036 reply_parse = "ADAT=";
17037 n = ftpcmd("ADAT",buf,-1,-1,0);
17039 if (n == REPLY_CONTINUE) { /* Get protocol version */
17044 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17046 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17049 if (host) { /* Get username/password if needed */
17050 srp_userpass (host);
17052 ckstrncpy (srp_user, user, BUFSIZ);
17055 bp = tmp; blen = 0; /* Send username */
17056 srp_put (srp_user, &bp, strlen (srp_user), &blen);
17058 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17060 reply_parse = "ADAT=";
17061 n = ftpcmd("ADAT",buf,-1,-1,0);
17063 if (n == REPLY_CONTINUE) { /* Get N, g and s */
17068 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17070 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17072 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17074 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17076 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17077 fprintf (stderr, "Unable to open SRP client structure.\n");
17080 wp = t_clientgenexp (tc); /* Send wp */
17081 bp = tmp; blen = 0;
17082 srp_put (wp->data, &bp, wp->len, &blen);
17084 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17086 reply_parse = "ADAT=";
17087 n = ftpcmd("ADAT",buf,-1,-1,0);
17089 if (n == REPLY_CONTINUE) { /* Get yp */
17094 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17096 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17099 static char ftppass[PASSBUFSIZ];
17102 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17103 DEFAULT_UQ_TIMEOUT);
17105 srp_pass = brstrip(ftppass);
17107 t_clientpasswd (tc, srp_pass);
17108 memset (srp_pass, 0, strlen (srp_pass));
17109 skey = t_clientgetkey (tc, &yp); /* Send response */
17110 bp = tmp; blen = 0;
17111 srp_put (t_clientresponse (tc), &bp, 20, &blen);
17113 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17115 reply_parse = "ADAT=";
17116 n = ftpcmd("ADAT",buf,-1,-1,0);
17118 if (n == REPLY_CONTINUE) { /* Get response */
17123 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17125 if (srp_get (&bp, &cp, &blen, &clen) != 20)
17127 if (t_clientverify (tc, cp)) {
17128 fprintf (stderr, "WARNING: bad response to client challenge.\n");
17131 bp = tmp; blen = 0; /* Send nothing */
17132 srp_put ("\0", &bp, 1, &blen);
17134 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17136 reply_parse = "ADAT=";
17137 n = ftpcmd("ADAT",buf,-1,-1,0);
17139 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
17144 int clist_len, hlist_len;
17149 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17151 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17153 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17155 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17157 memcpy (seqnum, cp, 4);
17158 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17159 cid = srp_pref_cipher;
17160 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17161 cid = SRP_DEFAULT_CIPHER;
17163 CHAR *loclist = cipher_getlist ();
17164 for (i = 0; i < strlen (loclist); i++)
17165 if (cipher_supported (clist, loclist[i])) {
17171 fprintf (stderr, "Unable to agree on cipher.\n");
17176 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17177 hid = srp_pref_hash;
17179 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17180 hid = SRP_DEFAULT_HASH;
17183 CHAR *loclist = hash_getlist ();
17184 for (i = 0; i < strlen (loclist); i++)
17185 if (hash_supported (hlist, loclist[i])) {
17191 fprintf (stderr, "Unable to agree on hash.\n");
17196 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17200 /* Generate random number for outkey and outseqnum */
17202 t_random (seqnum, 4);
17204 /* Send cid, hid, outkey, outseqnum */
17206 bp = tmp; blen = 0;
17207 srp_put (&cid, &bp, 1, &blen);
17208 srp_put (&hid, &bp, 1, &blen);
17209 srp_put (seqnum, &bp, 4, &blen);
17211 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17213 reply_parse = "ADAT=";
17214 n = ftpcmd("ADAT",buf,-1,-1,0);
17218 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17222 t_clientclose (tc);
17225 if (n != REPLY_COMPLETE)
17231 printf ("SRP authentication succeeded.\n");
17232 printf ("Using cipher %s and hash function %s.\n",
17233 (cipher_getdescbyid(cid))->name,
17234 (hash_getdescbyid(hid))->name
17237 reply_parse = NULL;
17242 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17246 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17250 fprintf (stderr, "Unable to unmarshal authentication data.\n");
17254 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17255 reply_parse = NULL;
17259 /*--------------------------------------------------------------+
17260 | srp_put: put item to send buffer |
17261 +--------------------------------------------------------------*/
17263 srp_put (in, out, inlen, outlen)
17269 srp_uint32 net_len;
17271 net_len = htonl (inlen);
17272 memcpy (*out, &net_len, 4);
17274 *out += 4; *outlen += 4;
17276 memcpy (*out, in, inlen);
17278 *out += inlen; *outlen += inlen;
17282 /*--------------------------------------------------------------+
17283 | srp_get: get item from receive buffer |
17284 +--------------------------------------------------------------*/
17286 srp_get (in, out, inlen, outlen)
17292 srp_uint32 net_len;
17294 if (*inlen < 4) return -1;
17296 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17297 *outlen = ntohl (net_len);
17299 if (*inlen < *outlen) return -1;
17301 *out = *in; *inlen -= *outlen; *in += *outlen;
17306 /*--------------------------------------------------------------+
17307 | srp_encode: encode control message |
17308 +--------------------------------------------------------------*/
17310 srp_encode (private, in, out, len)
17317 return krypto_msg_priv (outcrypt, in, out, len);
17319 return krypto_msg_safe (outcrypt, in, out, len);
17322 /*--------------------------------------------------------------+
17323 | srp_decode: decode control message |
17324 +--------------------------------------------------------------*/
17326 srp_decode (private, in, out, len)
17333 return krypto_msg_priv (incrypt, in, out, len);
17335 return krypto_msg_safe (incrypt, in, out, len);
17338 #endif /* FTP_SRP */
17344 The following code is from the Unix FTP client. Be sure to
17345 make sure that the functionality is not lost. Especially
17346 the Proxy stuff even though we have not yet implemented it.
17349 /* Send multiple files */
17352 ftp_mput(argc, argv) int argc; char **argv; {
17359 if (argc < 2 && !another(&argc, &argv, "local-files")) {
17360 printf("usage: %s local-files\n", argv[0]);
17366 oldintr = signal(SIGINT, mcancel);
17368 /* Replace with calls to cc_execute() */
17372 char *cp, *tp2, tmpbuf[CKMAXPATH];
17374 while ((cp = remglob(argv,0)) != NULL) {
17379 if (mflag && confirm(argv[0], cp)) {
17382 while (*tp && !islower(*tp)) {
17388 while ((*tp2 = *tp) != 0) {
17389 if (isupper(*tp2)) {
17390 *tp2 = 'a' + *tp2 - 'A';
17404 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17405 if (!mflag && fromatty) {
17406 ointer = interactive;
17408 if (confirm("Continue with","mput")) {
17411 interactive = ointer;
17415 signal(SIGINT, oldintr);
17419 #endif /* FTP_PROXY */
17420 for (i = 1; i < argc; i++) {
17421 register char **cpp, **gargs;
17423 if (mflag && confirm(argv[0], argv[i])) {
17425 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17426 if (!mflag && fromatty) {
17427 ointer = interactive;
17429 if (confirm("Continue with","mput")) {
17432 interactive = ointer;
17437 gargs = ftpglob(argv[i]);
17438 if (globerr != NULL) {
17439 printf("%s\n", globerr);
17442 free((char *)gargs);
17446 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17447 if (mflag && confirm(argv[0], *cpp)) {
17449 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17450 if (!mflag && fromatty) {
17451 ointer = interactive;
17453 if (confirm("Continue with","mput")) {
17456 interactive = ointer;
17460 if (gargs != NULL) {
17462 free((char *)gargs);
17465 signal(SIGINT, oldintr);
17469 /* Get multiple files */
17472 ftp_mget(argc, argv) int argc; char **argv; {
17476 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17479 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17480 printf("usage: %s remote-files\n", argv[0]);
17486 oldintr = signal(SIGINT,mcancel);
17487 /* Replace with calls to cc_execute() */
17489 while ((cp = remglob(argv,proxy)) != NULL) {
17494 if (mflag && confirm(argv[0], cp)) {
17497 while (*tp && !islower(*tp)) {
17503 while ((*tp2 = *tp) != 0) {
17504 if (isupper(*tp2)) {
17505 *tp2 = 'a' + *tp2 - 'A';
17513 rc = (recvrequest("RETR", tp, cp, "wb",
17514 tp != cp || !interactive) == 0,0,NULL,0,0,0);
17515 if (!mflag && fromatty) {
17516 ointer = interactive;
17518 if (confirm("Continue with","mget")) {
17521 interactive = ointer;
17525 signal(SIGINT,oldintr);
17530 /* Delete multiple files */
17533 mdelete(argc, argv) int argc; char **argv; {
17539 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17540 printf("usage: %s remote-files\n", argv[0]);
17546 oldintr = signal(SIGINT, mcancel);
17547 /* Replace with calls to cc_execute() */
17549 while ((cp = remglob(argv,0)) != NULL) {
17554 if (mflag && confirm(argv[0], cp)) {
17555 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17556 if (!mflag && fromatty) {
17557 ointer = interactive;
17559 if (confirm("Continue with", "mdelete")) {
17562 interactive = ointer;
17566 signal(SIGINT, oldintr);
17571 /* Get a directory listing of multiple remote files */
17574 mls(argc, argv) int argc; char **argv; {
17577 char *cmd, mode[1], *dest;
17581 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17583 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17585 printf("usage: %s remote-files local-file\n", argv[0]);
17589 dest = argv[argc - 1];
17590 argv[argc - 1] = NULL;
17591 if (strcmp(dest, "-") && *dest != '|')
17592 if (!globulize(&dest) ||
17593 !confirm("output to local-file:", dest)) {
17597 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17600 oldintr = signal(SIGINT, mcancel);
17601 /* Replace with calls to cc_execute() */
17603 for (i = 1; mflag && i < argc-1; ++i) {
17604 *mode = (i == 1) ? 'w' : 'a';
17605 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17606 if (!mflag && fromatty) {
17607 ointer = interactive;
17609 if (confirm("Continue with", argv[0])) {
17612 interactive = ointer;
17615 signal(SIGINT, oldintr);
17621 remglob(argv,doswitch) char *argv[]; int doswitch; {
17623 static char buf[CKMAXPATH];
17624 static FILE *ftemp = NULL;
17625 static char **args;
17634 (void) fclose(ftemp);
17643 if ((cp = *++args) == NULL)
17647 if (ftemp == NULL) {
17648 (void) strcpy(temp, _PATH_TMP);
17651 (void) mktemp(temp);
17652 #endif /* MKSTEMP */
17653 #endif /* MKTEMP */
17655 oldhash = hash, hash = 0;
17660 #endif /* FTP_PROXY */
17661 for (mode = "wb"; *++argv != NULL; mode = "ab")
17662 recvrequest ("NLST", temp, *argv, mode, 0);
17667 #endif /* FTP_PROXY */
17669 ftemp = fopen(temp, "r");
17671 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17672 printf("Can't find list of remote files, oops\n");
17676 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17677 fclose(ftemp), ftemp = NULL;
17680 if ((cp = ckstrchr(buf,'\n')) != NULL)
17684 #endif /* NOT_USED */
17685 #endif /* TCPSOCKET (top of file) */
17686 #endif /* SYSFTP (top of file) */
17687 #endif /* NOFTP (top of file) */