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 } else if (ftp_bug_use_ssl_v3) {
10214 /* allow SSL 3.0 ONLY - previous default */
10215 client_method = SSLv3_client_method();
10217 /* default - allow TLS 1.0 or later */
10218 client_method = TLSv1_client_method();
10220 if (auth_type && !strcmp(auth_type,"TLS")) {
10221 ssl_ftp_ctx=SSL_CTX_new(client_method);
10224 SSL_CTX_set_options(ssl_ftp_ctx,
10225 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10228 ssl_ftp_ctx = SSL_CTX_new(client_method);
10231 SSL_CTX_set_options(ssl_ftp_ctx,
10232 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10233 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10236 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10237 (pem_password_cb *)ssl_passwd_callback);
10238 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10239 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10243 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10245 char path[CKMAXPATH];
10246 extern char exedir[];
10248 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10249 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10250 debug(F110,"ftp ssl_auth unable to load path",path,0);
10251 if (ssl_debug_flag)
10252 printf("?Unable to load verify-dir: %s\r\n",path);
10255 ckmakmsg(path,CKMAXPATH,
10256 (char *)GetAppData(1),"kermit 95/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(0),"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,exedir,"ca_certs.pem",NULL,NULL);
10272 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10273 debug(F110,"ftp ssl_auth unable to load path",path,0);
10274 if (ssl_debug_flag)
10275 printf("?Unable to load verify-file: %s\r\n",path);
10278 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10279 "kermit 95/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(0),
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);
10295 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10298 char path[CKMAXPATH];
10299 extern char exedir[];
10301 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10302 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
10303 debug(F110,"ftp ssl_auth unable to load path",path,0);
10304 if (ssl_debug_flag)
10305 printf("?Unable to load verify-dir: %s\r\n",path);
10307 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10308 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10309 debug(F110,"ftp ssl_auth unable to load path",path,0);
10310 if (ssl_debug_flag)
10311 printf("?Unable to load verify-file: %s\r\n",path);
10316 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10319 if (ssl_verify_file &&
10320 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10322 "ftp ssl auth unable to load ssl_verify_file",
10326 if (ssl_debug_flag)
10327 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10329 if (ssl_verify_dir &&
10330 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10332 "ftp ssl auth unable to load ssl_verify_dir",
10336 if (ssl_debug_flag)
10337 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10340 /* set up the new CRL Store */
10341 crl_store = (X509_STORE *)X509_STORE_new();
10344 char path[CKMAXPATH];
10345 extern char exedir[];
10347 ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
10348 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10349 debug(F110,"ftp ssl auth unable to load dir",path,0);
10350 if (ssl_debug_flag)
10351 printf("?Unable to load crl-dir: %s\r\n",path);
10354 ckmakmsg(path,CKMAXPATH,
10355 (char *)GetAppData(1),"kermit 95/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);
10361 ckmakmsg(path,CKMAXPATH,
10362 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10363 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10364 debug(F110,"ftp ssl auth unable to load dir",path,0);
10365 if (ssl_debug_flag)
10366 printf("?Unable to load crl-dir: %s\r\n",path);
10370 ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
10371 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10372 debug(F110,"ftp ssl auth unable to load file",path,0);
10373 if (ssl_debug_flag)
10374 printf("?Unable to load crl-file: %s\r\n",path);
10377 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10378 "kermit 95/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);
10384 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10385 "kermit 95/ca_crls.pem",NULL,NULL);
10386 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10387 debug(F110,"ftp ssl auth unable to load file",path,0);
10388 if (ssl_debug_flag)
10389 printf("?Unable to load crl-file: %s\r\n",path);
10394 if (ssl_crl_file || ssl_crl_dir) {
10395 if (ssl_crl_file &&
10396 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10398 "ftp ssl auth unable to load ssl_crl_file",
10402 if (ssl_debug_flag)
10403 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10406 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10408 "ftp ssl auth unable to load ssl_crl_dir",
10412 if (ssl_debug_flag)
10413 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10416 X509_STORE_set_default_paths(crl_store);
10419 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10420 ssl_client_verify_callback);
10421 ssl_verify_depth = -1;
10422 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10423 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10424 SSL_set_fd(ssl_ftp_con,csocket);
10425 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10426 if (ssl_cipher_list) {
10427 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10430 if (p = getenv("SSL_CIPHER")) {
10431 SSL_set_cipher_list(ssl_ftp_con,p);
10433 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10436 if (ssl_debug_flag) {
10437 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10440 if (SSL_connect(ssl_ftp_con) <= 0) {
10441 static char errbuf[1024];
10442 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10443 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10444 fprintf(stderr,"%s\n", errbuf);
10446 ssl_ftp_active_flag=0;
10447 SSL_free(ssl_ftp_con);
10448 ssl_ftp_con = NULL;
10450 ssl_ftp_active_flag = 1;
10452 if (!ssl_certsok_flag &&
10453 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
10455 char *subject = ssl_get_subject_name(ssl_ftp_con);
10458 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10459 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10460 return(ssl_ftp_active_flag = 0);
10462 if (uq_ok("Warning: Server didn't provide a certificate\n",
10463 "Continue? (Y/N)",3,NULL,0) <= 0) {
10464 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10465 return(ssl_ftp_active_flag = 0);
10468 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10469 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10470 return(ssl_ftp_active_flag = 0);
10473 debug(F110,"ssl_auth","[SSL - OK]",0);
10474 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10476 if (ssl_debug_flag) {
10477 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10480 return(ssl_ftp_active_flag);
10482 #endif /* CK_SSL */
10485 cmdcancel(sig) int sig; {
10487 /* In Unix we "chain" to trap(), which prints this */
10490 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10492 secure_getc(0,1); /* Initialize net input buffers */
10498 if (ptflag) /* proxy... */
10499 longjmp(ptcancel,1);
10500 #endif /* FTP_PROXY */
10501 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10504 debug(F100,"ftp cmdcancel return from trap()...","",0);
10506 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10513 scommand(char * s) /* Was secure_command() */
10515 scommand(s) char * s;
10516 #endif /* CK_ANSIC */
10518 int length = 0, len2;
10519 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10521 if (ssl_ftp_active_flag) {
10523 length = strlen(s) + 2;
10524 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10525 rc = SSL_write(ssl_ftp_con,out,length);
10526 error = SSL_get_error(ssl_ftp_con,rc);
10528 case SSL_ERROR_NONE:
10530 case SSL_ERROR_WANT_WRITE:
10531 case SSL_ERROR_WANT_READ:
10532 case SSL_ERROR_SYSCALL:
10535 int gle = GetLastError();
10538 case SSL_ERROR_WANT_X509_LOOKUP:
10539 case SSL_ERROR_SSL:
10540 case SSL_ERROR_ZERO_RETURN:
10546 #endif /* CK_SSL */
10548 if (auth_type && ftp_cpl != FPL_CLR) {
10550 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10551 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10555 fprintf(stderr, "SRP failed to encode message\n");
10558 #endif /* FTP_SRP */
10560 if (ck_krb4_is_installed() &&
10561 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10562 if (ftp_cpl == FPL_PRV) {
10564 krb_mk_priv((CHAR *)s, (CHAR *)out,
10565 strlen(s), ftp_sched,
10570 #endif /* KRB524 */
10571 &myctladdr, &hisctladdr);
10574 krb_mk_safe((CHAR *)s,
10581 #endif /* KRB524 */
10582 &myctladdr, &hisctladdr);
10584 if (length == -1) {
10585 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10586 ftp_cpl == FPL_PRV ? "priv" : "safe");
10590 #endif /* FTP_KRB4 */
10592 /* Scommand (based on level) */
10593 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10594 gss_buffer_desc in_buf, out_buf;
10595 OM_uint32 maj_stat, min_stat;
10598 in_buf.length = strlen(s) + 1;
10599 maj_stat = gss_seal(&min_stat, gcontext,
10600 (ftp_cpl==FPL_PRV), /* private */
10602 &in_buf, &conf_state,
10604 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10605 user_gss_error(maj_stat, min_stat,
10606 (ftp_cpl==FPL_PRV)?
10607 "gss_seal ENC didn't complete":
10608 "gss_seal MIC didn't complete");
10609 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10610 fprintf(stderr, "GSSAPI didn't encrypt message");
10613 fprintf(stderr, "sealed (%s) %d bytes\n",
10614 ftp_cpl==FPL_PRV?"ENC":"MIC",
10616 memcpy(out, out_buf.value,
10617 length=out_buf.length);
10618 gss_release_buffer(&min_stat, &out_buf);
10621 #endif /* FTP_GSSAPI */
10622 /* Other auth types go here ... */
10625 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10626 length, &len2, RADIX_ENCODE))
10628 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10629 radix_error(kerror));
10633 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10634 len2 = ckmakmsg(out,
10636 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10641 send(csocket,(SENDARG2TYPE)out,len2,0);
10643 char out[FTP_BUFSIZ];
10644 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10645 send(csocket,(SENDARG2TYPE)out,len,0);
10652 static char inbuf[4096];
10653 static int bp = 0, ep = 0;
10659 if (ssl_ftp_active_flag) {
10661 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10662 error = SSL_get_error(ssl_ftp_con,rc);
10664 case SSL_ERROR_NONE:
10666 case SSL_ERROR_WANT_WRITE:
10667 case SSL_ERROR_WANT_READ:
10669 case SSL_ERROR_SYSCALL:
10670 if (rc == 0) { /* EOF */
10674 int gle = GetLastError();
10678 case SSL_ERROR_WANT_X509_LOOKUP:
10679 case SSL_ERROR_SSL:
10680 case SSL_ERROR_ZERO_RETURN:
10685 #endif /* CK_SSL */
10686 rc = recv(csocket,(char *)inbuf,4096,0);
10691 return(inbuf[bp++]);
10694 /* x l a t e c -- Translate a character */
10697 fc = Function code: 0 = translate, 1 = initialize.
10698 c = Character (as int).
10699 incs = Index of charset to translate from.
10700 outcs = Index of charset to translate to.
10707 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10711 static char buf[128];
10715 if (fc == 1) { /* Initialize */
10716 cx = 0; /* Catch-up buffer write index */
10717 xgnbp = buf; /* Catch-up buffer read pointer */
10718 buf[0] = NUL; /* Buffer is empty */
10721 if (cx >= 127) { /* Catch-up buffer full */
10722 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10723 printf("?Translation buffer overflow\n");
10726 /* Add char to buffer. */
10727 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10729 debug(F000,"xlatec buf",ckitoa(cx),c);
10733 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10734 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10737 /* If we're caught up, reinitialize the buffer */
10738 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10739 #endif /* NOCSETS */
10743 /* p a r s e f e a t */
10745 /* Note: for convenience we align keyword values with table indices */
10746 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10748 static struct keytab feattab[] = {
10749 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10750 { "AUTH", SFT_AUTH, 0 },
10751 { "LANG", SFT_LANG, 0 },
10752 { "MDTM", SFT_MDTM, 0 },
10753 { "MLST", SFT_MLST, 0 },
10754 { "PBSZ", SFT_PBSZ, 0 },
10755 { "PROT", SFT_PROT, 0 },
10756 { "REST", SFT_REST, 0 },
10757 { "SIZE", SFT_SIZE, 0 },
10758 { "TVFS", SFT_TVFS, 0 },
10759 { "UTF8", SFT_UTF8, 0 }
10761 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10763 #define FACT_CSET 1
10764 #define FACT_CREA 2
10765 #define FACT_LANG 3
10766 #define FACT_MTYP 4
10767 #define FACT_MDTM 5
10768 #define FACT_PERM 6
10769 #define FACT_SIZE 7
10770 #define FACT_TYPE 8
10771 #define FACT_UNIQ 9
10773 static struct keytab facttab[] = {
10774 { "CHARSET", FACT_CSET, 0 },
10775 { "CREATE", FACT_CREA, 0 },
10776 { "LANG", FACT_LANG, 0 },
10777 { "MEDIA-TYPE", FACT_MTYP, 0 },
10778 { "MODIFY", FACT_MDTM, 0 },
10779 { "PERM", FACT_PERM, 0 },
10780 { "SIZE", FACT_SIZE, 0 },
10781 { "TYPE", FACT_TYPE, 0 },
10782 { "UNIQUE", FACT_UNIQ, 0 }
10784 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10786 static struct keytab ftyptab[] = {
10787 { "CDIR", FTYP_CDIR, 0 },
10788 { "DIR", FTYP_DIR, 0 },
10789 { "FILE", FTYP_FILE, 0 },
10790 { "PDIR", FTYP_PDIR, 0 }
10792 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10795 parsefeat(s) char * s; { /* Parse a FEATURE response */
10802 for (i = 0; i < 4; i++) {
10807 if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10810 /* xlookup requires a full (but case independent) match */
10811 i = xlookup(feattab,kwbuf,nfeattab,&x);
10812 debug(F111,"ftp parsefeat",s,i);
10813 if (i < 0 || i > 15)
10817 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10818 sfttab[i] = mdtmok;
10819 if (mdtmok) sfttab[0]++;
10821 case SFT_MLST: /* ditto */
10822 sfttab[i] = mlstok;
10823 if (mlstok) sfttab[0]++;
10825 case SFT_SIZE: /* ditto */
10826 sfttab[i] = sizeok;
10827 if (sizeok) sfttab[0]++;
10829 case SFT_AUTH: /* ditto */
10830 sfttab[i] = ftp_aut;
10831 if (ftp_aut) sfttab[0]++;
10833 default: /* Others */
10840 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10843 if (!s) return(NULL);
10844 if (!*s) return(NULL);
10846 /* Maybe we should make a copy of s so we can poke it... */
10848 while ((p = ckstrchr(s,'='))) {
10849 *p = NUL; /* s points to fact */
10850 i = xlookup(facttab,s,nfacttab,&x);
10851 debug(F111,"ftp parsefact fact",s,i);
10853 s = p+1; /* Now s points to arg */
10854 p = ckstrchr(s,';');
10856 p = ckstrchr(s,SP);
10858 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10862 debug(F110,"ftp parsefact valu",s,0);
10864 case FACT_CSET: /* Ignore these for now */
10871 case FACT_MDTM: /* Modtime */
10872 makestr(&havemdtm,s);
10873 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10875 case FACT_SIZE: /* Size */
10876 havesize = ckatofs(s);
10877 debug(F101,"ftp parsefact size","",havesize);
10879 case FACT_TYPE: /* Type */
10880 j = xlookup(ftyptab,s,nftyptab,NULL);
10881 debug(F111,"ftp parsefact type",s,j);
10882 havetype = (j < 1) ? 0 : j;
10886 s = p+1; /* s points next fact or name */
10888 while (*s == SP) /* Skip past spaces. */
10890 if (!*s) /* Make sure we still have a name */
10892 debug(F110,"ftp parsefact name",s,0);
10896 /* g e t r e p l y -- (to an FTP command sent to server) */
10898 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10901 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10902 /* lcs, rcs, vbm parameters as in ftpcmd() */
10903 register int i, c, n;
10909 int originalcode = 0, continuation = 0;
10913 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10917 auth = (fc == GRF_AUTH);
10920 debug(F101,"ftp getreply lcs","",lcs);
10921 debug(F101,"ftp getreply rcs","",rcs);
10922 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10924 initxlate(rcs,lcs);
10925 xlatec(1,0,rcs,lcs);
10927 #endif /* NOCSETS */
10928 debug(F101,"ftp getreply fc","",fc);
10936 if (ftp_deb) /* DEBUG */
10938 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10940 else if (vbm < 0) /* VERBOSE */
10945 reply_ptr = reply_buf;
10947 oldintr = signal(SIGINT, cmdcancel);
10948 for (count = 0;; count++) {
10950 dig = n = ftpcode = i = 0;
10951 cp = ftp_reply_str;
10952 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10953 if (c == IAC) { /* Handle telnet commands */
10954 switch (c = mygetc()) {
10963 if (ssl_ftp_active_flag) {
10965 rc = SSL_write(ssl_ftp_con,obuf,3);
10966 error = SSL_get_error(ssl_ftp_con,rc);
10968 case SSL_ERROR_NONE:
10970 case SSL_ERROR_WANT_WRITE:
10971 case SSL_ERROR_WANT_READ:
10973 case SSL_ERROR_SYSCALL:
10974 if (rc == 0) { /* EOF */
10978 int gle = GetLastError();
10982 case SSL_ERROR_WANT_X509_LOOKUP:
10983 case SSL_ERROR_SSL:
10984 case SSL_ERROR_ZERO_RETURN:
10989 #endif /* CK_SSL */
10990 send(csocket,(SENDARG2TYPE)obuf,3,0);
11000 if (ssl_ftp_active_flag) {
11002 rc = SSL_write(ssl_ftp_con,obuf,3);
11003 error = SSL_get_error(ssl_ftp_con,rc);
11005 case SSL_ERROR_NONE:
11007 case SSL_ERROR_WANT_WRITE:
11008 case SSL_ERROR_WANT_READ:
11009 signal(SIGINT,oldintr);
11011 case SSL_ERROR_SYSCALL:
11012 if (rc == 0) { /* EOF */
11016 int gle = GetLastError();
11020 case SSL_ERROR_WANT_X509_LOOKUP:
11021 case SSL_ERROR_SSL:
11022 case SSL_ERROR_ZERO_RETURN:
11027 #endif /* CK_SSL */
11028 send(csocket,(SENDARG2TYPE)obuf,3,0);
11038 signal(SIGINT,oldintr);
11040 debug(F101,"ftp getreply EOF","",ftpcode);
11048 "Service not available, connection closed by server\n");
11051 signal(SIGINT,oldintr);
11053 debug(F101,"ftp getreply EOF","",ftpcode);
11056 if (n == 0) { /* First digit */
11057 n = c; /* Save it */
11061 !ssl_ftp_active_flag &&
11062 #endif /* CK_SSL */
11063 !ibuf[0] && (n == '6' || continuation)) {
11064 if (c != '\r' && dig > 4)
11069 !ssl_ftp_active_flag &&
11070 #endif /* CK_SSL */
11071 !ibuf[0] && dig == 1 && vbm)
11072 printf("Unauthenticated reply received from server:\n");
11077 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11080 (ftp_deb || ((vbm || (!auth && n == '5')) &&
11081 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11085 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11086 printf("%s:",ftp_host);
11087 #endif /* FTP_PROXY */
11094 xlatec(0,c,rcs,lcs);
11098 #endif /* NOCSETS */
11105 !ssl_ftp_active_flag &&
11106 #endif /* CK_SSL */
11107 !ibuf[0] && n != '6')
11109 if (dig < 4 && isdigit(c))
11110 ftpcode = ftpcode * 10 + (c - '0');
11111 if (!pflag && ftpcode == 227)
11113 if (dig > 4 && pflag == 1 && isdigit(c))
11116 if (c != '\r' && c != ')')
11123 if (dig == 4 && c == '-' && n != '6') {
11128 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11136 Sometimes we need to print the server reply. printlines is nonzero for any
11137 command where the results are sent back on the control connection rather
11138 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
11139 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
11140 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
11141 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11142 lines from UNIX. Further experimentation needed with other servers. Of
11143 course RFC959 is mute as to the format of the server reply.
11145 'printlines' is also true for PWD and BYE.
11147 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11149 /* No, we can't be that clever -- it breaks other things like RPWD... */
11151 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11152 #endif /* COMMENT */
11155 char *r = ftp_reply_str;
11156 *q-- = NUL; /* NUL-terminate */
11157 while (*q < '!' && q > r) /* Strip CR, etc */
11159 if (!ftp_deb && printlines) { /* If printing */
11160 if (ftpcode != 0) /* strip ftpcode if any */
11163 printf("%s\n",r); /* and print */
11167 } else { /* Translating */
11168 xgnbp = r; /* Set up strgetc() */
11169 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11170 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
11171 signal(SIGINT,oldintr);
11177 #endif /* NOCSETS */
11180 debug(F110,"FTP RCVD ",ftp_reply_str,0);
11182 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
11183 if (count == 0 && n == '2') {
11184 int i; /* (Re)-init server FEATure table */
11185 debug(F100,"ftp getreply clearing feature table","",0);
11186 for (i = 0; i < 16; i++)
11189 parsefeat((char *)ftp_reply_str);
11194 !ssl_ftp_active_flag &&
11195 #endif /* CK_SSL */
11196 !ibuf[0] && n != '6') {
11197 signal(SIGINT,oldintr);
11198 return(getreply(expecteof,lcs,rcs,vbm,auth));
11200 ibuf[0] = obuf[i] = '\0';
11201 if (ftpcode && n == '6')
11202 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11203 printf("Unknown reply: %d %s\n", ftpcode, obuf);
11205 } else safe = (ftpcode == 631);
11206 if (obuf[0] /* if there is a string to decode */
11208 && !ssl_ftp_active_flag /* and not SSL/TLS */
11209 #endif /* CK_SSL */
11212 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11215 #ifndef CK_ENCRYPTION
11216 else if (ftpcode == 632) {
11217 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11220 #endif /* CK_ENCRYPTION */
11221 #ifdef NOCONFIDENTIAL
11222 else if (ftpcode == 633) {
11223 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11226 #endif /* NOCONFIDENTIAL */
11228 int len = FTP_BUFSIZ;
11229 if ((kerror = radix_encode((CHAR *)obuf,
11235 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11236 ftpcode, radix_error(kerror), obuf);
11240 else if (strcmp(auth_type, "SRP") == 0) {
11242 outlen = srp_decode(!safe, (CHAR *)ibuf,
11243 (CHAR *) ibuf, len);
11245 printf("Warning: %d reply %s!\n",
11246 ftpcode, safe ? "modified" : "garbled");
11249 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11251 printf("%c:", safe ? 'S' : 'P');
11255 #endif /* FTP_SRP */
11257 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11259 kerror = krb_rd_safe((CHAR *)ibuf, len,
11264 #endif /* KRB524 */
11270 kerror = krb_rd_priv((CHAR *)ibuf, len,
11276 #endif /* KRB524 */
11282 if (kerror != KSUCCESS) {
11283 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11284 safe ? "modified" : "garbled",
11285 safe ? "safe" : "priv",
11286 krb_get_err_text(kerror));
11288 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11291 printf("reply data too large for buffer\n");
11294 printf("%c:", safe ? 'S' : 'P');
11295 memcpy(ibuf,ftp_msg_data.app_data,
11296 ftp_msg_data.app_length);
11297 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11298 FTP_BUFSIZ - ftp_msg_data.app_length);
11302 #endif /* FTP_KRB4 */
11304 else if (strcmp(auth_type, "GSSAPI") == 0) {
11305 gss_buffer_desc xmit_buf, msg_buf;
11306 OM_uint32 maj_stat, min_stat;
11308 xmit_buf.value = ibuf;
11309 xmit_buf.length = len;
11310 /* decrypt/verify the message */
11312 maj_stat = gss_unseal(&min_stat, gcontext,
11313 &xmit_buf, &msg_buf,
11314 &conf_state, NULL);
11315 if (maj_stat != GSS_S_COMPLETE) {
11316 user_gss_error(maj_stat, min_stat,
11317 "failed unsealing reply");
11320 memcpy(ibuf, msg_buf.value, msg_buf.length);
11321 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11322 FTP_BUFSIZ-msg_buf.length);
11323 gss_release_buffer(&min_stat,&msg_buf);
11325 printf("%c:", safe ? 'S' : 'P');
11329 #endif /* FTP_GSSAPI */
11330 /* Other auth types go here... */
11332 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11333 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11338 xlatec(0,c,rcs,lcs);
11342 #endif /* NOCSETS */
11345 if (continuation && ftpcode != originalcode) {
11346 if (originalcode == 0)
11347 originalcode = ftpcode;
11353 signal(SIGINT,oldintr);
11354 if (ftpcode == 421 || originalcode == 421) {
11356 if (!xquiet && !ftp_deb)
11357 printf("%s\n",reply_buf);
11359 if ((cancelfile != 0) &&
11361 /* Ultrix 3.0 cc objects violently to this clause */
11362 (oldintr != cmdcancel) &&
11363 #endif /* ULTRIX3 */
11364 (oldintr != SIG_IGN)) {
11366 (*oldintr)(SIGINT);
11370 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11371 reply_parse = reply_ptr + strlen(reply_parse);
11372 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11375 reply_parse = reply_ptr;
11377 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11379 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11387 empty(fd_set * mask, int sec)
11389 empty(mask, sec) fd_set * mask; int sec;
11390 #endif /* CK_ANSIC */
11393 t.tv_sec = (long) sec;
11395 debug(F100,"ftp empty calling select...","",0);
11397 x = select(32, (int *)mask, NULL, NULL, &t);
11399 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11400 #endif /* INTSELECT */
11401 debug(F101,"ftp empty select","",x);
11404 #else /* BSDSELECT */
11407 empty(mask, cnt, sec) int * mask, sec;
11410 return(select(mask,cnt,0,0,sec*1000));
11412 #endif /* IBMSELECT */
11413 #endif /* BSDSELECT */
11416 cancelsend(sig) int sig; {
11420 printf(" Canceled...\n");
11421 secure_getc(0,1); /* Initialize net input buffers */
11422 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11425 longjmp(sendcancel, 1);
11433 secure_error(char *fmt, ...)
11436 secure_error(fmt, p1, p2, p3, p4, p5)
11437 char *fmt; int p1, p2, p3, p4, p5;
11438 #endif /* CK_ANSIC */
11444 vfprintf(stderr, fmt, ap);
11447 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11449 fprintf(stderr, "\n");
11453 * Internal form of settype; changes current type in use with server
11454 * without changing our notion of the type for data transfers.
11455 * Used to change to and from ascii for listings.
11458 changetype(newtype, show) int newtype, show; {
11462 if ((newtype == curtype) && typesent++)
11478 rc = ftpcmd("TYPE",s,-1,-1,show);
11479 if (rc == REPLY_COMPLETE)
11483 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11487 doftpsend(void * threadinfo)
11489 doftpsend(threadinfo) VOID * threadinfo;
11493 if (threadinfo) { /* Thread local storage... */
11494 TlsSetValue(TlsIndex,threadinfo);
11495 debug(F100, "doftpsend called with threadinfo block","", 0);
11496 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11505 #endif /* CK_LOGIN */
11510 /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11512 /* If the connection failed and we are using an HTTP Proxy
11513 * and the reason for the failure was an authentication
11514 * error, then we need to give the user to ability to
11515 * enter a username and password, just like a browser.
11517 * I tried to do all of this within the netopen() call
11518 * but it is much too much work.
11520 while (y != 0 && tcp_http_proxy != NULL ) {
11522 if (tcp_http_proxy_errno == 401 ||
11523 tcp_http_proxy_errno == 407 ) {
11524 char uid[UIDBUFLEN];
11526 struct txtbox tb[2];
11530 tb[0].t_len = UIDBUFLEN;
11531 tb[0].t_lbl = "Proxy Userid: ";
11532 tb[0].t_dflt = NULL;
11536 tb[1].t_lbl = "Proxy Passphrase: ";
11537 tb[1].t_dflt = NULL;
11540 ok = uq_mtxt("Proxy Server Authentication Required\n",
11542 if (ok && uid[0]) {
11543 char * proxy_user, * proxy_pwd;
11545 proxy_user = tcp_http_proxy_user;
11546 proxy_pwd = tcp_http_proxy_pwd;
11548 tcp_http_proxy_user = uid;
11549 tcp_http_proxy_pwd = pwd;
11553 debug(F101,"doftpsend","initconn",y);
11554 memset(pwd,0,PWDSIZ);
11555 tcp_http_proxy_user = proxy_user;
11556 tcp_http_proxy_pwd = proxy_pwd;
11564 #endif /* NOHTTP */
11565 signal(SIGINT, ftpsnd.oldintr);
11567 if (ftpsnd.oldintp)
11568 signal(SIGPIPE, ftpsnd.oldintp);
11569 #endif /* SIGPIPE */
11574 ckThreadEnd(threadinfo);
11579 #endif /* NOHTTP */
11583 ckThreadEnd(threadinfo);
11589 failftpsend(void * threadinfo)
11591 failftpsend(threadinfo) VOID * threadinfo;
11592 #endif /* CK_ANSIC */
11595 if (threadinfo) { /* Thread local storage... */
11596 TlsSetValue(TlsIndex,threadinfo);
11597 debug(F100, "docmdfile called with threadinfo block","", 0);
11598 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11607 #endif /* CK_LOGIN */
11610 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11611 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11615 if (ssl_ftp_data_active_flag) {
11616 SSL_shutdown(ssl_ftp_data_con);
11617 SSL_free(ssl_ftp_data_con);
11618 ssl_ftp_data_active_flag = 0;
11619 ssl_ftp_data_con = NULL;
11621 #endif /* CK_SSL */
11623 socket_close(data);
11624 #else /* TCPIPLIB */
11625 #ifdef USE_SHUTDOWN
11626 shutdown(data, 1+1);
11627 #endif /* USE_SHUTDOWN */
11629 #endif /* TCPIPLIB */
11633 if (ftpsnd.oldintr)
11634 signal(SIGINT,ftpsnd.oldintr);
11636 if (ftpsnd.oldintp)
11637 signal(SIGPIPE,ftpsnd.oldintp);
11638 #endif /* SIGPIPE */
11641 /* TEST ME IN K95 */
11644 debug(F100,"ftp failftpsend chain to trap()...","",0);
11645 if (ftpsnd.oldintr != SIG_IGN)
11646 (*ftpsnd.oldintr)(SIGINT);
11647 /* NOTREACHED (I hope!) */
11648 debug(F100,"ftp failftpsend return from trap()...","",0);
11655 failftpsend2(void * threadinfo)
11657 failftpsend2(threadinfo) VOID * threadinfo;
11658 #endif /* CK_ANSIC */
11661 if (threadinfo) { /* Thread local storage... */
11662 TlsSetValue(TlsIndex,threadinfo);
11663 debug(F100, "docmdfile called with threadinfo block","", 0);
11664 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11673 #endif /* CK_LOGIN */
11675 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11678 fpfsecs = gftimer();
11679 #endif /* GFTIMER */
11684 #endif /* PIPESEND */
11685 signal(SIGINT, ftpsnd.oldintr);
11687 if (ftpsnd.oldintp)
11688 signal(SIGPIPE, ftpsnd.oldintp);
11689 #endif /* SIGPIPE */
11694 ckThreadEnd(threadinfo);
11700 if (ssl_ftp_data_active_flag) {
11701 SSL_shutdown(ssl_ftp_data_con);
11702 SSL_free(ssl_ftp_data_con);
11703 ssl_ftp_data_active_flag = 0;
11704 ssl_ftp_data_con = NULL;
11706 #endif /* CK_SSL */
11708 socket_close(data);
11709 #else /* TCPIPLIB */
11710 #ifdef USE_SHUTDOWN
11711 shutdown(data, 1+1);
11712 #endif /* USE_SHUTDOWN */
11714 #endif /* TCPIPLIB */
11720 socket_close(dout);
11721 #else /* TCPIPLIB */
11722 #ifdef USE_SHUTDOWN
11723 shutdown(dout, 1+1);
11724 #endif /* USE_SHUTDOWN */
11726 #endif /* TCPIPLIB */
11728 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11733 /* TEST ME IN K95 */
11736 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11737 if (ftpsnd.oldintr != SIG_IGN)
11738 (*ftpsnd.oldintr)(SIGINT);
11739 /* NOTREACHED (I hope!) */
11740 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11747 doftpsend2(void * threadinfo)
11749 doftpsend2(threadinfo) VOID * threadinfo;
11752 register int c, d = 0;
11753 int n, t, x, notafile, unique = 0;
11757 if (threadinfo) { /* Thread local storage... */
11758 TlsSetValue(TlsIndex,threadinfo);
11759 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11760 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11769 #endif /* CK_LOGIN */
11771 buf = ftpsndbuf; /* (not on stack) */
11773 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11774 notafile = sndarray || pipesend;
11777 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11779 changetype(FTT_BIN,0); /* Change to binary */
11781 /* Ask for remote file's size */
11782 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11784 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11785 p = &ftp_reply_str[4]; /* Parse it */
11786 while (isdigit(*p)) {
11787 sendstart = sendstart * 10 + (int)(*p - '0');
11790 if (*p && *p != CR) { /* Bad number */
11791 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11792 sendstart = (CK_OFF_T)0;
11793 } else if (sendstart > fsize) { /* Remote file bigger than local */
11794 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11795 sendstart = (CK_OFF_T)0;
11797 /* Local is newer */
11798 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11799 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11800 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11801 sendstart = (CK_OFF_T)0; /* Send the whole file */
11804 changetype(ftp_typ,0); /* Change back to appropriate type */
11805 if (sendstart > (CK_OFF_T)0) { /* Still restarting? */
11806 if (sendstart == fsize) { /* Same size - no need to send */
11807 debug(F111,"doftpsend2 /restart SKIP",
11808 ckfstoa(fsize),sendstart);
11810 ftpsndret = SKP_RES;
11812 ckThreadEnd(threadinfo);
11816 errno = 0; /* Restart needed, seek to the spot */
11817 if (zfseek((long)sendstart) < 0) {
11818 debug(F111,"doftpsend2 zfseek fails",
11819 ftpsnd.local,sendstart);
11820 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11825 ckThreadEnd(threadinfo);
11830 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11831 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11832 if (x != REPLY_CONTINUE) {
11837 ckThreadEnd(threadinfo);
11841 ftpsnd.cmd = "STOR";
11844 sendmode = SM_RESEND;
11845 ftpsnd.cmd = "APPE";
11846 #endif /* COMMENT */
11847 /* sendstart = (CK_OFF_T)0; */
11850 #endif /* FTP_RESTART */
11852 if (unique && !stouarg) /* If we know STOU accepts no arg */
11853 ftpsnd.remote = NULL; /* don't include one. */
11855 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11856 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11857 debug(F101,"doftpsend2 ftpcmd","",x);
11859 if (x != REPLY_PRELIM && unique) {
11861 RFC959 says STOU does not take an argument. But every FTP server
11862 I've encountered but one accepts the arg and constructs the unique
11863 name from it, which is better than making up a totally random name
11864 for the file, which is what RFC959 calls for. Especially because
11865 there is no way for the client to find out the name chosen by the
11866 server. So we try STOU with the argument first, which works with
11867 most servers, and if it fails we retry it without the arg, for
11868 the benefit of the one picky server that is not "liberal in what
11869 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11870 which means STOU is not accepted, period.
11872 if ((x == 5) && stouarg && (ftpcode != 502)) {
11873 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11874 if (x == REPLY_PRELIM) /* If accepted */
11875 stouarg = 0; /* flag no STOU arg for this server */
11878 if (x != REPLY_PRELIM) {
11879 signal(SIGINT, ftpsnd.oldintr);
11881 if (ftpsnd.oldintp)
11882 signal(SIGPIPE, ftpsnd.oldintp);
11883 #endif /* SIGPIPE */
11884 debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11889 #endif /* PIPESEND */
11892 ckThreadEnd(threadinfo);
11896 debug(F100,"doftpsend2 getting data connection...","",0);
11897 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11898 debug(F101,"doftpsend2 dataconn","",dout);
11900 failftpsend2(threadinfo);
11902 ckThreadEnd(threadinfo);
11906 /* Initialize per-file stats */
11907 ffc = (CK_OFF_T)0; /* Character counter */
11908 cps = oldcps = 0L; /* Thruput */
11911 rftimer(); /* reset f.p. timer */
11912 #endif /* GFTIMER */
11915 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11916 #endif /* SIGPIPE */
11917 debug(F101,"doftpsend2 curtype","",curtype);
11919 case FTT_BIN: /* Binary mode */
11924 This is because VMS zxin() is C-Library fread()
11925 but the file was opened with zopeni(), which is RMS.
11927 while (((c = zminchar()) > -1) && !cancelfile) {
11929 if (zzout(dout,c) < 0)
11933 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11936 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11937 ckhexdump("doftpsend2 zxin",buf,16);
11939 if (ssl_ftp_data_active_flag) {
11940 for (bufp = buf; n > 0; n -= d, bufp += d) {
11941 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11945 if (fdispla != XYFD_B) {
11947 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11951 #endif /* CK_SSL */
11952 for (bufp = buf; n > 0; n -= d, bufp += d) {
11953 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11958 if (fdispla != XYFD_B) {
11960 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11965 #endif /* CK_SSL */
11971 debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11973 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11974 if (d < 0 || (d = secure_flush(dout)) < 0) {
11975 if (d == -1 && errno && errno != EPIPE)
11981 case FTT_ASC: /* Text mode */
11983 if (ftpsnd.xlate) { /* With translation */
11984 initxlate(ftpsnd.incs,ftpsnd.outcs);
11985 while (!cancelfile) {
11986 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11987 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11990 #endif /* NOCSETS */
11991 /* Text mode, no translation */
11992 while (((c = zminchar()) > -1) && !cancelfile) {
12000 #endif /* NOCSETS */
12001 if (dout == -1 || (d = secure_flush(dout)) < 0) {
12002 if (d == -1 && errno && errno != EPIPE)
12008 tfc += ffc; /* Total file chars */
12010 fpfsecs = gftimer();
12011 #endif /* GFTIMER */
12012 zclose(ZIFILE); /* Close input file */
12014 if (sndfilter) /* Undo this (it's per file) */
12016 #endif /* PIPESEND */
12019 if (ssl_ftp_data_active_flag) {
12020 SSL_shutdown(ssl_ftp_data_con);
12021 SSL_free(ssl_ftp_data_con);
12022 ssl_ftp_data_active_flag = 0;
12023 ssl_ftp_data_con = NULL;
12025 #endif /* CK_SSL */
12028 socket_close(dout); /* Close data connection */
12029 #else /* TCPIPLIB */
12030 #ifdef USE_SHUTDOWN
12031 shutdown(dout, 1+1);
12032 #endif /* USE_SHUTDOWN */
12034 #endif /* TCPIPLIB */
12035 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12036 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
12038 if (ftpsnd.oldintp)
12039 signal(SIGPIPE, ftpsnd.oldintp);
12040 #endif /* SIGPIPE */
12041 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12042 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12045 ckThreadEnd(threadinfo);
12048 } else if (cancelfile) {
12049 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12052 ckThreadEnd(threadinfo);
12056 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12059 ckThreadEnd(threadinfo);
12064 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12065 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12067 if (!remote) remote = ""; /* Check args */
12068 if (!*remote) remote = local;
12069 if (!local) local = "";
12070 if (!*local) return(-1);
12071 if (!cmd) cmd = "";
12072 if (!*cmd) cmd = "STOR";
12074 debug(F111,"ftp sendrequest restart",local,restart);
12076 nout = 0; /* Init output buffer count */
12077 ftpsnd.bytes = 0; /* File input byte count */
12082 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12085 #endif /* FTP_PROXY */
12087 changetype(ftp_typ,0); /* Change type for this file */
12089 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
12090 ftpsnd.oldintp = NULL;
12091 ftpsnd.restart = restart;
12092 ftpsnd.xlate = xlate;
12093 ftpsnd.lmode = "wb";
12095 #ifdef PIPESEND /* Use Kermit API for file i/o... */
12097 char * p = NULL, * q;
12100 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12102 debug(F110,"sendrequest pipesend filter",sndfilter,0);
12103 zzstring(sndfilter,&p,&n);
12104 debug(F111,"sendrequest pipename",q,n);
12106 printf("?Sorry, send filter + filename too long, %d max.\n",
12112 ckstrncpy(filnam,q,CKMAXPATH+1);
12119 if (sndfilter) /* If sending thru a filter */
12120 pipesend = 1; /* set this for open and i/o */
12121 #endif /* PIPESEND */
12124 debug(F101,"XXX before openi binary","",binary);
12125 debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12128 if (openi(local) == 0) /* Try to open the input file */
12132 debug(F101,"XXX after openi binary","",binary);
12133 debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12135 if (binary != ftp_typ) { /* VMS zopeni() sets binary */
12136 debug(F101,"XXX changing type","",binary);
12138 debug(F101,"XXX after doftptyp","",ftp_typ);
12141 if (displa && fdispla) { /* Update file type display */
12142 ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12148 ftpsnd.incs = incs;
12149 ftpsnd.outcs = outcs;
12151 ftpsnd.local = local;
12152 ftpsnd.remote = remote;
12153 ftpsnd.oldintr = signal(SIGINT, cancelsend);
12156 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12160 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12167 cancelrecv(sig) int sig; {
12171 secure_getc(0,1); /* Initialize net input buffers */
12172 printf(" Canceling...\n");
12173 debug(F100,"ftp cancelrecv caught SIGINT","",0);
12176 if (fp_nml != stdout)
12181 longjmp(recvcancel, 1);
12187 /* Argumentless front-end for secure_getc() */
12191 return(secure_getc(globaldin,0));
12194 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12197 Sets ftpcode < 0 on failure if failure reason is not server reply code:
12198 -1: interrupted by user.
12199 -2: error opening or writing output file (reason in errno).
12200 -3: failure to make data connection.
12201 -4: network read error (reason in errno).
12204 struct xx_ftprecv {
12212 sig_t oldintr, oldintp;
12219 CK_OFF_T localsize;
12221 static struct xx_ftprecv ftprecv;
12223 static int ftprecvret = 0;
12227 failftprecv(VOID * threadinfo)
12229 failftprecv(threadinfo) VOID * threadinfo;
12230 #endif /* CK_ANSIC */
12233 if (threadinfo) { /* Thread local storage... */
12234 TlsSetValue(TlsIndex,threadinfo);
12235 debug(F100, "docmdfile called with threadinfo block","", 0);
12236 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12246 #endif /* CK_LOGIN */
12249 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12253 if (ssl_ftp_data_active_flag) {
12254 SSL_shutdown(ssl_ftp_data_con);
12255 SSL_free(ssl_ftp_data_con);
12256 ssl_ftp_data_active_flag = 0;
12257 ssl_ftp_data_con = NULL;
12259 #endif /* CK_SSL */
12261 socket_close(data);
12262 #else /* TCPIPLIB */
12263 #ifdef USE_SHUTDOWN
12264 shutdown(data, 1+1);
12265 #endif /* USE_SHUTDOWN */
12267 #endif /* TCPIPLIB */
12271 if (ftprecv.oldintr)
12272 signal(SIGINT, ftprecv.oldintr);
12277 /* TEST ME IN K95 */
12280 debug(F100,"ftp failftprecv chain to trap()...","",0);
12281 if (ftprecv.oldintr != SIG_IGN)
12282 (*ftprecv.oldintr)(SIGINT);
12283 /* NOTREACHED (I hope!) */
12284 debug(F100,"ftp failftprecv return from trap()...","",0);
12292 doftprecv(VOID * threadinfo)
12294 doftprecv(threadinfo) VOID * threadinfo;
12295 #endif /* CK_ANSIC */
12298 if (threadinfo) { /* Thread local storage... */
12299 TlsSetValue(TlsIndex,threadinfo);
12300 debug(F100, "docmdfile called with threadinfo block","", 0);
12301 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12310 #endif /* CK_LOGIN */
12313 if (!out2screen && !ftprecv.pipename) {
12316 local = ftprecv.local;
12319 if ((!dpyactive || ftp_deb))
12321 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12322 signal(SIGINT, ftprecv.oldintr);
12326 ckThreadEnd(threadinfo);
12331 #endif /* COMMENT */
12332 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12333 if (initconn()) { /* Initialize the data connection */
12334 signal(SIGINT, ftprecv.oldintr);
12338 ckThreadEnd(threadinfo);
12342 secure_getc(0,1); /* Initialize net input buffers */
12346 ckThreadEnd(threadinfo);
12352 failftprecv2(VOID * threadinfo)
12354 failftprecv2(threadinfo) VOID * threadinfo;
12355 #endif /* CK_ANSIC */
12358 if (threadinfo) { /* Thread local storage... */
12359 TlsSetValue(TlsIndex,threadinfo);
12360 debug(F100, "docmdfile called with threadinfo block","", 0);
12361 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12370 #endif /* CK_LOGIN */
12372 /* Cancel using RFC959 recommended IP,SYNC sequence */
12374 debug(F100,"ftp recvrequest CANCEL","",0);
12376 fpfsecs = gftimer();
12377 #endif /* GFTIMER */
12379 if (ftprecv.oldintp)
12380 signal(SIGPIPE, ftprecv.oldintr);
12381 #endif /* SIGPIPE */
12382 signal(SIGINT, SIG_IGN);
12385 signal(SIGINT, ftprecv.oldintr);
12388 ckThreadEnd(threadinfo);
12392 cancel_remote(ftprecv.din);
12395 if (ftp_timed_out && out2screen && !quiet)
12396 printf("\n?Timed out.\n");
12397 #endif /* FTP_TIMEOUT */
12403 if (ssl_ftp_data_active_flag) {
12404 SSL_shutdown(ssl_ftp_data_con);
12405 SSL_free(ssl_ftp_data_con);
12406 ssl_ftp_data_active_flag = 0;
12407 ssl_ftp_data_con = NULL;
12409 #endif /* CK_SSL */
12411 socket_close(data);
12412 #else /* TCPIPLIB */
12413 #ifdef USE_SHUTDOWN
12414 shutdown(data, 1+1);
12415 #endif /* USE_SHUTDOWN */
12417 #endif /* TCPIPLIB */
12423 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12425 switch (keep) { /* which is... */
12426 case SET_AUTO: /* AUTO */
12427 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12430 case SET_OFF: /* DISCARD */
12431 x = 1; /* Delete file, period. */
12433 default: /* KEEP */
12437 x = zdelet(ftprecv.local);
12438 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12443 socket_close(ftprecv.din);
12444 #else /* TCPIPLIB */
12445 #ifdef USE_SHUTDOWN
12446 shutdown(ftprecv.din, 1+1);
12447 #endif /* USE_SHUTDOWN */
12448 close(ftprecv.din);
12449 #endif /* TCPIPLIB */
12451 signal(SIGINT, ftprecv.oldintr);
12456 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12458 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12461 if (ftprecv.oldintr != SIG_IGN)
12462 (*ftprecv.oldintr)(SIGINT);
12463 /* NOTREACHED (I hope!) */
12464 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12471 doftprecv2(VOID * threadinfo)
12473 doftprecv2(threadinfo) VOID * threadinfo;
12474 #endif /* CK_ANSIC */
12477 CK_OFF_T bytes = (CK_OFF_T)0;
12480 ULONG start = 0L, stop;
12482 static char * rcvbuf = NULL;
12483 static int rcvbufsiz = 0;
12485 char newname[CKMAXPATH+1]; /* For file dialog */
12486 #endif /* CK_URL */
12487 extern int adl_ask;
12491 #endif /* FTP_TIMEOUT */
12495 if (threadinfo) { /* Thread local storage... */
12496 TlsSetValue(TlsIndex,threadinfo);
12497 debug(F100, "docmdfile called with threadinfo block","", 0);
12498 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12507 #endif /* CK_LOGIN */
12509 if (ftprecv.recover) { /* Initiate recovery */
12510 x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12511 debug(F111,"ftp reply","REST",x);
12512 if (x == REPLY_CONTINUE) {
12513 ftprecv.lmode = "ab";
12514 rs_len = ftprecv.localsize;
12516 ftprecv.recover = 0;
12519 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12521 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12523 /* Send the command and get reply */
12524 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12525 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12527 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12529 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12530 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12532 ckThreadEnd(threadinfo);
12536 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12537 globaldin = ftprecv.din; /* Global copy of file descriptor */
12538 if (ftprecv.din == -1) { /* Check for failure */
12539 ftpcode = -3; /* Code for no data connection */
12542 ckThreadEnd(threadinfo);
12547 /* In K95 GUI put up a file box */
12548 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12551 "\r\nIncoming file from FTP server...\r\n\
12552 Please confirm output file specification or supply an alternative:";
12554 x = uq_file(preface, /* K95 GUI: Put up file box. */
12558 ftprecv.local ? ftprecv.local : ftprecv.remote,
12563 ftprecv.local = newname; /* Substitute user's file name */
12564 if (x == 2) /* And append if user said to */
12565 ftprecv.lmode = "ab";
12568 #endif /* CK_URL */
12569 x = 1; /* Output file open OK? */
12570 if (ftprecv.pipename) { /* Command */
12571 x = zxcmd(ZOFILE,ftprecv.pipename);
12572 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12573 } else if (!out2screen) { /* File */
12575 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12576 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12577 /* Append or New */
12578 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12579 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12580 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12582 if (x < 1) { /* Failure to open output file */
12583 if ((!dpyactive || ftp_deb))
12584 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12587 ckThreadEnd(threadinfo);
12591 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12593 debug(F101,"ftp recvrequest blksize","",blksize);
12594 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12596 if (rcvbufsiz < blksize) { /* if necessary */
12601 rcvbuf = (char *)malloc((unsigned)blksize);
12603 debug(F100,"ftp get rcvbuf malloc failed","",0);
12607 #endif /* ENOMEM */
12608 if ((!dpyactive || ftp_deb))
12613 ckThreadEnd(threadinfo);
12617 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12618 rcvbufsiz = blksize;
12620 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12622 ffc = (CK_OFF_T)0; /* Character counter */
12623 cps = oldcps = 0L; /* Thruput */
12624 start = gmstimer(); /* Start time (msecs) */
12626 rftimer(); /* Start time (float) */
12627 #endif /* GFTIMER */
12629 debug(F111,"ftp get type",ftprecv.local,curtype);
12630 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12632 case FTT_BIN: /* Binary mode */
12633 case FTT_TEN: /* TENEX mode */
12637 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12639 failftprecv2(threadinfo);
12641 ckThreadEnd(threadinfo);
12647 #ifdef printf /* (What if it isn't?) */
12648 if (out2screen && !ftprecv.pipename) {
12650 for (i = 0; i < c; i++)
12651 printf("%c",rcvbuf[i]);
12653 #endif /* printf */
12659 if (zmchout(rcvbuf[i++]) < 0) {
12670 debug(F100,"ftp recvrequest timeout","",0);
12671 bytes = (CK_OFF_T)-1;
12675 #endif /* FTP_TIMEOUT */
12677 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12678 if (c == -1 && errno != EPIPE)
12679 if ((!dpyactive || ftp_deb))
12681 bytes = (CK_OFF_T)-1;
12686 if ((!dpyactive || ftp_deb)) {
12688 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12691 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12694 "%s: short write\n", ftprecv.local);
12699 case FTT_ASC: /* Text mode */
12700 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12702 if (ftprecv.xlate) {
12708 #endif /* CK_ANSIC */
12709 debug(F110,"ftp recvrequest (data)","initxlate",0);
12710 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12711 if (ftprecv.pipename) {
12713 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12715 fn = out2screen ? scrnout : putfil;
12716 debug(F110,"ftp recvrequest ASCII",
12717 out2screen ? "scrnout" : "putfil",0);
12720 /* Get byte from net */
12721 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12723 failftprecv2(threadinfo);
12725 ckThreadEnd(threadinfo);
12731 /* Second byte from net */
12732 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12734 failftprecv2(threadinfo);
12736 ckThreadEnd(threadinfo);
12743 /* K95: Check whether we need this */
12744 if (fileorder > 0) /* Little Endian */
12745 bytswap(&c0,&c1); /* swap bytes*/
12746 #endif /* COMMENT */
12749 if ( out2screen && /* we're translating to UCS-2 */
12750 !k95stdout && !inserver) /* for the real screen... */
12757 output.bytes[0] = c1;
12758 output.bytes[1] = c0;
12760 VscrnWrtUCS2StrAtt(VCMD,
12771 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12772 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12776 #endif /* NOCSETS */
12778 c = secure_getc(ftprecv.din,0);
12782 #endif /* FTP_TIMEOUT */
12784 failftprecv2(threadinfo);
12786 ckThreadEnd(threadinfo);
12790 if (c < 0 || c == EOF)
12793 /* Record format conversion for Unix */
12794 /* SKIP THIS FOR WINDOWS! */
12797 while (c == '\r') {
12799 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12802 failftprecv2(threadinfo);
12804 ckThreadEnd(threadinfo);
12808 if (c < 0 || c == EOF)
12820 if (out2screen && !ftprecv.pipename)
12822 printf("%c",(char)c);
12825 #endif /* printf */
12827 if ((d = zmchout(c)) < 0)
12835 if (bare_lfs && (!dpyactive || ftp_deb)) {
12836 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12838 printf("File might not have transferred correctly.\n");
12840 if (ftprecv.din == -1) {
12841 bytes = (CK_OFF_T)-1;
12844 bytes = (CK_OFF_T)-1;
12848 #endif /* NOCSETS */
12850 if (ftprecv.pipename || !out2screen) {
12851 zclose(ZOFILE); /* Close the file */
12852 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12853 if (ftpcode < 0) { /* If download failed */
12855 switch (keep) { /* which is... */
12856 case SET_AUTO: /* AUTO */
12857 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12860 case SET_OFF: /* DISCARD */
12861 x = 1; /* Delete file, period. */
12863 default: /* KEEP */
12867 x = zdelet(ftprecv.local);
12868 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12872 signal(SIGINT, ftprecv.oldintr);
12874 if (ftprecv.oldintp)
12875 signal(SIGPIPE, ftprecv.oldintp);
12876 #endif /* SIGPIPE */
12879 fpfsecs = gftimer();
12880 #endif /* GFTIMER */
12884 socket_close(ftprecv.din);
12885 #else /* TCPIPLIB */
12886 #ifdef USE_SHUTDOWN
12887 shutdown(ftprecv.din, 1+1);
12888 #endif /* USE_SHUTDOWN */
12889 close(ftprecv.din);
12890 #endif /* TCPIPLIB */
12891 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12892 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12893 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12895 ckThreadEnd(threadinfo);
12900 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12902 char *cmd, *local, *remote, *lmode, *pipename;
12903 int printnames, recover, xlate, fcs, rcs;
12906 struct _stat stbuf;
12913 debug(F111,"ftp recvrequest cmd",cmd,recover);
12914 debug(F110,"ftp recvrequest local ",local,0);
12915 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12916 debug(F110,"ftp recvrequest pipename ",pipename,0);
12917 debug(F101,"ftp recvrequest xlate","",xlate);
12918 debug(F101,"ftp recvrequest fcs","",fcs);
12919 debug(F101,"ftp recvrequest rcs","",rcs);
12923 ftprecv.localsize = (CK_OFF_T)0;
12925 if (remfile) { /* See remcfm(), remtxt() */
12927 pipename = remdest;
12930 if (remappd) lmode = "ab";
12934 if (!cmd) cmd = ""; /* Core dump prevention */
12935 if (!remote) remote = "";
12936 if (!lmode) lmode = "";
12938 if (pipename) { /* No recovery for pipes. */
12943 if (!local) /* Output to screen? */
12945 out2screen = !strcmp(local,"-");
12947 debug(F101,"ftp recvrequest out2screen","",out2screen);
12950 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12954 if (out2screen) /* No recovery to screen */
12956 if (!ftp_typ) /* No recovery in text mode */
12958 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12960 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12964 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12965 if (recursive && ckstrchr(local,'/')) {
12969 #endif /* COMMENT */
12971 ftprecv.localsize = (CK_OFF_T)0; /* Local file size */
12972 rs_len = (CK_OFF_T)0; /* Recovery point */
12974 debug(F101,"ftp recvrequest recover","",recover);
12975 if (recover) { /* Recovering... */
12976 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12977 debug(F101,"ftp recvrequest recover stat failed","",errno);
12978 recover = 0; /* So cancel recovery */
12979 } else { /* Have local file info */
12980 ftprecv.localsize = stbuf.st_size; /* Get size */
12981 /* Remote file smaller than local */
12982 if (fsize < ftprecv.localsize) {
12983 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12984 recover = 0; /* Recovery can't work */
12985 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12986 debug(F111,"ftp recvrequest recover equal size",
12987 remote,ftprecv.localsize);
12992 The problem here is that the original partial file never got its date
12993 set, either because FTP DATES was OFF, or because the partial file was
12994 downloaded by some other program that doesn't set local file dates, or
12995 because Kermit only sets the file's date when the download was complete
12996 and successful. In all these cases, the local file has a later time
12999 if (recover) { /* Remote is bigger */
13000 x = chkmodtime(local,remote,0); /* Check file dates */
13001 debug(F111,"ftp recvrequest chkmodtime",remote,x);
13002 if (x != 1) /* Dates must be equal! */
13003 recover = 0; /* If not, get whole file */
13005 #endif /* COMMENT */
13007 debug(F111,"ftp recvrequest recover",remote,recover);
13011 if (proxy && ftprecv.is_retr)
13012 return(proxtrans(cmd, local ? local : remote, remote));
13013 #endif /* FTP_PROXY */
13015 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
13020 ftprecv.recover = recover;
13021 ftprecv.xlate = xlate;
13023 ftprecv.local = local;
13024 ftprecv.remote = remote;
13025 ftprecv.lmode = lmode;
13026 ftprecv.pipename = pipename;
13027 ftprecv.oldintp = NULL;
13031 ftprecv.oldintr = signal(SIGINT, cancelrecv);
13032 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13036 debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13037 debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13040 #endif /* FTP_TIMEOUT */
13042 if (ftprecvret < 0)
13045 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13051 * Need to start a listen on the data channel before we send the command,
13052 * otherwise the server's connect may fail.
13056 register char *p, *a;
13057 int result, tmpno = 0;
13061 #ifndef NO_PASSIVE_MODE
13062 int a1,a2,a3,a4,p1,p2;
13065 data = socket(AF_INET, SOCK_STREAM, 0);
13068 perror("ftp: socket");
13071 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13072 printf("Passive mode refused\n");
13074 return(initconn());
13077 Now we have a string of comma-separated one-byte unsigned integer values,
13078 The first four are the an IP address. The fifth is the MSB of the port
13079 number, the sixth is the LSB. From that we can make a sockaddr_in.
13081 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13082 printf("Passive mode address scan failure\n");
13086 if (tcp_http_proxy) {
13088 char * agent = "Kermit 95"; /* Default user agent */
13090 char * agent = "C-Kermit";
13092 register struct hostent *hp = 0;
13093 struct servent *destsp;
13094 char host[512], *p, *q;
13096 #ifdef IPTOS_THROUGHPUT
13098 #endif /* IPTOS_THROUGHPUT */
13099 #endif /* IP_TOS */
13108 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13109 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13112 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13113 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13117 hisctladdr.sin_addr.s_addr = inet_addr(host);
13118 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13120 debug(F110,"initconn A",host,0);
13121 hisctladdr.sin_family = AF_INET;
13123 debug(F110,"initconn B",host,0);
13124 hp = gethostbyname(host);
13126 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13127 #endif /* HADDRLIST */
13129 fprintf(stderr, "ftp: %s: Unknown host\n", host);
13136 hisctladdr.sin_family = hp->h_addrtype;
13138 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13139 sizeof(hisctladdr.sin_addr));
13140 #else /* HADDRLIST */
13141 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13142 sizeof(hisctladdr.sin_addr));
13143 #endif /* HADDRLIST */
13145 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13146 debug(F101,"initconn socket","",data);
13148 perror("ftp: socket");
13160 destsp = getservbyname(p,"tcp");
13162 hisctladdr.sin_port = destsp->s_port;
13164 hisctladdr.sin_port = htons(atoi(p));
13166 hisctladdr.sin_port = htons(80);
13169 debug(F100,"initconn HADDRLIST","",0);
13172 debug(F100,"initconn no HADDRLIST","",0);
13174 #endif /* HADDRLIST */
13175 (connect(data, (struct sockaddr *)&hisctladdr,
13176 sizeof (hisctladdr)) < 0) {
13177 debug(F101,"initconn connect failed","",errno);
13179 if (hp && hp->h_addr_list[1]) {
13180 int oerrno = errno;
13183 "ftp: connect to address %s: ",
13184 inet_ntoa(hisctladdr.sin_addr)
13187 perror("ftphookup");
13189 memcpy((char *)&hisctladdr.sin_addr,
13190 hp->h_addr_list[0],
13191 sizeof(hisctladdr.sin_addr));
13192 fprintf(stdout, "Trying %s...\n",
13193 inet_ntoa(hisctladdr.sin_addr));
13195 socket_close(data);
13196 #else /* TCPIPLIB */
13198 #endif /* TCPIPLIB */
13199 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13201 perror("ftp: socket");
13210 #endif /* HADDRLIST */
13211 perror("ftp: connect");
13215 if (http_connect(data,
13216 tcp_http_proxy_agent ?
13217 tcp_http_proxy_agent :
13220 tcp_http_proxy_user,
13221 tcp_http_proxy_pwd,
13226 socket_close(data);
13227 #else /* TCPIPLIB */
13229 #endif /* TCPIPLIB */
13230 perror("ftp: connect");
13235 #endif /* NOHTTP */
13237 data_addr.sin_family = AF_INET;
13238 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13239 data_addr.sin_port = htons((p1<<8)|p2);
13242 (struct sockaddr *)&data_addr,
13243 sizeof(data_addr)) < 0
13245 perror("ftp: connect");
13249 debug(F100,"initconn connect ok","",0);
13251 #ifdef IPTOS_THROUGHPUT
13252 on = IPTOS_THROUGHPUT;
13253 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13254 perror("ftp: setsockopt TOS (ignored)");
13255 #endif /* IPTOS_THROUGHPUT */
13256 #endif /* IP_TOS */
13257 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13260 #endif /* NO_PASSIVE_MODE */
13263 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13265 data_addr.sin_port = 0; /* let system pick one */
13268 socket_close(data);
13269 #else /* TCPIPLIB */
13270 #ifdef USE_SHUTDOWN
13271 shutdown(data, 1+1);
13272 #endif /* USE_SHUTDOWN */
13274 #endif /* TCPIPLIB */
13276 data = socket(AF_INET, SOCK_STREAM, 0);
13279 perror("ftp: socket");
13285 if (setsockopt(data,
13292 perror("ftp: setsockopt (reuse address)");
13296 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13297 perror("ftp: bind");
13300 len = sizeof (data_addr);
13301 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13302 perror("ftp: getsockname");
13305 if (listen(data, 1) < 0) {
13306 perror("ftp: listen");
13310 a = (char *)&data_addr.sin_addr;
13311 p = (char *)&data_addr.sin_port;
13312 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13313 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13314 UC(p[0]),",", UC(p[1]));
13315 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13316 if (result == REPLY_ERROR && sendport) {
13321 return(result != REPLY_COMPLETE);
13326 #ifdef IPTOS_THROUGHPUT
13327 on = IPTOS_THROUGHPUT;
13328 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13329 perror("ftp: setsockopt TOS (ignored)");
13335 socket_close(data);
13336 #else /* TCPIPLIB */
13337 #ifdef USE_SHUTDOWN
13338 shutdown(data, 1+1);
13339 #endif /* USE_SHUTDOWN */
13341 #endif /* TCPIPLIB */
13352 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
13353 SSL_free(ssl_ftp_data_con);
13354 ssl_ftp_data_con=NULL;
13356 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13358 SSL_set_fd(ssl_ftp_data_con,data);
13359 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13361 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13363 if (ssl_debug_flag) {
13364 fprintf(stderr,"=>START SSL connect on DATA\n");
13367 if (SSL_connect(ssl_ftp_data_con) <= 0) {
13368 static char errbuf[1024];
13369 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13370 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13371 fprintf(stderr,"%s\n", errbuf);
13374 socket_close(data);
13375 #else /* TCPIPLIB */
13376 #ifdef USE_SHUTDOWN
13377 shutdown(data, 1+1);
13378 #endif /* USE_SHUTDOWN */
13380 #endif /* TCPIPLIB */
13385 ssl_ftp_data_active_flag=1;
13387 if (!ssl_certsok_flag &&
13388 (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
13390 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13393 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13394 debug(F110,"dataconn","[SSL _- FAILED]",0);
13396 ssl_ftp_data_active_flag = 0;
13398 socket_close(data);
13399 #else /* TCPIPLIB */
13400 #ifdef USE_SHUTDOWN
13401 shutdown(data, 1+1);
13402 #endif /* USE_SHUTDOWN */
13404 #endif /* TCPIPLIB */
13409 if (!out2screen && displa && fdispla) {
13410 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13411 /* fdispla = XYFD_B; */
13415 "Warning: Server didn't provide a certificate on data connection\n",
13416 "Continue with file transfer? (Y/N)",
13418 debug(F110, "dataconn","[SSL - FAILED]",0);
13419 ssl_ftp_data_active_flag = 0;
13421 socket_close(data);
13422 #else /* TCPIPLIB */
13423 #ifdef USE_SHUTDOWN
13424 shutdown(data, 1+1);
13425 #endif /* USE_SHUTDOWN */
13427 #endif /* TCPIPLIB */
13434 if (!out2screen && displa && fdispla == XYFD_C) {
13435 ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13436 /* fdispla = XYFD_B; */
13439 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13440 debug(F110,"dataconn","[SSL - FAILED]",0);
13441 ssl_ftp_data_active_flag = 0;
13443 socket_close(data);
13444 #else /* TCPIPLIB */
13445 #ifdef USE_SHUTDOWN
13446 shutdown(data, 1+1);
13447 #endif /* USE_SHUTDOWN */
13449 #endif /* TCPIPLIB */
13456 debug(F110,"dataconn","[SSL - OK]",0);
13458 /* This messes up the full screen file transfer display */
13459 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13460 #endif /* COMMENT */
13462 if (ssl_debug_flag) {
13463 fprintf(stderr,"=>DONE SSL connect on DATA\n");
13468 #endif /* CK_SSL */
13471 dataconn(lmode) char *lmode; {
13475 #endif /* IP_TOS */
13477 static u_int fromlen;
13479 static SOCKOPT_T fromlen;
13482 fromlen = sizeof(hisdataaddr);
13484 #ifndef NO_PASSIVE_MODE
13487 ssl_ftp_data_active_flag=0;
13488 if (ssl_ftp_active_flag &&
13489 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13490 return(ssl_dataconn());
13491 #endif /* CK_SSL */
13494 #endif /* NO_PASSIVE_MODE */
13496 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13498 perror("ftp: accept");
13500 socket_close(data);
13501 #else /* TCPIPLIB */
13502 #ifdef USE_SHUTDOWN
13503 shutdown(data, 1+1);
13504 #endif /* USE_SHUTDOWN */
13506 #endif /* TCPIPLIB */
13512 socket_close(data);
13513 #else /* TCPIPLIB */
13514 #ifdef USE_SHUTDOWN
13515 shutdown(data, 1+1);
13516 #endif /* USE_SHUTDOWN */
13518 #endif /* TCPIPLIB */
13522 #ifdef IPTOS_THROUGHPUT
13523 tos = IPTOS_THROUGHPUT;
13524 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13525 perror("ftp: setsockopt TOS (ignored)");
13526 #endif /* IPTOS_THROUGHPUT */
13527 #endif /* IP_TOS */
13530 ssl_ftp_data_active_flag=0;
13531 if (ssl_ftp_active_flag &&
13532 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13533 return(ssl_dataconn());
13534 #endif /* CK_SSL */
13540 pscancel(sig) int sig; {
13545 pswitch(flag) int flag; {
13548 static struct comvars {
13550 char name[MAXHOSTNAMELEN];
13551 struct sockaddr_in mctl;
13552 struct sockaddr_in hctl;
13565 char mi[CKMAXPATH];
13566 char mo[CKMAXPATH];
13571 des_cblock session;
13572 des_key_schedule ftp_sched;
13573 #endif /* FTP_KRB4 */
13575 gss_ctx_id_t gcontext;
13576 #endif /* GSSAPI */
13577 } proxstruct, tmpstruct;
13578 struct comvars *ip, *op;
13581 oldintr = signal(SIGINT, pscancel);
13595 ip->connect = connected;
13596 connected = op->connect;
13598 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13599 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13600 ip->name[strlen(ip->name)] = '\0';
13603 ftp_host = op->name;
13604 ip->hctl = hisctladdr;
13605 hisctladdr = op->hctl;
13606 ip->mctl = myctladdr;
13607 myctladdr = op->mctl;
13614 ip->curtpe = curtype;
13615 curtype = op->curtpe;
13618 ip->sunqe = ftp_usn;
13619 ftp_usn = op->sunqe;
13622 ip->ntflg = ntflag;
13623 ntflag = op->ntflg;
13624 strncpy(ip->nti, ntin, 16);
13625 (ip->nti)[strlen(ip->nti)] = '\0';
13626 strcpy(ntin, op->nti);
13627 strncpy(ip->nto, ntout, 16);
13628 (ip->nto)[strlen(ip->nto)] = '\0';
13629 strcpy(ntout, op->nto);
13630 ip->mapflg = mapflag;
13631 mapflag = op->mapflg;
13632 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13633 (ip->mi)[strlen(ip->mi)] = '\0';
13634 strcpy(mapin, op->mi);
13635 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13636 (ip->mo)[strlen(ip->mo)] = '\0';
13637 strcpy(mapout, op->mo);
13638 ip->authtype = auth_type;
13639 auth_type = op->authtype;
13640 ip->clvl = ftp_cpl;
13641 ftp_cpl = op->clvl;
13642 ip->dlvl = ftp_dpl;
13643 ftp_dpl = op->dlvl;
13649 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13650 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13651 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13652 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13653 #endif /* FTP_KRB4 */
13655 ip->gcontext = gcontext;
13656 gcontext = op->gcontext;
13657 #endif /* GSSAPI */
13658 signal(SIGINT, oldintr);
13661 debug(F101,"pswitch cancelfile B","",cancelfile);
13662 (*oldintr)(SIGINT);
13667 cancelpt(sig) int sig; {
13673 longjmp(ptcancel, 1);
13680 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13682 int secndflag = 0, prox_type, nfnd;
13686 #endif /* BSDSELECT */
13687 sigtype cancelpt();
13689 if (strcmp(cmd, "RETR"))
13692 cmd2 = unique ? "STOU" : "STOR";
13693 if ((prox_type = type) == 0) {
13694 if (servertype == SYS_UNIX && unix_proxy)
13695 prox_type = FTT_BIN;
13697 prox_type = FTT_ASC;
13699 if (curtype != prox_type)
13700 changetype(prox_type, 1);
13701 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13702 printf("Proxy server does not support third party transfers.\n");
13707 printf("No primary connection\n");
13712 if (curtype != prox_type)
13713 changetype(prox_type, 1);
13715 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13720 /* Replace with calls to cc_execute() */
13721 if (setjmp(ptcancel))
13723 oldintr = signal(SIGINT, cancelpt);
13724 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13725 signal(SIGINT, oldintr);
13732 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13735 getreply(0,-1,-1,ftp_vbm,0);
13737 getreply(0,-1,-1,ftp_vbm,0);
13738 signal(SIGINT, oldintr);
13744 signal(SIGINT, SIG_IGN);
13746 if (strcmp(cmd, "RETR") && !proxy)
13748 else if (!strcmp(cmd, "RETR") && proxy)
13750 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13751 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13759 signal(SIGINT, oldintr);
13765 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13766 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13773 signal(SIGINT, oldintr);
13783 FD_SET(csocket, &mask);
13784 if ((nfnd = empty(&mask, 10)) <= 0) {
13792 #else /* BSDSELECT */
13794 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13802 #endif /* IBMSELECT */
13803 #endif /* BSDSELECT */
13804 getreply(0,-1,-1,ftp_vbm,0);
13805 getreply(0,-1,-1,ftp_vbm,0);
13812 signal(SIGINT, oldintr);
13814 #endif /* FTP_PROXY */
13816 #ifdef FTP_SECURITY
13820 /* ck_gss_mech_krb5 is not declared anywhere */
13822 CONST gss_OID_desc * CONST * mech_type;
13823 char *service_name;
13825 { &ck_gss_mech_krb5, "ftp" },
13826 { &ck_gss_mech_krb5, "host" },
13829 /* This matches what is declared above */
13831 CONST gss_OID_desc * CONST * mech_type;
13832 char *service_name;
13834 { &gss_mech_krb5, "ftp" },
13835 { &gss_mech_krb5, "host" },
13837 #endif /* COMMENT */
13840 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13841 #endif /* FTP_GSSAPI */
13845 extern int setsafe();
13848 char *service, inst[INST_SZ];
13850 ULONG checksum = (ULONG) getpid();
13851 CHAR out_buf[FTP_BUFSIZ];
13853 #else /* FTP_KRB4 */
13855 CHAR out_buf[FTP_BUFSIZ];
13857 #endif /* FTP_GSSAPI */
13858 #endif /* FTP_KRB4 */
13860 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13864 return(1); /* auth already succeeded */
13866 /* Try each auth type as specified by the end user */
13867 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13869 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13870 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13871 if (n == REPLY_CONTINUE) {
13872 OM_uint32 maj_stat, min_stat;
13873 gss_name_t target_name;
13874 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13875 char stbuf[FTP_BUFSIZ];
13876 int comcode, trial;
13877 struct gss_channel_bindings_struct chan;
13878 char * realm = NULL;
13881 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13882 chan.initiator_address.length = 4;
13883 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13884 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13885 chan.acceptor_address.length = 4;
13886 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13887 chan.application_data.length = 0;
13888 chan.application_data.value = 0;
13891 printf("GSSAPI accepted as authentication type\n");
13893 realm = ck_krb5_realmofhost(ftp_user_host);
13895 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13896 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13897 if ( krb5_autoget &&
13898 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13899 (ck_krb5_is_tgt_valid() > 0)) )
13900 ck_krb5_autoget_TGT(realm);
13903 /* Blob from gss-client */
13904 for (trial = 0; trial < n_gss_trials; trial++) {
13905 /* ftp@hostname first, the host@hostname */
13906 /* the V5 GSSAPI binding canonicalizes this for us... */
13907 ckmakmsg(stbuf,FTP_BUFSIZ,
13908 gss_trials[trial].service_name,
13915 "Authenticating to <%s>...\n", stbuf);
13916 send_tok.value = stbuf;
13917 send_tok.length = strlen(stbuf);
13918 maj_stat = gss_import_name(&min_stat, &send_tok,
13919 gss_nt_service_name,
13922 if (maj_stat != GSS_S_COMPLETE) {
13923 user_gss_error(maj_stat, min_stat, "parsing name");
13924 secure_error("name parsed <%s>\n", stbuf);
13927 token_ptr = GSS_C_NO_BUFFER;
13928 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13932 fprintf(stderr, "calling gss_init_sec_context\n");
13934 gss_init_sec_context(&min_stat,
13935 GSS_C_NO_CREDENTIAL,
13939 gss_trials[trial].mech_type,
13940 GSS_C_MUTUAL_FLAG |
13941 GSS_C_REPLAY_FLAG |
13943 GSS_C_DELEG_FLAG : 0),
13945 /* channel bindings */
13946 (krb5_d_no_addresses ?
13947 GSS_C_NO_CHANNEL_BINDINGS :
13950 NULL, /* ignore mech type */
13952 NULL, /* ignore ret_flags */
13954 ); /* ignore time_rec */
13956 if (maj_stat != GSS_S_COMPLETE &&
13957 maj_stat != GSS_S_CONTINUE_NEEDED) {
13958 if (trial == n_gss_trials-1)
13959 user_gss_error(maj_stat,
13961 "initializing context"
13963 gss_release_name(&min_stat, &target_name);
13964 /* maybe we missed on the service name */
13967 if (send_tok.length != 0) {
13969 reply_parse = "ADAT="; /* for ftpcmd() later */
13972 radix_encode(send_tok.value,
13980 "Base 64 encoding failed: %s\n",
13981 radix_error(kerror)
13983 goto gss_complete_loop;
13985 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13986 if (comcode != REPLY_COMPLETE
13987 && comcode != REPLY_CONTINUE /* (335) */
13989 if (trial == n_gss_trials-1) {
13990 fprintf(stderr, "GSSAPI ADAT failed\n");
13991 /* force out of loop */
13992 maj_stat = GSS_S_FAILURE;
13995 Backoff to the v1 gssapi is still possible.
13996 Send a new AUTH command. If that fails,
13997 terminate the loop.
13999 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
14000 != REPLY_CONTINUE) {
14002 "GSSAPI ADAT failed, AUTH restart failed\n");
14003 /* force out of loop */
14004 maj_stat = GSS_S_FAILURE;
14008 if (!reply_parse) {
14010 "No authentication data received from server\n");
14011 if (maj_stat == GSS_S_COMPLETE) {
14013 "...but no more was needed\n");
14014 goto gss_complete_loop;
14016 user_gss_error(maj_stat,
14020 goto gss_complete_loop;
14024 kerror = radix_encode(reply_parse,out_buf,i,&len,
14028 "Base 64 decoding failed: %s\n",
14029 radix_error(kerror));
14030 goto gss_complete_loop;
14033 /* everything worked */
14034 token_ptr = &recv_tok;
14035 recv_tok.value = out_buf;
14036 recv_tok.length = len;
14039 /* get out of loop clean */
14041 trial = n_gss_trials-1;
14042 gss_release_buffer(&min_stat, &send_tok);
14043 gss_release_name(&min_stat, &target_name);
14046 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14049 if (maj_stat == GSS_S_COMPLETE)
14052 if (maj_stat == GSS_S_COMPLETE) {
14053 printf("GSSAPI authentication succeeded\n");
14054 reply_parse = NULL;
14055 auth_type = "GSSAPI";
14058 fprintf(stderr, "GSSAPI authentication failed\n");
14059 reply_parse = NULL;
14063 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14064 if (ftpcode == 500 || ftpcode == 502)
14068 #endif /* FTP_GSSAPI */
14070 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14071 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14073 else if (ftpcode == 500 || ftpcode == 502)
14076 #endif /* FTP_SRP */
14078 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14079 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14080 if (n == REPLY_CONTINUE) {
14081 char tgt[4*REALM_SZ+1];
14085 printf("KERBEROS_V4 accepted as authentication type\n");
14086 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14087 ckstrncpy(ftp_realm,
14088 (char *)ck_krb4_realmofhost(ftp_user_host),
14092 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14093 rc = ck_krb4_tkt_isvalid(tgt);
14095 if (rc <= 0 && krb4_autoget)
14096 ck_krb4_autoget_TGT(ftp_realm);
14099 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14100 if (kerror == KDC_PR_UNKNOWN) {
14102 kerror = krb_mk_req(&ftp_tkt,
14110 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14111 krb_get_err_text(kerror));
14113 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14115 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14116 krb_get_err_text(kerror));
14120 rc = des_key_sched(ftp_cred.session, ftp_sched);
14122 printf("?Invalid DES key specified in credentials\r\n");
14123 debug(F110,"ftp_auth",
14124 "invalid DES Key specified in credentials",0);
14125 } else if ( rc == -2 ) {
14126 printf("?Weak DES key specified in credentials\r\n");
14127 debug(F110,"ftp_auth",
14128 "weak DES Key specified in credentials",0);
14129 } else if ( rc != 0 ) {
14130 printf("?DES Key Schedule not set by credentials\r\n");
14131 debug(F110,"ftp_auth",
14132 "DES Key Schedule not set by credentials",0);
14134 reply_parse = "ADAT=";
14136 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14139 fprintf(stderr, "Base 64 encoding failed: %s\n",
14140 radix_error(kerror));
14143 if (i > FTP_BUFSIZ - 6)
14144 printf("?ADAT data too long\n");
14145 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14147 fprintf(stderr, "Kerberos V4 authentication failed\n");
14150 if (!reply_parse) {
14152 "No authentication data received from server\n");
14155 i = sizeof(out_buf);
14157 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14159 fprintf(stderr, "Base 64 decoding failed: %s\n",
14160 radix_error(kerror));
14163 kerror = krb_rd_safe(out_buf, i,
14168 #endif /* KRB524 */
14174 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14175 krb_get_err_text(kerror));
14179 /* fetch the (modified) checksum */
14180 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14181 if (ntohl(cksum) == checksum + 1) {
14183 printf("Kerberos V4 authentication succeeded\n");
14184 reply_parse = NULL;
14185 auth_type = "KERBEROS_V4";
14189 "Kerberos V4 mutual authentication failed\n");
14191 reply_parse = NULL;
14196 "KERBEROS_V4 rejected as an authentication type\n");
14197 if (ftpcode == 500 || ftpcode == 502)
14201 #endif /* FTP_KRB4 */
14203 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14206 ftpcmd("HOST",ftp_user_host,0,0,0);
14209 #endif /* FTPHOST */
14210 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14211 if (n != REPLY_COMPLETE)
14212 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14213 if (n == REPLY_COMPLETE) {
14215 printf("TLS accepted as authentication type\n");
14219 if (ssl_ftp_active_flag ) {
14224 fprintf(stderr,"TLS authentication failed\n");
14227 socket_close(csocket);
14228 #else /* TCPIPLIB */
14229 #ifdef USE_SHUTDOWN
14230 shutdown(csocket, 1+1);
14231 #endif /* USE_SHUTDOWN */
14233 #endif /* TCPIPLIB */
14235 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14240 fprintf(stderr,"TLS rejected as an authentication type\n");
14241 if (ftpcode == 500 || ftpcode == 502)
14245 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14248 ftpcmd("HOST",ftp_user_host,0,0,0);
14251 #endif /* FTPHOST */
14252 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14253 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14255 printf("SSL accepted as authentication type\n");
14258 if (ssl_ftp_active_flag) {
14264 fprintf(stderr,"SSL authentication failed\n");
14267 socket_close(csocket);
14268 #else /* TCPIPLIB */
14269 #ifdef USE_SHUTDOWN
14270 shutdown(csocket, 1+1);
14271 #endif /* USE_SHUTDOWN */
14273 #endif /* TCPIPLIB */
14275 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14280 fprintf(stderr, "SSL rejected as an authentication type\n");
14281 if (ftpcode == 500 || ftpcode == 502)
14285 #endif /* CK_SSL */
14286 /* Other auth types go here ... */
14290 #endif /* FTP_SECURITY */
14294 setprotbuf(unsigned int size)
14296 setprotbuf(size) unsigned int size;
14297 #endif /* CK_ANSIC */
14304 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14310 ucbufsiz = actualbuf - FUDGE_FACTOR;
14311 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14312 if (ucbufsiz < 128) {
14313 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14314 } else if (ucbufsiz < 0) {
14315 printf("ERROR: ucbuf allocation failure\n");
14318 maxbuf = actualbuf;
14324 setpbsz(unsigned int size)
14326 setpbsz(size) unsigned int size;
14327 #endif /* CK_ANSIC */
14329 if (!setprotbuf(size)) {
14330 perror("?Error while trying to malloc PROT buffer:");
14333 #endif /* FTP_SRP */
14337 reply_parse = "PBSZ=";
14338 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14340 ssl_ftp_active_flag ? "0" :
14341 #endif /* CK_SSL */
14342 ckuitoa(actualbuf),NULL,NULL);
14343 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14345 printf("?Unable to negotiate PROT buffer size with FTP server\n");
14351 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14352 maxbuf = actualbuf;
14354 maxbuf = actualbuf;
14355 ucbufsiz = maxbuf - FUDGE_FACTOR;
14356 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14357 reply_parse = NULL;
14362 cancel_remote(din) int din; {
14363 CHAR buf[FTP_BUFSIZ];
14367 #endif /* BSDSELECT */
14369 int fds[2], fdcnt = 0;
14370 #endif /* IBMSELECT */
14377 debug(F100,"ftp cancel_remote entry","",0);
14379 if (ssl_ftp_active_flag) {
14381 * Send Telnet IP, Telnet DM but do so inline and within the
14392 count = SSL_write(ssl_ftp_con, buf, 4);
14393 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14394 error = SSL_get_error(ssl_ftp_con,count);
14395 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14397 case SSL_ERROR_NONE:
14399 case SSL_ERROR_WANT_WRITE:
14400 case SSL_ERROR_WANT_READ:
14401 case SSL_ERROR_SYSCALL:
14404 int gle = GetLastError();
14407 case SSL_ERROR_WANT_X509_LOOKUP:
14408 case SSL_ERROR_SSL:
14409 case SSL_ERROR_ZERO_RETURN:
14415 #endif /* CK_SSL */
14418 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14419 * after urgent byte rather than before as is protocol now.
14425 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14427 debug(F101,"ftp cancel_remote send 1","",x);
14429 x = send(csocket,(SENDARG2TYPE)buf,1,0);
14430 debug(F101,"ftp cancel_remote send 2","",x);
14432 x = scommand("ABOR");
14433 debug(F101,"ftp cancel_remote scommand","",x);
14436 FD_SET(csocket, &mask);
14438 FD_SET(din, &mask);
14440 nfnd = empty(&mask, 10);
14441 debug(F101,"ftp cancel_remote empty","",nfnd);
14449 #endif /* FTP_PROXY */
14452 debug(F110,"ftp cancel_remote","D",0);
14453 if (din && FD_ISSET(din, &mask)) {
14454 /* Security: No threat associated with this read. */
14455 /* But you can't simply read the TLS data stream */
14457 if (ssl_ftp_data_active_flag) {
14459 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14462 #endif /* CK_SSL */
14464 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14468 debug(F110,"ftp cancel_remote","E",0);
14469 #else /* BSDSELECT */
14477 nfnd = empty(fds, fdcnt, 10);
14478 debug(F101,"ftp cancel_remote empty","",nfnd);
14486 #endif /* FTP_PROXY */
14489 debug(F110,"ftp cancel_remote","D",0);
14490 if (din && select(&din, 1,0,0,1) ) {
14492 if (ssl_ftp_data_active_flag) {
14494 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14497 #endif /* CK_SSL */
14499 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14503 debug(F110,"ftp cancel_remote","E",0);
14504 #else /* IBMSELECT */
14505 Some form of select is required.
14506 #endif /* IBMSELECT */
14507 #endif /* BSDSELECT */
14508 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14509 debug(F110,"ftp cancel_remote","F",0);
14510 /* 552 needed for NIC style cancel */
14511 getreply(0,-1,-1,ftp_vbm,0);
14512 debug(F110,"ftp cancel_remote","G",0);
14514 debug(F110,"ftp cancel_remote","H",0);
14515 getreply(0,-1,-1,ftp_vbm,0);
14516 debug(F110,"ftp cancel_remote","I",0);
14523 fts_dpl(x) int x; {
14526 || !ck_crypt_is_installed()
14531 printf("?Cannot set protection level to PRIVATE\n");
14534 printf("?Cannot set protection level to SAFE\n");
14542 if (x == FPL_SAF &&
14543 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14544 printf("Cannot set protection level to safe\n");
14547 #endif /* CK_SSL */
14548 /* Start with a PBSZ of 1 meg */
14549 if (x != FPL_CLR) {
14550 if (setpbsz(DEFAULT_PBSZ) < 0)
14553 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14554 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14555 if (y == REPLY_COMPLETE) {
14563 fts_cpl(x) int x; {
14566 || !ck_crypt_is_installed()
14571 printf("?Cannot set protection level to PRIVATE\n");
14574 printf("?Cannot set protection level to SAFE\n");
14580 if (x == FPL_CLR) {
14581 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14582 if (y == REPLY_COMPLETE) {
14594 user_gss_error(maj_stat, min_stat, s)
14595 OM_uint32 maj_stat, min_stat;
14598 /* a lot of work just to report the error */
14599 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14600 gss_buffer_desc msg;
14603 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14609 if ((gmaj_stat == GSS_S_COMPLETE)||
14610 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14611 fprintf(stderr, "GSSAPI error major: %s\n",
14613 gss_release_buffer(&gmin_stat, &msg);
14615 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14620 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14626 if ((gmaj_stat == GSS_S_COMPLETE)||
14627 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14628 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14629 gss_release_buffer(&gmin_stat, &msg);
14631 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14634 fprintf(stderr, "GSSAPI error: %s\n", s);
14636 #endif /* FTP_GSSAPI */
14644 #endif /* HPUX5WINTCP */
14645 #endif /* datageneral */
14646 #endif /* NOMHHOST */
14649 static struct in_addr inaddrx;
14650 #endif /* INADDRX */
14653 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14654 register struct hostent *hp = 0;
14656 #ifdef IPTOS_THROUGHPUT
14658 #endif /* IPTOS_THROUGHPUT */
14659 #endif /* IP_TOS */
14662 static char hostnamebuf[MAXHOSTNAMELEN];
14663 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14672 debug(F111,"ftp_hookup",host,port);
14675 if (tcp_http_proxy) {
14676 struct servent *destsp;
14679 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14680 for (p = tcp_http_proxy, q = hostname;
14681 *p != '\0' && *p != ':';
14692 destsp = getservbyname(p,"tcp");
14694 cport = ntohs(destsp->s_port);
14700 #endif /* NOHTTP */
14702 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14705 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14706 hisctladdr.sin_addr.s_addr = inet_addr(host);
14707 if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14709 debug(F110,"ftp hookup A",hostname,0);
14710 hisctladdr.sin_family = AF_INET;
14711 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14713 debug(F110,"ftp hookup B",hostname,0);
14714 hp = gethostbyname(hostname);
14716 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14717 #endif /* HADDRLIST */
14719 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14724 return((char *) 0);
14726 hisctladdr.sin_family = hp->h_addrtype;
14728 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14729 sizeof(hisctladdr.sin_addr));
14730 #else /* HADDRLIST */
14731 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14732 sizeof(hisctladdr.sin_addr));
14733 #endif /* HADDRLIST */
14734 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14736 debug(F110,"ftp hookup C",hostnamebuf,0);
14737 ftp_host = hostnamebuf;
14738 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14739 debug(F101,"ftp hookup socket","",s);
14741 perror("ftp: socket");
14748 hisctladdr.sin_port = htons(cport);
14752 printf("hisctladdr=%d\n",sizeof(hisctladdr));
14753 printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14754 printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14755 printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14756 #endif /* COMMENT */
14759 debug(F100,"ftp hookup HADDRLIST","",0);
14762 debug(F100,"ftp hookup no HADDRLIST","",0);
14764 #endif /* HADDRLIST */
14765 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14766 debug(F101,"ftp hookup connect failed","",errno);
14768 if (hp && hp->h_addr_list[1]) {
14769 int oerrno = errno;
14771 fprintf(stderr, "ftp: connect to address %s: ",
14772 inet_ntoa(hisctladdr.sin_addr));
14774 perror((char *) 0);
14776 memcpy((char *)&hisctladdr.sin_addr,
14777 hp->h_addr_list[0],
14778 sizeof(hisctladdr.sin_addr));
14779 fprintf(stdout, "Trying %s...\n",
14780 inet_ntoa(hisctladdr.sin_addr));
14783 #else /* TCPIPLIB */
14785 #endif /* TCPIPLIB */
14786 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14788 perror("ftp: socket");
14797 #endif /* HADDRLIST */
14798 perror("ftp: connect");
14802 debug(F100,"ftp hookup connect ok","",0);
14804 len = sizeof (myctladdr);
14806 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14807 debug(F101,"ftp hookup getsockname failed","",errno);
14808 perror("ftp: getsockname");
14812 debug(F100,"ftp hookup getsockname ok","",0);
14815 if (tcp_http_proxy) {
14817 char * agent = "Kermit 95"; /* Default user agent */
14819 char * agent = "C-Kermit";
14822 if (http_connect(s,agent,NULL,
14823 tcp_http_proxy_user,
14824 tcp_http_proxy_pwd,
14831 #else /* TCPIPLIB */
14833 #endif /* TCPIPLIB */
14835 while (foo == NULL && tcp_http_proxy != NULL ) {
14837 if (tcp_http_proxy_errno == 401 ||
14838 tcp_http_proxy_errno == 407 ) {
14839 char uid[UIDBUFLEN];
14841 struct txtbox tb[2];
14845 tb[0].t_len = UIDBUFLEN;
14846 tb[0].t_lbl = "Proxy Userid: ";
14847 tb[0].t_dflt = NULL;
14851 tb[1].t_lbl = "Proxy Passphrase: ";
14852 tb[1].t_dflt = NULL;
14855 ok = uq_mtxt("Proxy Server Authentication Required\n",
14858 if (ok && uid[0]) {
14859 char * proxy_user, * proxy_pwd;
14861 proxy_user = tcp_http_proxy_user;
14862 proxy_pwd = tcp_http_proxy_pwd;
14864 tcp_http_proxy_user = uid;
14865 tcp_http_proxy_pwd = pwd;
14867 foo = ftp_hookup(host, port, 0);
14869 debug(F110,"ftp_hookup()",foo,0);
14870 memset(pwd,0,PWDSIZ);
14871 tcp_http_proxy_user = proxy_user;
14872 tcp_http_proxy_pwd = proxy_pwd;
14880 perror("ftp: connect");
14884 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14886 #endif /* NOHTTP */
14893 * If the connection is over an SSL proxy then the
14894 * auth_type will be NULL. However, I'm not sure
14895 * whether we should protect the data channel in
14896 * that case or not.
14899 debug(F100,"ftp hookup use_tls","",0);
14901 debug(F100,"ftp hookup ssl_auth failed","",0);
14909 #endif /* CK_SSL */
14912 #ifdef IPTOS_LOWDELAY
14913 tos = IPTOS_LOWDELAY;
14914 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14915 perror("ftp: setsockopt TOS (ignored)");
14919 printf("Connected to %s.\n", host);
14921 /* Read greeting from server */
14922 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14923 debug(F100,"ftp hookup bad reply","",0);
14925 socket_close(csocket);
14926 #else /* TCPIPLIB */
14928 #endif /* TCPIPLIB */
14932 #ifdef SO_OOBINLINE
14936 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14938 perror("ftp: setsockopt");
14939 debug(F101,"ftp hookup setsockopt failed","",errno);
14943 debug(F100,"ftp hookup setsockopt ok","",0);
14946 #endif /* SO_OOBINLINE */
14954 debug(F100,"ftp hookup bad","",0);
14957 #else /* TCPIPLIB */
14959 #endif /* TCPIPLIB */
14971 /* The purpose of the initial REST 0 is not clear, but other FTP */
14972 /* clients do it. In any case, failure of this command is not a */
14973 /* reliable indication that the server does not support Restart. */
14977 n = ftpcmd("REST 0",NULL,0,0,0);
14978 if (n == REPLY_COMPLETE)
14982 printf("WARNING: Unable to restore file pointer.\n");
14983 #endif /* COMMENT */
14985 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14986 if (n == REPLY_COMPLETE) {
14987 register char *cp, c = NUL;
14988 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14990 cp = ckstrchr(ftp_reply_str+4,'\r');
14994 c = *cp; /* Save this char */
14995 *cp = '\0'; /* Replace it with NUL */
14998 printf("Remote system type is %s.\n",ftp_reply_str+4);
14999 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
15000 if (cp) /* Put back saved char */
15003 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
15005 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
15006 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
15007 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
15008 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
15009 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
15010 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
15011 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
15015 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
15016 #endif /* FTP_PROXY */
15018 if (ftp_cmdlin && ftp_xfermode == XMODE_M)
15019 ftp_typ = binary; /* Type given on command line */
15020 else /* Otherwise set it automatically */
15021 ftp_typ = alike ? FTT_BIN : FTT_ASC;
15022 changetype(ftp_typ,0); /* Change to this type */
15023 g_ftp_typ = ftp_typ; /* Make it the global type */
15025 printf("Default transfer mode is %s\n",
15026 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
15028 for (i = 0; i < 16; i++) /* Init server FEATure table */
15031 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15033 if (n != REPLY_COMPLETE)
15034 printf("WARNING: Server does not accept MODE S(TREAM)\n");
15035 #endif /* COMMENT */
15036 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15038 if (n != REPLY_COMPLETE)
15039 printf("WARNING: Server does not accept STRU F(ILE)\n");
15040 #endif /* COMMENT */
15042 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15043 if (n == REPLY_COMPLETE) {
15044 debug(F101,"ftp_init FEAT","",sfttab[0]);
15045 if (deblog || ftp_deb) {
15047 for (i = 1; i < 16 && i < nfeattab; i++) {
15048 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15050 printf(" Server %s %s\n",
15051 sfttab[i] ? "supports" : "does not support",
15055 /* Deal with disabled MLST opts here if necessary */
15056 /* But why would it be? */
15064 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
15065 static char ftppass[PASSBUFSIZ]="";
15066 char tmp[PASSBUFSIZ];
15067 char *user = NULL, *pass = NULL, *acct = NULL;
15069 extern char uidbuf[];
15070 extern char pwbuf[];
15071 extern int pwflg, pwcrypt;
15073 debug(F111,"ftp_login",ftp_logname,ftp_log);
15075 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15077 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15081 if (auth_type && !strcmp(auth_type, "SRP")) {
15086 #endif /* FTP_SRP */
15088 user = "anonymous";
15089 if (ftp_tmp) { /* They gave a password */
15091 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
15093 } else { /* Supply user@host */
15094 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15097 debug(F110,"ftp anonymous",pass,0);
15099 #ifdef USE_RUSERPASS
15100 if (ruserpass(host, &user, &pass, &acct) < 0) {
15104 #endif /* USE_RUSERPASS */
15106 user = ftp_logname;
15108 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15112 } else if (pwbuf[0] && pwflg) {
15113 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15116 ck_encrypt((char *)ftppass);
15122 while (user == NULL) {
15123 char *myname, prompt[PROMPTSIZ];
15128 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15129 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15131 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15134 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15135 DEFAULT_UQ_TIMEOUT);
15136 if (!ok || *tmp == '\0')
15139 user = brstrip(tmp);
15142 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15143 if (n == REPLY_COMPLETE) {
15144 /* determine if we need to send a dummy password */
15145 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15146 ftpcmd("PASS dummy",NULL,0,0,1);
15147 } else if (n == REPLY_CONTINUE) {
15148 #ifdef CK_ENCRYPTION
15150 #endif /* CK_ENCRYPTION */
15152 if (pass == NULL) {
15155 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15156 DEFAULT_UQ_TIMEOUT);
15158 pass = brstrip(ftppass);
15161 #ifdef CK_ENCRYPTION
15162 oldftp_cpl = ftp_cpl;
15164 #endif /* CK_ENCRYPTION */
15165 n = ftpcmd("PASS",pass,-1,-1,1);
15166 if (!anonymous && pass) {
15168 while (*p++) *(p-1) = NUL;
15169 makestr(&ftp_tmp,NULL);
15171 #ifdef CK_ENCRYPTION
15172 /* level may have changed */
15173 if (ftp_cpl == FPL_PRV)
15174 ftp_cpl = oldftp_cpl;
15175 #endif /* CK_ENCRYPTION */
15177 if (n == REPLY_CONTINUE) {
15179 if (acct == NULL) {
15180 static char ftpacct[80];
15183 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15184 DEFAULT_UQ_TIMEOUT);
15186 acct = brstrip(ftpacct);
15188 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15190 if (n != REPLY_COMPLETE) {
15191 fprintf(stderr, "FTP login failed.\n");
15193 doexit(BAD_EXIT,-1);
15196 if (!aflag && acct != NULL) {
15197 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15199 makestr(&ftp_logname,user);
15202 /* Unprefixed file management commands go to server */
15203 if (autolocus && !ftp_cmdlin) {
15209 if (anonymous && !quiet) {
15210 printf(" Logged in as anonymous (%s)\n",pass);
15211 memset(pass, 0, strlen(pass));
15214 if (doftpcwd(ftp_rdir,-1) < 1)
15215 doexit(BAD_EXIT,-1);
15221 #endif /* FTP_PROXY */
15233 FD_SET(csocket, &mask);
15234 if ((nfnd = empty(&mask,0)) < 0) {
15240 getreply(0,-1,-1,ftp_vbm,0);
15243 #else /* BSDSELECT */
15247 if ((nfnd = empty(&csocket,1,0)) < 0) {
15253 getreply(0,-1,-1,ftp_vbm,0);
15256 #endif /* IBMSELECT */
15257 #endif /* BSDSELECT */
15258 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15265 ftp_rename(from, to) char * from, * to; {
15266 int lcs = -1, rcs = -1;
15270 if (lcs < 0) lcs = fcharset;
15272 if (rcs < 0) rcs = ftp_csr;
15274 #endif /* NOCSETS */
15275 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15276 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15278 return(0); /* Failure */
15282 ftp_umask(mask) char * mask; {
15284 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15289 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15290 int n = 0, aflag = 0;
15293 if (!auth_type && ftp_aut) {
15295 if (ck_srp_is_installed()) {
15296 if (srp_ftp_auth( NULL, user, pass)) {
15297 makestr(&pass,srp_pass);
15300 #endif /* FTP_SRP */
15302 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15303 if (n == REPLY_COMPLETE)
15304 n = ftpcmd("PASS dummy",NULL,0,0,1);
15305 else if (n == REPLY_CONTINUE) {
15306 #ifdef CK_ENCRYPTION
15308 #endif /* CK_ENCRYPTION */
15309 if (pass == NULL || !pass[0]) {
15313 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15314 DEFAULT_UQ_TIMEOUT);
15316 pass = brstrip(pwd);
15319 #ifdef CK_ENCRYPTION
15320 if ((oldftp_cpl = ftp_cpl) == PROT_S)
15322 #endif /* CK_ENCRYPTION */
15323 n = ftpcmd("PASS",pass,-1,-1,1);
15324 memset(pass, 0, strlen(pass));
15325 #ifdef CK_ENCRYPTION
15326 /* level may have changed */
15327 if (ftp_cpl == PROT_P)
15328 ftp_cpl = oldftp_cpl;
15329 #endif /* CK_ENCRYPTION */
15331 if (n == REPLY_CONTINUE) {
15332 if (acct == NULL || !acct[0]) {
15336 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15337 DEFAULT_UQ_TIMEOUT);
15341 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15344 if (n != REPLY_COMPLETE) {
15345 printf("Login failed.\n");
15348 if (!aflag && acct != NULL && acct[0]) {
15349 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15351 if (n == REPLY_COMPLETE) {
15352 makestr(&ftp_logname,user);
15364 return(auth_type ? auth_type : "NULL");
15377 return("confidential");
15393 return("confidential");
15400 /* remote_files() */
15402 Returns next remote filename on success;
15403 NULL on error or no more files with global rfrc set to:
15405 -2: Server error response to NLST, e.g. file not found
15409 #define FTPNAMBUFLEN CKMAXPATH+1024
15411 /* Check: ckmaxfiles CKMAXOPEN */
15413 #define MLSDEPTH 128 /* Stack of open temp files */
15414 static int mlsdepth = 0; /* Temp file stack depth */
15415 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15416 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15419 mlsreset() { /* Reset MGET temp-file stack */
15421 for (i = 0; i <= mlsdepth; i++) {
15422 if (tmpfilptr[i]) {
15423 fclose(tmpfilptr[i]);
15424 tmpfilptr[i] = NULL;
15425 if (tmpfilnam[i]) {
15427 unlink(tmpfilnam[i]);
15429 free(tmpfilnam[i]);
15438 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15439 #else /* CK_ANSIC */
15440 remote_files(new_query, arg, pattern, proxy_switch)
15442 CHAR * arg; /* That we send to the server */
15443 CHAR * pattern; /* That we use locally */
15445 #endif /* CK_ANSIC */
15446 /* remote_files */ {
15447 static CHAR buf[FTPNAMBUFLEN];
15448 CHAR *cp, *whicharg;
15449 char * cdto = NULL;
15451 int i, x, forced = 0;
15452 int lcs = 0, rcs = 0, xlate = 0;
15454 debug(F101,"ftp remote_files new_query","",new_query);
15455 debug(F110,"ftp remote_files arg",arg,0);
15456 debug(F110,"ftp remote_files pattern",pattern,0);
15459 if (pattern) /* Treat empty pattern same as NULL */
15462 if (arg) /* Ditto for arg */
15469 if (tmpfilptr[mlsdepth]) {
15470 fclose(tmpfilptr[mlsdepth]);
15471 tmpfilptr[mlsdepth] = NULL;
15473 if (!ftp_deb && !deblog)
15474 unlink(tmpfilnam[mlsdepth]);
15478 if (tmpfilptr[mlsdepth] == NULL) {
15479 extern char * tempdir;
15481 debug(F110,"ftp remote_files tempdir",tempdir,0);
15487 p = getenv("K95TMP");
15489 p = getenv("K2TMP");
15493 p = getenv("CK_TMP");
15495 p = getenv("TMPDIR");
15496 if (!p) p = getenv("TEMP");
15497 if (!p) p = getenv("TMP");
15500 int len = strlen(p);
15501 if (p[len-1] != '/'
15503 && p[len-1] != '\\'
15506 static char foo[CKMAXPATH];
15507 ckstrncpy(foo,p,CKMAXPATH);
15508 ckstrncat(foo,"/",CKMAXPATH);
15512 #else /* OS2ORUNIX */
15514 #endif /* OS2ORUNIX */
15515 #ifdef UNIX /* Systems that have a standard */
15516 p = "/tmp/"; /* temporary directory... */
15522 #endif /* datageneral */
15525 debug(F110,"ftp remote_files p",p,0);
15527 /* Get temp file */
15529 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15530 ckmakmsg((char *)tmpfilnam[mlsdepth],
15531 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15533 printf("?Malloc failure: remote_files()\n");
15539 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15541 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15546 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15547 if (x > -1) close(x); /* We just want the name. */
15549 mktemp((char *)tmpfilnam[mlsdepth]);
15550 #endif /* MKSTEMP */
15551 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15552 #endif /* MKTEMP */
15555 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15556 tmpfilnam[mlsdepth],mlsdepth);
15559 if (proxy_switch) {
15562 #endif /* FTP_PROXY */
15564 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15565 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15566 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15569 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15570 if (xlate) { /* ON? */
15571 lcs = ftp_csl; /* Local charset */
15572 if (lcs < 0) lcs = fcharset;
15573 if (lcs < 0) xlate = 0;
15575 if (xlate) { /* Still ON? */
15576 rcs = ftp_csx; /* Remote (Server) charset */
15577 if (rcs < 0) rcs = ftp_csr;
15578 if (rcs < 0) xlate = 0;
15580 #endif /* NOCSETS */
15582 forced = mgetforced; /* MGET method forced? */
15583 if (!forced || !mgetmethod) /* Not forced... */
15584 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15588 User's Command: Result:
15589 mget /nlst NLST (NULL)
15590 mget /nlst foo NLST foo
15591 mget /nlst *.txt NLST *.txt
15592 mget /nlst /match:*.txt NLST (NULL)
15593 mget /nlst /match:*.txt foo NLST foo
15594 mget /mlsd MLSD (NULL)
15595 mget /mlsd foo MLSD foo
15596 mget /mlsd *.txt MLSD (NULL)
15597 mget /mlsd /match:*.txt MLSD (NULL)
15598 mget /mlsd /match:*.txt foo MLSD foo
15602 if (pattern) { /* Don't simplify this! */
15604 } else if (mgetmethod == SND_MLS) {
15606 whicharg = iswild((char *)arg) ? NULL : arg;
15612 debug(F110,"ftp remote_files mgetmethod",
15613 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15614 debug(F110,"ftp remote_files whicharg",whicharg,0);
15616 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15617 (char *)tmpfilnam[mlsdepth],
15627 if (x < 0) { /* Chosen method wasn't accepted */
15629 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15630 printf("?%s: Not supported by server\n",
15631 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15633 rfrc = -2; /* Fail */
15636 /* Not forced - if MLSD failed, try NLST */
15637 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15638 sfttab[SFT_MLST] = 0; /* So disable it */
15639 mlstok = 0; /* and */
15640 mgetmethod = SND_NLS; /* try NLST */
15648 if (proxy_switch) {
15651 #endif /* FTP_PROXY */
15652 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15654 if (tmpfilptr[mlsdepth]) {
15655 if (!ftp_deb && !deblog)
15656 unlink(tmpfilnam[mlsdepth]);
15660 if (!tmpfilptr[mlsdepth]) {
15661 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15662 if ((!dpyactive || ftp_deb))
15663 printf("?Can't find list of remote files, oops\n");
15668 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15671 buf[FTPNAMBUFLEN-1] = NUL;
15672 buf[FTPNAMBUFLEN-2] = NUL;
15674 /* We have to redo all this because the first time was only for */
15675 /* for getting the file list, now it's for getting each file */
15677 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15678 if (!pattern && iswild((char *)arg)) {
15679 pattern = arg; /* Wild arg is really a pattern */
15683 arg = NULL; /* and not an arg */
15685 if (new_query) { /* Initial query? */
15686 cdto = (char *)arg; /* (nonwild) arg given? */
15690 if (cdto) /* If so, then CD to it */
15696 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15697 fclose(tmpfilptr[mlsdepth]);
15698 tmpfilptr[mlsdepth] = NULL;
15701 if (!ftp_deb && !deblog)
15702 unlink(tmpfilnam[mlsdepth]);
15704 if (ftp_deb && !deblog) {
15705 printf("(Temporary file %s NOT deleted)\n",
15706 (char *)tmpfilnam[mlsdepth]);
15708 if (mlsdepth <= 0) { /* EOF at depth 0 */
15709 rfrc = -3; /* means we're done */
15712 printf("POPPING(%d)...\n",mlsdepth-1);
15713 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15716 zchdir(".."); /* <-- Not portable */
15719 if (buf[FTPNAMBUFLEN-1]) {
15720 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15723 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15726 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15727 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15729 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15731 debug(F110,"ftp remote_files buf",buf,0);
15735 printf("[%s]\n",(char *)buf);
15737 havesize = (CK_OFF_T)-1; /* Initialize file facts... */
15739 makestr(&havemdtm,NULL);
15742 if (mgetmethod == SND_NLS) { /* NLST... */
15744 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15747 } else { /* MLSD... */
15748 p = parsefacts((char *)buf);
15749 switch (havetype) {
15750 case FTYP_FILE: /* File: Get it if it matches */
15752 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15756 case FTYP_CDIR: /* Current directory */
15757 case FTYP_PDIR: /* Parent directory */
15758 goto again; /* Skip */
15759 case FTYP_DIR: /* (Sub)Directory */
15760 if (!recursive) /* If not /RECURSIVE */
15761 goto again; /* Skip */
15762 if (mlsdepth < MLSDEPTH) {
15765 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15766 if (doftpcwd(p,0) > 0) {
15768 if (!ckstrchr(p,'/')) {
15769 /* zmkdir() needs dirsep */
15770 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15771 strcpy(p2,p); /* SAFE */
15772 strcat(p2,"/"); /* SAFE */
15780 #endif /* NOMKDIR */
15783 p = (char *)remote_files(1,arg,pattern,0);
15786 printf("?mkdir failed: [%s] Depth=%d\n",
15795 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15800 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15811 debug(F101,"remote_files havesize","",havesize);
15812 debug(F101,"remote_files havetype","",havetype);
15813 debug(F110,"remote_files havemdtm",havemdtm,0);
15814 debug(F110,"remote_files name",p,0);
15820 /* N O T P O R T A B L E !!! */
15822 #if (SIZEOF_SHORT == 4)
15823 typedef unsigned short ftp_uint32;
15824 typedef short ftp_int32;
15826 #if (SIZEOF_INT == 4)
15827 typedef unsigned int ftp_uint32;
15828 typedef int ftp_int32;
15830 #if (SIZEOF_LONG == 4)
15831 typedef ULONG ftp_uint32;
15832 typedef long ftp_int32;
15837 /* Perhaps use these in general, certainly use them for GSSAPI */
15839 #ifndef looping_write
15840 #define ftp_int32 int
15841 #define ftp_uint32 unsigned int
15843 looping_write(fd, buf, len)
15845 register CONST char *buf;
15849 register int wrlen = len;
15851 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15853 if (errno == EINTR)
15860 } while (wrlen > 0);
15864 #ifndef looping_read
15866 looping_read(fd, buf, len)
15868 register char *buf;
15874 cc = recv(fd, (char *)buf, len,0);
15876 if (errno == EINTR)
15878 return(cc); /* errno is already set */
15879 } else if (cc == 0) {
15889 #endif /* looping_read */
15895 secure_putbyte(fd, c) int fd; CHAR c; {
15899 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15901 if (!ftpissecure())
15902 ret = send(fd, (SENDARG2TYPE)ucbuf,
15903 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15905 ret = secure_putbuf(fd,
15907 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15913 #endif /* COMMENT */
15917 * -1 on error (errno set)
15918 * -2 on security error
15921 secure_flush(fd) int fd; {
15927 if (!ftpissecure()) {
15928 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15932 rc = secure_putbuf(fd, ucbuf, nout);
15937 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15940 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15943 ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15948 #ifdef COMMENT /* (not used) */
15952 * -2 on security error
15956 secure_putc(char c, int fd)
15958 secure_putc(c, fd) char c; int fd;
15959 #endif /* CK_ANSIC */
15960 /* secure_putc */ {
15961 return(secure_putbyte(fd, (CHAR) c));
15963 #endif /* COMMENT */
15967 * -1 on error (errno set)
15968 * -2 on security error
15972 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15974 secure_write(fd, buf, nbyte)
15977 unsigned int nbyte;
15978 #endif /* CK_ANSIC */
15984 if (check_data_connection(fd,1) < 0) {
15988 #endif /* FTP_TIMEOUT */
15990 if (!ftpissecure()) {
15992 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15996 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15998 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
16001 while (bsent < nbyte) {
16002 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
16003 (ucbuflen - nout) : (nbyte - bsent));
16006 debug(F101,"secure_write ucbuflen","",ucbuflen);
16007 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
16008 debug(F101,"secure_write bsent","",bsent);
16009 debug(F101,"secure_write b2cp","",b2cp);
16012 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
16016 if (nout == ucbuflen) {
16018 ret = secure_putbuf(fd, ucbuf, ucbuflen);
16029 * -1 on error (errno set)
16030 * -2 on security error
16034 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16036 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16037 #endif /* CK_ANSIC */
16039 static char *outbuf = NULL; /* output ciphertext */
16040 #ifdef FTP_SECURITY
16041 static unsigned int bufsize = 0; /* size of outbuf */
16042 #endif /* FTP_SECURITY */
16043 ftp_int32 length = 0;
16044 ftp_uint32 net_len = 0;
16046 /* Other auth types go here ... */
16048 if (ssl_ftp_data_active_flag) {
16051 /* there is no need to send an empty buffer when using SSL/TLS */
16055 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16056 error = SSL_get_error(ssl_ftp_data_con,count);
16058 case SSL_ERROR_NONE:
16060 case SSL_ERROR_WANT_WRITE:
16061 case SSL_ERROR_WANT_READ:
16062 case SSL_ERROR_SYSCALL:
16065 int gle = GetLastError();
16068 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16071 case SSL_ERROR_WANT_X509_LOOKUP:
16072 case SSL_ERROR_SSL:
16073 case SSL_ERROR_ZERO_RETURN:
16075 SSL_shutdown(ssl_ftp_data_con);
16076 SSL_free(ssl_ftp_data_con);
16077 ssl_ftp_data_active_flag = 0;
16078 ssl_ftp_data_con = NULL;
16080 socket_close(data);
16081 #else /* TCPIPLIB */
16082 #ifdef USE_SHUTDOWN
16083 shutdown(data, 1+1);
16084 #endif /* USE_SHUTDOWN */
16086 #endif /* TCPIPLIB */
16093 #endif /* CK_SSL */
16096 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16097 if (bufsize < nbyte + FUDGE_FACTOR) {
16099 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16100 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16101 bufsize = nbyte + FUDGE_FACTOR;
16104 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16109 srp_encode(ftp_dpl == FPL_PRV,
16115 secure_error ("srp_encode failed");
16119 #endif /* FTP_SRP */
16121 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16122 struct sockaddr_in myaddr, hisaddr;
16124 len = sizeof(myaddr);
16125 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16126 secure_error("secure_putbuf: getsockname failed");
16129 len = sizeof(hisaddr);
16130 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16131 secure_error("secure_putbuf: getpeername failed");
16134 if (bufsize < nbyte + FUDGE_FACTOR) {
16136 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16137 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16138 bufsize = nbyte + FUDGE_FACTOR;
16141 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16145 if (ftp_dpl == FPL_PRV) {
16146 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16152 #endif /* KRB524 */
16157 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16162 #endif /* KRB524 */
16167 if (length == -1) {
16168 secure_error("krb_mk_%s failed for KERBEROS_V4",
16169 ftp_dpl == FPL_PRV ? "priv" : "safe");
16173 #endif /* FTP_KRB4 */
16175 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16176 gss_buffer_desc in_buf, out_buf;
16177 OM_uint32 maj_stat, min_stat;
16180 in_buf.value = buf;
16181 in_buf.length = nbyte;
16182 maj_stat = gss_seal(&min_stat, gcontext,
16183 (ftp_dpl == FPL_PRV), /* confidential */
16189 if (maj_stat != GSS_S_COMPLETE) {
16190 /* generally need to deal */
16191 /* ie. should loop, but for now just fail */
16192 user_gss_error(maj_stat, min_stat,
16193 ftp_dpl == FPL_PRV?
16194 "GSSAPI seal failed":
16195 "GSSAPI sign failed");
16198 if (bufsize < out_buf.length) {
16200 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16201 (outbuf = malloc((unsigned) out_buf.length))) {
16202 bufsize = out_buf.length;
16205 secure_error("%s (in malloc of PROT buffer)",
16210 memcpy(outbuf, out_buf.value, length=out_buf.length);
16211 gss_release_buffer(&min_stat, &out_buf);
16213 #endif /* FTP_GSSAPI */
16214 net_len = htonl((ULONG) length);
16215 if (looping_write(fd, (char *)&net_len, 4) == -1)
16217 if (looping_write(fd, outbuf, length) != length)
16223 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16226 secure_getbyte(fd,fc) int fd,fc; {
16227 /* number of chars in ucbuf, pointer into ucbuf */
16228 static unsigned int nin = 0, bufp = 0;
16242 if (check_data_connection(fd,0) < 0)
16244 #endif /* FTP_TIMEOUT */
16247 if (ssl_ftp_data_active_flag) {
16249 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16250 error = SSL_get_error(ssl_ftp_data_con,count);
16252 if (error != SSL_ERROR_NONE)
16253 debug(F101,"ftp secure_getbyte error","",error);
16255 debug(F101,"ftp secure_getbyte count","",count);
16258 case SSL_ERROR_NONE:
16260 nin = bufp = count;
16263 if (fdispla != XYFD_B) {
16265 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16269 case SSL_ERROR_WANT_WRITE:
16270 case SSL_ERROR_WANT_READ:
16271 case SSL_ERROR_SYSCALL:
16274 int gle = GetLastError();
16277 case SSL_ERROR_WANT_X509_LOOKUP:
16278 case SSL_ERROR_SSL:
16279 case SSL_ERROR_ZERO_RETURN:
16281 nin = bufp = count = 0;
16282 SSL_shutdown(ssl_ftp_data_con);
16283 SSL_free(ssl_ftp_data_con);
16284 ssl_ftp_data_active_flag = 0;
16285 ssl_ftp_data_con = NULL;
16287 socket_close(data);
16288 #else /* TCPIPLIB */
16289 #ifdef USE_SHUTDOWN
16290 shutdown(data, 1+1);
16291 #endif /* USE_SHUTDOWN */
16293 #endif /* TCPIPLIB */
16299 #endif /* CK_SSL */
16301 kerror = looping_read(fd, (char *)&length, sizeof(length));
16302 if (kerror != sizeof(length)) {
16303 secure_error("Couldn't read PROT buffer length: %d/%s",
16305 kerror == -1 ? ck_errstr()
16310 debug(F101,"secure_getbyte length","",length);
16311 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16313 length = (ULONG) ntohl(length);
16314 if (length > maxbuf) {
16315 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16321 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16322 secure_error("Couldn't read %u byte PROT buffer: %s",
16324 kerror == -1 ? ck_errstr() : "premature EOF"
16329 /* Other auth types go here ... */
16331 if (strcmp(auth_type, "SRP") == 0) {
16332 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16338 secure_error ("srp_encode failed" );
16342 #endif /* FTP_SRP */
16344 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16345 struct sockaddr_in myaddr, hisaddr;
16347 len = sizeof(myaddr);
16348 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16349 secure_error("secure_putbuf: getsockname failed");
16352 len = sizeof(hisaddr);
16353 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16354 secure_error("secure_putbuf: getpeername failed");
16358 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16363 #endif /* KRB524 */
16364 &hisaddr, &myaddr, &ftp_msg_data);
16366 kerror = krb_rd_safe(ucbuf, length,
16371 #endif /* KRB524 */
16372 &hisaddr, &myaddr, &ftp_msg_data);
16375 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16376 ftp_dpl == FPL_PRV ? "priv" : "safe",
16377 krb_get_err_text(kerror));
16380 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16381 nin = bufp = ftp_msg_data.app_length;
16383 #endif /* FTP_KRB4 */
16385 if (strcmp(auth_type, "GSSAPI") == 0) {
16386 gss_buffer_desc xmit_buf, msg_buf;
16387 OM_uint32 maj_stat, min_stat;
16390 xmit_buf.value = ucbuf;
16391 xmit_buf.length = length;
16392 conf_state = (ftp_dpl == FPL_PRV);
16393 /* decrypt/verify the message */
16394 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16395 &msg_buf, &conf_state, NULL);
16396 if (maj_stat != GSS_S_COMPLETE) {
16397 user_gss_error(maj_stat, min_stat,
16398 (ftp_dpl == FPL_PRV)?
16399 "failed unsealing ENC message":
16400 "failed unsealing MIC message");
16403 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16404 gss_release_buffer(&min_stat, &msg_buf);
16406 #endif /* FTP_GSSAPI */
16407 /* Other auth types go here ... */
16409 /* Update file transfer display */
16412 if (fdispla != XYFD_B) {
16414 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16421 return(ucbuf[bufp - nin--]);
16424 /* secure_getc(fd,fc)
16426 * fd = file descriptor for connection.
16427 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16429 * c>=0 on success (character value)
16431 * -2 on security error
16432 * -3 on timeout (if built with FTP_TIMEOUT defined)
16435 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
16437 if (!ftpissecure()) {
16438 static unsigned int nin = 0, bufp = 0;
16449 if (check_data_connection(fd,0) < 0) {
16450 debug(F100,"secure_getc TIMEOUT","",0);
16455 #endif /* FTP_TIMEOUT */
16457 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16458 if ((nin == 0) || (nin == (unsigned int)-1)) {
16459 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16460 debug(F101,"secure_getc returns EOF","",EOF);
16464 debug(F101,"ftp secure_getc recv","",nin);
16465 ckhexdump("ftp secure_getc recv",ucbuf,16);
16468 if (fdispla != XYFD_B) {
16470 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16473 return(ucbuf[bufp - nin--]);
16475 return(secure_getbyte(fd,fc));
16479 * n>0 on success (n == # of bytes read)
16481 * -1 on error (errno set), only for FPL_CLR
16482 * -2 on security error
16485 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16489 debug(F101,"secure_read bytes requested","",nbyte);
16492 for (i = 0; nbyte > 0; nbyte--) {
16493 c = secure_getc(fd,0);
16495 case -9: /* Canceled from keyboard */
16496 debug(F101,"ftp secure_read interrupted","",c);
16499 debug(F101,"ftp secure_read error","",c);
16502 debug(F101,"ftp secure_read EOF","",c);
16508 debug(F101,"ftp secure_read timeout","",c);
16510 #endif /* FTP_TIMEOUT */
16518 #ifdef USE_RUSERPASS
16521 * Copyright (c) 1985 Regents of the University of California.
16522 * All rights reserved.
16524 * Redistribution and use in source and binary forms, with or without
16525 * modification, are permitted provided that the following conditions
16527 * 1. Redistributions of source code must retain the above copyright
16528 * notice, this list of conditions and the following disclaimer.
16529 * 2. Redistributions in binary form must reproduce the above copyright
16530 * notice, this list of conditions and the following disclaimer in the
16531 * documentation and/or other materials provided with the distribution.
16532 * 3. All advertising materials mentioning features or use of this software
16533 * must display the following acknowledgement:
16534 * This product includes software developed by the University of
16535 * California, Berkeley and its contributors.
16536 * 4. Neither the name of the University nor the names of its contributors
16537 * may be used to endorse or promote products derived from this software
16538 * without specific prior written permission.
16540 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16541 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16542 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16543 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16544 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16545 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16546 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16547 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16548 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16549 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16554 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16555 #endif /* not lint */
16557 #ifndef MAXHOSTNAMELEN
16558 #define MAXHOSTNAMELEN 64
16562 static FILE * cfile;
16572 static char tokval[100];
16574 static struct toktab {
16578 "default", DEFAULT,
16580 "password", PASSWD,
16582 "account", ACCOUNT,
16596 while ((c = getc(cfile)) != EOF &&
16597 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16603 while ((c = getc(cfile)) != EOF && c != '"') {
16610 while ((c = getc(cfile)) != EOF
16611 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16618 if (tokval[0] == 0)
16620 for (t = toktab; t->tokstr; t++)
16621 if (!strcmp(t->tokstr, tokval))
16626 ruserpass(host, aname, apass, aacct)
16627 char *host, **aname, **apass, **aacct;
16629 char *hdir, buf[FTP_BUFSIZ], *tmp;
16630 char myname[MAXHOSTNAMELEN], *mydomain;
16631 int t, i, c, usedefault = 0;
16638 hdir = getenv("HOME");
16641 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16642 cfile = fopen(buf, "r");
16643 if (cfile == NULL) {
16644 if (errno != ENOENT)
16648 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16650 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16654 while ((t = token())) switch(t) {
16665 * Allow match either for user's input host name
16666 * or official hostname. Also allow match of
16667 * incompletely-specified host in local domain.
16669 if (ckstrcmp(host, tokval,-1,1) == 0)
16671 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16673 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16674 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16675 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16676 tokval[tmp - ftp_host] == '\0')
16678 if ((tmp = ckstrchr(host, '.')) != NULL &&
16679 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16680 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16681 tokval[tmp - host] == '\0')
16687 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16692 *aname = malloc((unsigned) strlen(tokval) + 1);
16693 strcpy(*aname, tokval); /* safe */
16695 if (strcmp(*aname, tokval))
16700 if (strcmp(*aname, "anonymous") &&
16701 fstat(fileno(cfile), &stb) >= 0 &&
16702 (stb.st_mode & 077) != 0) {
16703 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16704 fprintf(stderr, "Remove password or correct mode.\n");
16707 if (token() && *apass == 0) {
16708 *apass = malloc((unsigned) strlen(tokval) + 1);
16709 strcpy(*apass, tokval); /* safe */
16713 if (fstat(fileno(cfile), &stb) >= 0
16714 && (stb.st_mode & 077) != 0) {
16715 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16716 fprintf(stderr, "Remove account or correct mode.\n");
16719 if (token() && *aacct == 0) {
16720 *aacct = malloc((unsigned) strlen(tokval) + 1);
16721 strcpy(*aacct, tokval); /* safe */
16726 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16740 #endif /* USE_RUSERPASS */
16742 static char *radixN =
16743 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16745 static char pad = '=';
16748 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16749 CHAR inbuf[], outbuf[];
16750 int inlen, *outlen, decode;
16757 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16758 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16766 outbuf[j++] |= D>>4;
16767 outbuf[j] = (D&15)<<4;
16770 outbuf[j++] |= D>>2;
16771 outbuf[j] = (D&3)<<6;
16781 case 2: if (D&15) return(3);
16782 if (strcmp((char *)&inbuf[i], "==")) return(2);
16784 case 3: if (D&3) return(3);
16785 if (strcmp((char *)&inbuf[i], "=")) return(2);
16789 for (i = 0, j = 0; i < inlen; i++) {
16792 outbuf[j++] = radixN[inbuf[i]>>2];
16793 c = (inbuf[i]&3)<<4;
16796 outbuf[j++] = radixN[c|inbuf[i]>>4];
16797 c = (inbuf[i]&15)<<2;
16800 outbuf[j++] = radixN[c|inbuf[i]>>6];
16801 outbuf[j++] = radixN[inbuf[i]&63];
16807 if (i%3) outbuf[j++] = radixN[c];
16809 case 1: outbuf[j++] = pad;
16810 case 2: outbuf[j++] = pad;
16812 outbuf[*outlen = j] = '\0';
16818 radix_error(e) int e;
16821 case 0: return("Success");
16822 case 1: return("Bad character in encoding");
16823 case 2: return("Encoding not properly padded");
16824 case 3: return("Decoded # of bits not a multiple of 8");
16825 case 4: return("Output buffer too small");
16826 default: return("Unknown error");
16829 /* END_RUSERPASS */
16832 /*---------------------------------------------------------------------------+
16834 | Package: srpftp |
16835 | Author: Eugene Jhong |
16837 +---------------------------------------------------------------------------*/
16840 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16841 * All Rights Reserved.
16843 * Permission is hereby granted, free of charge, to any person obtaining
16844 * a copy of this software and associated documentation files (the
16845 * "Software"), to deal in the Software without restriction, including
16846 * without limitation the rights to use, copy, modify, merge, publish,
16847 * distribute, sublicense, and/or sell copies of the Software, and to
16848 * permit persons to whom the Software is furnished to do so, subject to
16849 * the following conditions:
16851 * The above copyright notice and this permission notice shall be
16852 * included in all copies or substantial portions of the Software.
16854 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16855 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16856 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16858 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16859 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16860 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16861 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16862 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16864 * In addition, the following conditions apply:
16866 * 1. Any software that incorporates the SRP authentication technology
16867 * must display the following acknowlegment:
16868 * "This product uses the 'Secure Remote Password' cryptographic
16869 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16871 * 2. Any software that incorporates all or part of the SRP distribution
16872 * itself must also display the following acknowledgment:
16873 * "This product includes software developed by Tom Wu and Eugene
16874 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16876 * 3. Redistributions in source or binary form must retain an intact copy
16877 * of this copyright notice and list of conditions.
16880 #define SRP_PROT_VERSION 1
16882 #ifdef CK_ENCRYPTION
16883 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16885 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16886 #endif /* CK_ENCRYPTION */
16888 #define SRP_DEFAULT_HASH HASH_ID_SHA
16890 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16891 CHAR srp_pref_hash = HASH_ID_SHA;
16893 static struct t_client *tc = NULL;
16894 static CHAR *skey = NULL;
16895 static krypto_context *incrypt = NULL;
16896 static krypto_context *outcrypt = NULL;
16898 typedef unsigned int srp_uint32;
16900 /*--------------------------------------------------------------+
16901 | srp_selcipher: select cipher |
16902 +--------------------------------------------------------------*/
16904 srp_selcipher (cname) char *cname; {
16907 if (!(cd = cipher_getdescbyname (cname))) {
16909 CHAR *list = cipher_getlist ();
16911 fprintf (stderr, "ftp: supported ciphers:\n\n");
16912 for (i = 0; i < strlen (list); i++)
16913 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16914 fprintf (stderr, "\n");
16917 srp_pref_cipher = cd->id;
16921 /*--------------------------------------------------------------+
16922 | srp_selhash: select hash |
16923 +--------------------------------------------------------------*/
16925 srp_selhash (hname) char *hname; {
16928 if (!(hd = hash_getdescbyname (hname))) {
16930 CHAR *list = hash_getlist ();
16932 fprintf (stderr, "ftp: supported hash functions:\n\n");
16933 for (i = 0; i < strlen (list); i++)
16934 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16935 fprintf (stderr, "\n");
16938 srp_pref_hash = hd->id;
16942 /*--------------------------------------------------------------+
16943 | srp_userpass: get username and password |
16944 +--------------------------------------------------------------*/
16946 srp_userpass (host) char *host; {
16947 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16951 #ifdef USE_RUSERPASS
16952 ruserpass (host, &user, &srp_pass, &srp_acct);
16953 #endif /* USE_RUSERPASS */
16955 while (user == NULL) {
16960 if (!myname) myname = "";
16962 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16963 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16965 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16967 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16968 DEFAULT_UQ_TIMEOUT);
16969 if (!ok || *tmp == '\0')
16972 user = brstrip(tmp);
16974 ckstrncpy (srp_user, user,BUFSIZ);
16978 /*--------------------------------------------------------------+
16979 | srp_reset: reset srp information |
16980 +--------------------------------------------------------------*/
16983 if (tc) { t_clientclose (tc); tc = NULL; }
16984 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16985 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16989 /*--------------------------------------------------------------+
16990 | srp_ftp_auth: perform srp authentication |
16991 +--------------------------------------------------------------*/
16993 srp_ftp_auth(host, user, pass)
17003 CHAR buf[FTP_BUFSIZ];
17004 CHAR tmp[FTP_BUFSIZ];
17006 int n, e, clen, blen, len, i;
17010 srp_pass = srp_acct = 0;
17012 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
17013 if (n != REPLY_CONTINUE) {
17015 fprintf(stderr, "SRP rejected as an authentication type\n");
17017 } else { /* Send protocol version */
17019 memset (vers, 0, 4);
17020 vers[3] = SRP_PROT_VERSION;
17022 printf ("SRP accepted as authentication type.\n");
17023 bp = tmp; blen = 0;
17024 srp_put (vers, &bp, 4, &blen);
17026 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17028 reply_parse = "ADAT=";
17029 n = ftpcmd("ADAT",buf,-1,-1,0);
17031 if (n == REPLY_CONTINUE) { /* Get protocol version */
17036 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17038 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17041 if (host) { /* Get username/password if needed */
17042 srp_userpass (host);
17044 ckstrncpy (srp_user, user, BUFSIZ);
17047 bp = tmp; blen = 0; /* Send username */
17048 srp_put (srp_user, &bp, strlen (srp_user), &blen);
17050 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17052 reply_parse = "ADAT=";
17053 n = ftpcmd("ADAT",buf,-1,-1,0);
17055 if (n == REPLY_CONTINUE) { /* Get N, g and s */
17060 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17062 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17064 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17066 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17068 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17069 fprintf (stderr, "Unable to open SRP client structure.\n");
17072 wp = t_clientgenexp (tc); /* Send wp */
17073 bp = tmp; blen = 0;
17074 srp_put (wp->data, &bp, wp->len, &blen);
17076 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17078 reply_parse = "ADAT=";
17079 n = ftpcmd("ADAT",buf,-1,-1,0);
17081 if (n == REPLY_CONTINUE) { /* Get yp */
17086 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17088 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17091 static char ftppass[PASSBUFSIZ];
17094 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17095 DEFAULT_UQ_TIMEOUT);
17097 srp_pass = brstrip(ftppass);
17099 t_clientpasswd (tc, srp_pass);
17100 memset (srp_pass, 0, strlen (srp_pass));
17101 skey = t_clientgetkey (tc, &yp); /* Send response */
17102 bp = tmp; blen = 0;
17103 srp_put (t_clientresponse (tc), &bp, 20, &blen);
17105 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17107 reply_parse = "ADAT=";
17108 n = ftpcmd("ADAT",buf,-1,-1,0);
17110 if (n == REPLY_CONTINUE) { /* Get response */
17115 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17117 if (srp_get (&bp, &cp, &blen, &clen) != 20)
17119 if (t_clientverify (tc, cp)) {
17120 fprintf (stderr, "WARNING: bad response to client challenge.\n");
17123 bp = tmp; blen = 0; /* Send nothing */
17124 srp_put ("\0", &bp, 1, &blen);
17126 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17128 reply_parse = "ADAT=";
17129 n = ftpcmd("ADAT",buf,-1,-1,0);
17131 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
17136 int clist_len, hlist_len;
17141 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17143 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17145 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17147 if (srp_get (&bp, &cp, &blen, &clen) != 4)
17149 memcpy (seqnum, cp, 4);
17150 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17151 cid = srp_pref_cipher;
17152 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17153 cid = SRP_DEFAULT_CIPHER;
17155 CHAR *loclist = cipher_getlist ();
17156 for (i = 0; i < strlen (loclist); i++)
17157 if (cipher_supported (clist, loclist[i])) {
17163 fprintf (stderr, "Unable to agree on cipher.\n");
17168 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17169 hid = srp_pref_hash;
17171 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17172 hid = SRP_DEFAULT_HASH;
17175 CHAR *loclist = hash_getlist ();
17176 for (i = 0; i < strlen (loclist); i++)
17177 if (hash_supported (hlist, loclist[i])) {
17183 fprintf (stderr, "Unable to agree on hash.\n");
17188 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17192 /* Generate random number for outkey and outseqnum */
17194 t_random (seqnum, 4);
17196 /* Send cid, hid, outkey, outseqnum */
17198 bp = tmp; blen = 0;
17199 srp_put (&cid, &bp, 1, &blen);
17200 srp_put (&hid, &bp, 1, &blen);
17201 srp_put (seqnum, &bp, 4, &blen);
17203 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17205 reply_parse = "ADAT=";
17206 n = ftpcmd("ADAT",buf,-1,-1,0);
17210 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17214 t_clientclose (tc);
17217 if (n != REPLY_COMPLETE)
17223 printf ("SRP authentication succeeded.\n");
17224 printf ("Using cipher %s and hash function %s.\n",
17225 (cipher_getdescbyid(cid))->name,
17226 (hash_getdescbyid(hid))->name
17229 reply_parse = NULL;
17234 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17238 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17242 fprintf (stderr, "Unable to unmarshal authentication data.\n");
17246 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17247 reply_parse = NULL;
17251 /*--------------------------------------------------------------+
17252 | srp_put: put item to send buffer |
17253 +--------------------------------------------------------------*/
17255 srp_put (in, out, inlen, outlen)
17261 srp_uint32 net_len;
17263 net_len = htonl (inlen);
17264 memcpy (*out, &net_len, 4);
17266 *out += 4; *outlen += 4;
17268 memcpy (*out, in, inlen);
17270 *out += inlen; *outlen += inlen;
17274 /*--------------------------------------------------------------+
17275 | srp_get: get item from receive buffer |
17276 +--------------------------------------------------------------*/
17278 srp_get (in, out, inlen, outlen)
17284 srp_uint32 net_len;
17286 if (*inlen < 4) return -1;
17288 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17289 *outlen = ntohl (net_len);
17291 if (*inlen < *outlen) return -1;
17293 *out = *in; *inlen -= *outlen; *in += *outlen;
17298 /*--------------------------------------------------------------+
17299 | srp_encode: encode control message |
17300 +--------------------------------------------------------------*/
17302 srp_encode (private, in, out, len)
17309 return krypto_msg_priv (outcrypt, in, out, len);
17311 return krypto_msg_safe (outcrypt, in, out, len);
17314 /*--------------------------------------------------------------+
17315 | srp_decode: decode control message |
17316 +--------------------------------------------------------------*/
17318 srp_decode (private, in, out, len)
17325 return krypto_msg_priv (incrypt, in, out, len);
17327 return krypto_msg_safe (incrypt, in, out, len);
17330 #endif /* FTP_SRP */
17336 The following code is from the Unix FTP client. Be sure to
17337 make sure that the functionality is not lost. Especially
17338 the Proxy stuff even though we have not yet implemented it.
17341 /* Send multiple files */
17344 ftp_mput(argc, argv) int argc; char **argv; {
17351 if (argc < 2 && !another(&argc, &argv, "local-files")) {
17352 printf("usage: %s local-files\n", argv[0]);
17358 oldintr = signal(SIGINT, mcancel);
17360 /* Replace with calls to cc_execute() */
17364 char *cp, *tp2, tmpbuf[CKMAXPATH];
17366 while ((cp = remglob(argv,0)) != NULL) {
17371 if (mflag && confirm(argv[0], cp)) {
17374 while (*tp && !islower(*tp)) {
17380 while ((*tp2 = *tp) != 0) {
17381 if (isupper(*tp2)) {
17382 *tp2 = 'a' + *tp2 - 'A';
17396 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17397 if (!mflag && fromatty) {
17398 ointer = interactive;
17400 if (confirm("Continue with","mput")) {
17403 interactive = ointer;
17407 signal(SIGINT, oldintr);
17411 #endif /* FTP_PROXY */
17412 for (i = 1; i < argc; i++) {
17413 register char **cpp, **gargs;
17415 if (mflag && confirm(argv[0], argv[i])) {
17417 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17418 if (!mflag && fromatty) {
17419 ointer = interactive;
17421 if (confirm("Continue with","mput")) {
17424 interactive = ointer;
17429 gargs = ftpglob(argv[i]);
17430 if (globerr != NULL) {
17431 printf("%s\n", globerr);
17434 free((char *)gargs);
17438 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17439 if (mflag && confirm(argv[0], *cpp)) {
17441 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17442 if (!mflag && fromatty) {
17443 ointer = interactive;
17445 if (confirm("Continue with","mput")) {
17448 interactive = ointer;
17452 if (gargs != NULL) {
17454 free((char *)gargs);
17457 signal(SIGINT, oldintr);
17461 /* Get multiple files */
17464 ftp_mget(argc, argv) int argc; char **argv; {
17468 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17471 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17472 printf("usage: %s remote-files\n", argv[0]);
17478 oldintr = signal(SIGINT,mcancel);
17479 /* Replace with calls to cc_execute() */
17481 while ((cp = remglob(argv,proxy)) != NULL) {
17486 if (mflag && confirm(argv[0], cp)) {
17489 while (*tp && !islower(*tp)) {
17495 while ((*tp2 = *tp) != 0) {
17496 if (isupper(*tp2)) {
17497 *tp2 = 'a' + *tp2 - 'A';
17505 rc = (recvrequest("RETR", tp, cp, "wb",
17506 tp != cp || !interactive) == 0,0,NULL,0,0,0);
17507 if (!mflag && fromatty) {
17508 ointer = interactive;
17510 if (confirm("Continue with","mget")) {
17513 interactive = ointer;
17517 signal(SIGINT,oldintr);
17522 /* Delete multiple files */
17525 mdelete(argc, argv) int argc; char **argv; {
17531 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17532 printf("usage: %s remote-files\n", argv[0]);
17538 oldintr = signal(SIGINT, mcancel);
17539 /* Replace with calls to cc_execute() */
17541 while ((cp = remglob(argv,0)) != NULL) {
17546 if (mflag && confirm(argv[0], cp)) {
17547 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17548 if (!mflag && fromatty) {
17549 ointer = interactive;
17551 if (confirm("Continue with", "mdelete")) {
17554 interactive = ointer;
17558 signal(SIGINT, oldintr);
17563 /* Get a directory listing of multiple remote files */
17566 mls(argc, argv) int argc; char **argv; {
17569 char *cmd, mode[1], *dest;
17573 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17575 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17577 printf("usage: %s remote-files local-file\n", argv[0]);
17581 dest = argv[argc - 1];
17582 argv[argc - 1] = NULL;
17583 if (strcmp(dest, "-") && *dest != '|')
17584 if (!globulize(&dest) ||
17585 !confirm("output to local-file:", dest)) {
17589 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17592 oldintr = signal(SIGINT, mcancel);
17593 /* Replace with calls to cc_execute() */
17595 for (i = 1; mflag && i < argc-1; ++i) {
17596 *mode = (i == 1) ? 'w' : 'a';
17597 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17598 if (!mflag && fromatty) {
17599 ointer = interactive;
17601 if (confirm("Continue with", argv[0])) {
17604 interactive = ointer;
17607 signal(SIGINT, oldintr);
17613 remglob(argv,doswitch) char *argv[]; int doswitch; {
17615 static char buf[CKMAXPATH];
17616 static FILE *ftemp = NULL;
17617 static char **args;
17626 (void) fclose(ftemp);
17635 if ((cp = *++args) == NULL)
17639 if (ftemp == NULL) {
17640 (void) strcpy(temp, _PATH_TMP);
17643 (void) mktemp(temp);
17644 #endif /* MKSTEMP */
17645 #endif /* MKTEMP */
17647 oldhash = hash, hash = 0;
17652 #endif /* FTP_PROXY */
17653 for (mode = "wb"; *++argv != NULL; mode = "ab")
17654 recvrequest ("NLST", temp, *argv, mode, 0);
17659 #endif /* FTP_PROXY */
17661 ftemp = fopen(temp, "r");
17663 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17664 printf("Can't find list of remote files, oops\n");
17668 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17669 fclose(ftemp), ftemp = NULL;
17672 if ((cp = ckstrchr(buf,'\n')) != NULL)
17676 #endif /* NOT_USED */
17677 #endif /* TCPSOCKET (top of file) */
17678 #endif /* SYSFTP (top of file) */
17679 #endif /* NOFTP (top of file) */