1 /* C K C F T P -- FTP Client for C-Kermit */
3 char *ckftpv = "FTP Client, 8.0.226, 7 Jan 2004";
7 Jeffrey E Altman <jaltman@secure-endpoints.com>
8 Secure Endpoints Inc., New York City
9 Frank da Cruz <fdc@columbia.edu>,
10 The Kermit Project, Columbia University.
12 Copyright (C) 2000, 2004,
13 Trustees of Columbia University in the City of New York.
14 All rights reserved. See the C-Kermit COPYING.TXT file or the
15 copyright text in the ckcmai.c module for disclaimer and permissions.
17 Portions of conditionally included code Copyright Regents of the
18 University of California and The Stanford SRP Authentication Project;
25 . Implement recursive NLST downloads by trying to CD to each filename.
26 If it works, it's a directory; if not, it's a file -- GET it. But
27 that won't work with servers like wu-ftpd that don't send directory
28 names. Recursion with MLSD is done.
30 . Make syslog entries for session? Files?
32 . Messages are printed to stdout and stderr in random fashion. We should
33 either print everything to stdout, or else be systematic about when
36 . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
38 . Adapt to VMS. Big job because of its record-oriented file system.
39 RMS programmer required. There are probably also some VMS TCP/IP
40 product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS
41 transfers using special options for Multinet or other FTP servers
42 (find out about STRU VMS).
46 Quick FTP command reference:
48 RFC765 (1980) and earlier:
49 MODE S(tream), B(lock), C(ompressed)
50 STRU F(ILE), R(ECORD), P(AGE)
51 TYPE A(SCII) <format>, E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
57 CWD - Change Working Directory
58 REIN - Logout but not disconnect
71 SITE - Site parameters or commands
77 CDUP - Change to Parent Directory
78 SMNT - Structure Mount
80 RMD - Remove Directory
86 FEAT - List Features (done)
87 OPTS - Send options (done)
90 LANG - Specify language for messages (not done)
92 Pending (Internet Drafts):
93 SIZE - File size (done)
94 MDTM - File modification date-time (done)
95 MLST - File name and attribute list (single file) (not done)
96 MLSD - File list with attributes (multiple files) (done)
97 MAIL, MLFL, MSOM - mail delivery (not done)
99 Alphabetical syntax list:
101 ACCT <SP> <account-information> <CRLF>
102 ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
103 APPE <SP> <pathname> <CRLF>
105 CWD <SP> <pathname> <CRLF>
106 DELE <SP> <pathname> <CRLF>
108 HELP [<SP> <string>] <CRLF>
109 LANG [<SP> <language-tag> ] <CRLF>
110 LIST [<SP> <pathname>] <CRLF>
111 MKD <SP> <pathname> <CRLF>
112 MLSD [<SP> <pathname>] <CRLF>
113 MLST [<SP> <pathname>] <CRLF>
114 MODE <SP> <mode-code> <CRLF>
115 NLST [<SP> <pathname-or-wildcard>] <CRLF>
117 OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
118 PASS <SP> <password> <CRLF>
120 PORT <SP> <host-port> <CRLF>
124 REST <SP> <marker> <CRLF>
125 RETR <SP> <pathname> <CRLF>
126 RMD <SP> <pathname> <CRLF>
127 RNFR <SP> <pathname> <CRLF>
128 RNTO <SP> <pathname> <CRLF>
129 SITE <SP> <string> <CRLF>
130 SIZE <SP> <pathname> <CRLF>
131 SMNT <SP> <pathname> <CRLF>
132 STAT [<SP> <pathname>] <CRLF>
133 STOR <SP> <pathname> <CRLF>
135 STRU <SP> <structure-code> <CRLF>
137 TYPE <SP> <type-code> <CRLF>
138 USER <SP> <username> <CRLF>
140 #include "ckcsym.h" /* Standard includes */
143 #ifndef NOFTP /* NOFTP = no FTP */
144 #ifndef SYSFTP /* SYSFTP = use external ftp client */
145 #ifdef TCPSOCKET /* Build only if TCP/IP included */
148 /* Note: much of the following duplicates what was done in ckcdeb.h */
149 /* but let's not mess with it unless it causes trouble. */
155 #endif /* CK_ANSIC */
166 #include <setjmpex.h>
177 #include <sys/stat.h>
184 #define EPIPE 32 /* Broken pipe error */
187 /* Kermit includes */
193 #include "ckcnet.h" /* Includes ckctel.h */
194 #include "ckctel.h" /* (then why include it again?) */
198 How to get the struct timeval definition so we can call select(). The
199 xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
200 targets. The problem is: maybe we have already included some header file
201 that defined struct timeval, and maybe we didn't. If we did, we don't want
202 to include another header file that defines it again or the compilation will
203 fail. If we didn't, we have to include the header file where it's defined.
204 But in some cases even that won't work because of strict POSIX constraints
205 or somesuch, or because this introduces other conflicts (e.g. struct tm
206 multiply defined), in which case we have to define it ourselves, but this
207 can work only if we didn't already encounter a definition.
216 #endif /* SV68R3V6 */
217 #endif /* DCLTIMEVAL */
220 /* Also maybe in some places the elements must be unsigned... */
226 /* Currently we don't use this... */
232 #else /* !DCLTIMEVAL */
235 #include <sys/time.h>
236 #endif /* SYSTIMEH */
237 #endif /* NOSYSTIMEH */
240 #include <sys/timeb.h>
241 #endif /* SYSTIMEBH */
242 #endif /* NOSYSTIMEBH */
243 #endif /* DCLTIMEVAL */
245 #include <sys/types.h>
250 #endif /* HAVE_STDLIB_H */
254 /* This section moved to ckcdeb.h */
269 #include <sys/utime.h>
275 #endif /* SYSUTIMEH */
276 #endif /* NOSETTIME */
280 #include <sys/select.h>
281 #endif /* SELECT_H */
282 #endif /* SCO_OSR504 */
284 /* select() dialects... */
287 #define BSDSELECT /* BSD select() syntax/semantics */
289 #ifdef OS2 /* OS/2 or Win32 */
298 /* Other select() peculiarities */
301 #ifndef HPUX10 /* HP-UX 9.xx and earlier */
303 /* The three interior args to select() are (int *) rather than (fd_set *) */
306 #endif /* INTSELECT */
307 #endif /* HPUX1100 */
311 #ifdef CK_SOCKS /* SOCKS Internet relay package */
312 #ifdef CK_SOCKS5 /* SOCKS 5 */
313 #define accept SOCKSaccept
314 #define bind SOCKSbind
315 #define connect SOCKSconnect
316 #define getsockname SOCKSgetsockname
317 #define listen SOCKSlisten
318 #else /* Not SOCKS 5 */
319 #define accept Raccept
321 #define connect Rconnect
322 #define getsockname Rgetsockname
323 #define listen Rlisten
324 #endif /* CK_SOCKS5 */
325 #endif /* CK_SOCKS */
328 extern char * tcp_http_proxy; /* Name[:port] of http proxy server */
329 extern int tcp_http_proxy_errno;
330 extern char * tcp_http_proxy_user;
331 extern char * tcp_http_proxy_pwd;
332 extern char * tcp_http_proxy_agent;
333 #define HTTPCPYL 1024
334 static char proxyhost[HTTPCPYL];
336 int ssl_ftp_proxy = 0; /* FTP over SSL/TLS Proxy Server */
338 /* Feature selection */
342 We don't use shutdown() because (a) we always call it just before close()
343 so it's redundant and unnecessary, and (b) it introduces a long pause on
344 some platforms like SV/68 R3.
346 /* #define USE_SHUTDOWN */
347 #endif /* USE_SHUTDOWN */
350 #ifndef NORESTART /* Restart / recover */
353 #endif /* FTP_RESTART */
354 #endif /* NORESTART */
355 #endif /* NORESEND */
357 #ifndef NOUPDATE /* Update mode */
360 #endif /* DOUPDATE */
361 #endif /* NOUPDATE */
363 #ifndef UNICODE /* Unicode required */
364 #ifndef NOCSETS /* for charset translation */
370 #ifndef HAVE_MSECS /* Millisecond timer */
376 #endif /* HAVE_MSECS */
379 #ifdef PIPESEND /* PUT from pipe */
383 #endif /* PIPESEND */
385 #ifndef NOSPL /* PUT from array */
388 #endif /* PUTARRAY */
400 There is a conflict between the Key Schedule formats used internally
401 within the standalone MIT KRB4 library and that used by Eric Young
402 in OpenSSL and his standalone DES library. Therefore, KRB4 FTP AUTH
403 cannot be supported when either of those two packages are used.
420 #endif /* CK_KERBEROS */
422 /* FTP_SECURITY is defined if any of the above is selected */
437 #endif /* FTP_KRB4 */
438 #endif /* FTP_GSSAPI */
439 #endif /* FTP_SECURITY */
453 #endif /* CRYPT_DLL */
456 #define des_cblock Block
457 #define des_key_schedule Schedule
462 #include "kerberosIV/krb.h"
466 /* For some reason lost in history the Makefile Solaris targets have -Usun */
471 #define krb_get_err_text_entry krb_get_err_text
473 #endif /* FTP_KRB4 */
479 #endif /* HEADER_DES_H */
480 #endif /* FTP_KRB4 */
487 #endif /* HAVE_PWD_H */
489 #include "t_client.h"
494 #include <gssapi/gssapi.h>
496 Need to include the krb5 file, because we're doing manual fallback
497 from the v2 mech to the v1 mech. Once there's real negotiation,
498 we can be generic again.
500 #include <gssapi/gssapi_generic.h>
501 #include <gssapi/gssapi_krb5.h>
502 static gss_ctx_id_t gcontext;
503 #endif /* FTP_GSSAPI */
516 #endif /* CK_ENCRYPTION */
517 #endif /* FTP_KRB4 */
521 #endif /* FTP_GSSAPI */
524 extern int k95stdout, wherex[], wherey[];
525 extern unsigned char colorcmd;
529 static char ftp_realm[REALM_SZ + 1];
530 static KTEXT_ST ftp_tkt;
532 static LEASH_CREDENTIALS ftp_cred;
534 static CREDENTIALS ftp_cred;
536 static MSG_DAT ftp_msg_data;
537 static des_key_schedule ftp_sched;
538 static int foo[4] = {99,99,99,99};
539 #endif /* FTP_KRB4 */
541 /* getreply() function codes */
543 #define GRF_AUTH 1 /* Reply to AUTH command */
544 #define GRF_FEAT 2 /* Reply to FEAT command */
546 /* Operational definitions */
548 #define DEF_VBM 0 /* Default verbose mode */
549 /* #define SETVBM */ /* (see getreply) */
551 #define URL_ONEFILE /* GET, not MGET, for FTP URL */
553 #define FTP_BUFSIZ 10240 /* Max size for FTP cmds & replies */
554 #define SRVNAMLEN 32 /* Max length for server type name */
556 #define PASSBUFSIZ 256
557 #define PROMPTSIZ 256
559 #ifndef MGETMAX /* Max operands for MGET command */
564 #define FUDGE_FACTOR 100
568 Amount of growth from cleartext to ciphertext. krb_mk_priv adds this
569 number bytes. Must be defined for each auth type.
570 GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
571 3DES requires 56 bytes. Lets use 96 just to be sure.
575 #define FUDGE_FACTOR 96
576 #endif /* FUDGE_FACTOR */
577 #endif /* FTP_GSSAPI */
581 #define FUDGE_FACTOR 32
582 #endif /* FUDGE_FACTOR */
583 #endif /* FTP_KRB4 */
585 #ifndef FUDGE_FACTOR /* In case no auth types define it */
586 #define FUDGE_FACTOR 0
587 #endif /* FUDGE_FACTOR */
589 #ifndef MAXHOSTNAMELEN
590 #define MAXHOSTNAMELEN 64
591 #endif /* MAXHOSTNAMELEN */
592 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
594 /* Fascist compiler toadying */
597 #ifdef COMMENT /* Might be needed here and there */
598 #define SENDARG2TYPE const char *
600 #define SENDARG2TYPE char *
602 #endif /* SENDARG2TYPE */
604 /* Common text messages */
606 static char *nocx = "?No FTP control connection\n";
608 static char *fncnam[] = {
609 "rename", "overwrite", "backup", "append", "discard", "ask", "update",
613 /* Macro definitions */
615 /* Used to speed up text-mode PUTs */
616 #define zzout(fd,c) \
617 ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
619 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
624 extern struct urldata g_url;
628 extern char *zinbuffer, *zoutbuffer; /* Regular Kermit file i/o */
630 extern char zinbuffer[], zoutbuffer[];
632 extern char *zinptr, *zoutptr;
633 extern int zincnt, zoutcnt, zobufsize, fncact;
636 extern int f_tmpdir; /* Directory changed temporarily */
637 extern char savdir[]; /* For saving current directory */
639 #endif /* CK_TMPDIR */
641 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
643 extern xx_strp xxstring;
644 extern struct keytab onoff[], txtbin[], rpathtab[];
645 extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
646 extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
647 extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
648 extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
649 extern int nolinks, msgflg, keep;
650 extern long fsize, ffc, tfc, filcnt, xfsecs, tfcps, cps, oldcps;
652 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
657 extern char filnam[], * filefile, myhost[];
658 extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
659 extern int g_skipbup, skipbup, sendmode;
660 extern int g_displa, fdispla, displa;
663 extern int locus, autolocus;
667 extern int nfilc, dcset7, dcset8, fileorder;
668 extern struct csinfo fcsinfo[];
669 extern struct keytab fcstab[];
673 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
674 extern char sndnbefore[], sndnafter[], *rcvexcept[];
676 extern long sendstart, sndsmaller, sndlarger, rs_len;
678 extern char * remdest;
679 extern int remfile, remappd, rempipe;
682 extern int cmd_quoting;
684 extern int sndxlo, sndxhi, sndxin;
685 extern char sndxnam[];
686 extern char **a_ptr[]; /* Array pointers */
687 extern int a_dim[]; /* Array dimensions */
688 #endif /* PUTARRAY */
691 #ifndef NOMSEND /* MPUT and ADD SEND-LIST lists */
692 extern char *msfiles[];
693 extern int filesinlist;
694 extern struct filelist * filehead;
695 extern struct filelist * filetail;
696 extern struct filelist * filenext;
698 extern char fspec[]; /* Most recent filespec */
699 extern int fspeclen; /* Length of fspec[] buffer */
704 extern char * sndfilter, * rcvfilter;
705 #endif /* PIPESEND */
708 extern int ckrooterr;
712 extern int krb4_autoget;
713 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
717 extern int krb5_autoget;
718 extern int krb5_d_no_addresses;
719 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
723 extern char *atmbuf; /* Atom buffer (malloc'd) */
724 extern char *cmdbuf; /* Command buffer (malloc'd) */
725 extern char *line; /* Big string buffer #1 */
726 extern char *tmpbuf; /* Big string buffer #2 */
728 extern char atmbuf[]; /* The same, but static */
729 extern char cmdbuf[];
731 extern char tmpbuf[];
734 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
736 /* Public variables declared here */
739 int ftpget = 1; /* GET/PUT/REMOTE orientation FTP */
741 int ftpget = 2; /* GET/PUT/REMOTE orientation AUTO */
743 int ftpcode = -1; /* Last FTP response code */
744 int ftp_cmdlin = 0; /* FTP invoked from command line */
745 int ftp_fai = 0; /* FTP failure count */
746 int ftp_deb = 0; /* FTP debugging */
747 int ftp_dis = -1; /* FTP display style */
748 int ftp_log = 1; /* FTP Auto-login */
750 int ftp_action = 0; /* FTP action from command line */
751 int ftp_dates = 1; /* Set file dates from server */
753 char ftp_reply_str[FTP_BUFSIZ] = ""; /* Last line of previous reply */
754 char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
755 char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
756 char * ftp_host = NULL; /* FTP hostname */
757 char * ftp_logname = NULL; /* FTP username */
758 char * ftp_rdir = NULL; /* Remote directory from cmdline */
759 char * ftp_apw = NULL; /* Anonymous password */
761 /* Definitions and typedefs needed for prototypes */
763 #define sig_t my_sig_t
764 #define sigtype SIGTYP
765 typedef sigtype (*sig_t)();
767 /* Static global variables */
769 static char ftpsndbuf[FTP_BUFSIZ+64];
771 static char * fts_sto = NULL;
773 static int ftpsndret = 0;
774 static struct _ftpsnd {
775 sig_t oldintr, oldintp;
779 char * cmd, * local, * remote;
787 This is just a first stab -- these strings should match how the
788 corresponding FTP servers identify themselves.
791 static char * myostype = "UNIX";
795 static char * myostype = "VMS";
799 static char * myostype = "WIN32";
801 static char * myostype = "OS/2";
804 static char * myostype = "UNSUPPORTED";
809 static int noinit = 0; /* Don't send REST, STRU, MODE */
810 static int alike = 0; /* Client/server like platforms */
811 static int local = 1; /* Shadows Kermit global 'local' */
812 static int dout = -1; /* Data connection file descriptor */
813 static int dpyactive = 0; /* Data transfer is active */
814 static int globaldin = -1; /* Data connection f.d. */
815 static int out2screen = 0; /* GET output is to screen */
816 static int forcetype = 0; /* Force text or binary mode */
817 static int cancelfile = 0; /* File canceled */
818 static int cancelgroup = 0; /* Group canceled */
819 static int anonymous = 0; /* Logging in as anonymous */
820 static int loggedin = 0; /* Logged in (or not) */
821 static int puterror = 0; /* What to do on PUT error */
822 static int geterror = 0; /* What to do on GET error */
823 static int rfrc = 0; /* remote_files() return code */
824 static int okrestart = 0; /* Server understands REST */
825 static int printlines = 0; /* getreply()should print data lines */
826 static int haveurl = 0; /* Invoked by command-line FTP URL */
827 static int mdtmok = 1; /* Server supports MDTM */
828 static int sizeok = 1;
829 static int featok = 1;
830 static int mlstok = 1;
831 static int stouarg = 1;
832 static int typesent = 0;
833 static int havesigint = 0;
834 static long havetype = 0;
835 static long havesize = -1L;
836 static char * havemdtm = NULL;
837 static int mgetmethod = 0; /* NLST or MLSD */
838 static int mgetforced = 0;
840 static int i, /* j, k, */ x, y, z; /* Volatile temporaries */
841 static int c0, c1; /* Temp variables for characters */
843 static char putpath[CKMAXPATH+1] = { NUL, NUL };
844 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
846 #define RFNBUFSIZ 4096 /* Remote filename buffer size */
848 static unsigned int maxbuf = 0, actualbuf = 0;
849 static CHAR *ucbuf = NULL;
850 static int ucbufsiz = 0;
851 static unsigned int nout = 0; /* Number of chars in ucbuf */
853 static jmp_buf recvcancel;
854 static jmp_buf sendcancel;
855 static jmp_buf ptcancel;
856 static jmp_buf jcancel;
857 static int ptabflg = 0;
859 /* Protection level symbols */
861 #define FPL_CLR 1 /* Clear */
862 #define FPL_SAF 2 /* Safe */
863 #define FPL_PRV 3 /* Private */
864 #define FPL_CON 4 /* Confidential */
866 /* Symbols for file types returned by MLST/MLSD */
868 #define FTYP_FILE 1 /* Regular file */
869 #define FTYP_DIR 2 /* Directory */
870 #define FTYP_CDIR 3 /* Current directory */
871 #define FTYP_PDIR 4 /* Parent directory */
873 /* File type symbols keyed to the file-type symbols from ckcker.h */
875 #define FTT_ASC XYFT_T /* ASCII (text) */
876 #define FTT_BIN XYFT_B /* Binary (image) */
877 #define FTT_TEN XYFT_X /* TENEX (TOPS-20) */
879 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
881 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
883 #define SFT_AUTH 1 /* FTP server feature codes */
894 #define CNV_AUTO 2 /* FTP filename conversion */
900 static int /* SET FTP values... */
901 ftp_aut = 1, /* Auto-authentication */
903 ftp_cry = 1, /* Auto-encryption */
904 ftp_cfw = 0, /* Credential forwarding */
905 #endif /* FTP_SECURITY */
906 ftp_cpl = FPL_CLR, /* Command protection level */
907 ftp_dpl = FPL_CLR, /* Data protection level */
909 ftp_prx = 0, /* Use proxy */
910 #endif /* FTP_PROXY */
911 sav_psv = -1, /* For saving passive mode */
912 ftp_psv = 1, /* Passive mode */
913 ftp_spc = 1, /* Send port commands */
914 ftp_typ = FTT_ASC, /* Type */
915 get_auto = 1, /* Automatic type switching for GET */
916 tenex = 0, /* Type is Tenex */
917 ftp_usn = 0, /* Unique server names */
918 ftp_prm = 0, /* Permissions */
919 ftp_cnv = CNV_AUTO, /* Filename conversion (2 = auto) */
920 ftp_vbm = DEF_VBM, /* Verbose mode */
921 ftp_vbx = DEF_VBM, /* Sticky version of same */
922 ftp_err = 0, /* Error action */
923 ftp_fnc = -1; /* Filename collision action */
926 static int ftp_bug_use_ssl_v2 = 0; /* use SSLv2 for AUTH SSL */
931 ftp_csr = -1, /* Remote (server) character set */
935 ftp_xla = 0; /* Character-set translation on/off */
937 ftp_csx = -1, /* Remote charset currently in use */
938 ftp_csl = -1; /* Local charset currently in use */
940 static int g_ftp_typ = FTT_ASC; /* For saving and restoring ftp_typ */
942 char * ftp_nml = NULL; /* /NAMELIST */
943 char * ftp_tmp = NULL; /* Temporary string */
944 static char * ftp_acc = NULL; /* Account string */
945 static char * auth_type = NULL; /* Authentication type */
946 static char * srv_renam = NULL; /* Server-rename string */
947 FILE * fp_nml = NULL; /* Namelist file pointer */
949 static int csocket = -1; /* Control socket */
950 static int connected = 0; /* Connected to FTP server */
951 static short ftp_port = 0; /* FTP port */
953 static int hostcmd = 0; /* Has HOST command been sent */
955 static int form, mode, stru, bytesize, curtype = FTT_ASC;
956 static char bytename[8];
958 /* For parsing replies to FTP server command */
959 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
962 static int proxy, unix_proxy
963 #endif /* FTP_PROXY */
965 static char pasv[64]; /* Passive-mode port */
966 static int passivemode = 0;
967 static int sendport = 0;
968 static int servertype = 0; /* FTP server's OS type */
970 static int testing = 0;
971 static char ftpcmdbuf[FTP_BUFSIZ];
973 /* Macro definitions */
975 #define UC(b) ckitoa(((int)b)&0xff)
976 #define nz(x) ((x) == 0 ? 1 : (x))
978 /* Command tables and definitions */
980 #define FTP_ACC 1 /* FTP command keyword codes */
1019 struct keytab gprtab[] = { /* GET-PUT-REMOTE keywords */
1025 static struct keytab qorp[] = { /* QUIT or PROCEED keywords */
1026 { "proceed", 0, 0 }, /* 0 = proceed */
1027 { "quit", 1, 0 } /* 1 = quit */
1030 static struct keytab ftpcmdtab[] = { /* FTP command table */
1031 { "account", FTP_ACC, 0 },
1032 { "append", FTP_APP, 0 },
1033 { "bye", FTP_CLS, 0 },
1034 { "cd", FTP_CWD, 0 },
1035 { "cdup", FTP_GUP, 0 },
1036 { "check", FTP_CHK, 0 },
1037 { "chmod", FTP_CHM, 0 },
1038 { "close", FTP_CLS, 0 },
1039 { "cwd", FTP_CWD, CM_INV },
1040 { "delete", FTP_MDE, 0 },
1041 { "directory", FTP_DIR, 0 },
1042 { "disable", FTP_DIS, 0 },
1043 { "enable", FTP_ENA, 0 },
1044 { "features", FTP_FEA, 0 },
1045 { "get", FTP_GET, 0 },
1046 { "help", FTP_HLP, 0 },
1047 { "idle", FTP_IDL, 0 },
1048 { "login", FTP_USR, CM_INV },
1049 { "mdelete", FTP_MDE, CM_INV },
1050 { "mget", FTP_MGE, 0 },
1051 { "mkdir", FTP_MKD, 0 },
1052 { "modtime", FTP_MOD, 0 },
1053 { "mput", FTP_MPU, 0 },
1054 { "open", FTP_OPN, 0 },
1055 { "opt", FTP_OPT, CM_INV|CM_ABR },
1056 { "opts", FTP_OPT, CM_INV },
1057 { "options", FTP_OPT, 0 },
1058 { "put", FTP_PUT, 0 },
1059 { "pwd", FTP_PWD, 0 },
1060 { "quit", FTP_CLS, CM_INV },
1061 { "quote", FTP_QUO, 0 },
1062 { "reget", FTP_RGE, 0 },
1063 { "rename", FTP_REN, 0 },
1064 { "reset", FTP_RES, 0 },
1065 { "rmdir", FTP_RMD, 0 },
1066 { "send", FTP_PUT, CM_INV },
1067 { "site", FTP_SIT, 0 },
1068 { "size", FTP_SIZ, 0 },
1069 { "status", FTP_STA, 0 },
1070 { "system", FTP_SYS, 0 },
1071 { "type", FTP_TYP, 0 },
1072 { "umask", FTP_UMA, 0 },
1073 { "up", FTP_GUP, CM_INV },
1074 { "user", FTP_USR, 0 },
1075 { "vdirectory",FTP_VDI, 0 },
1078 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1080 #define OPN_ANO 1 /* FTP OPEN switch codes */
1093 static struct keytab tlstab[] = { /* FTP SSL/TLS switches */
1094 { "/ssl", OPN_TLS, 0 },
1095 { "/tls", OPN_TLS, 0 },
1098 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1100 #endif /* FTP_SECURITY */
1102 static struct keytab ftpswitab[] = { /* FTP command switches */
1103 { "/account", OPN_ACC, CM_ARG },
1104 { "/active", OPN_ACT, 0 },
1105 { "/anonymous", OPN_ANO, 0 },
1106 { "/noinit", OPN_NIN, 0 },
1107 { "/nologin", OPN_NOL, 0 },
1108 { "/passive", OPN_PSV, 0 },
1109 { "/password", OPN_PSW, CM_ARG },
1110 { "/user", OPN_USR, CM_ARG },
1113 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1115 /* FTP { ENABLE, DISABLE } items */
1123 static struct keytab ftpenatab[] = {
1124 { "AUTH", ENA_AUTH, 0 },
1125 { "FEAT", ENA_FEAT, 0 },
1126 { "MDTM", ENA_MDTM, 0 },
1127 { "ML", ENA_MLST, CM_INV|CM_ABR },
1128 { "MLS", ENA_MLST, CM_INV|CM_ABR },
1129 { "MLSD", ENA_MLST, CM_INV },
1130 { "MLST", ENA_MLST, 0 },
1131 { "SIZE", ENA_SIZE, 0 },
1134 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1136 /* SET FTP command keyword indices */
1138 #define FTS_AUT 1 /* Autoauthentication */
1139 #define FTS_CRY 2 /* Encryption */
1140 #define FTS_LOG 3 /* Autologin */
1141 #define FTS_CPL 4 /* Command protection level */
1142 #define FTS_CFW 5 /* Credentials forwarding */
1143 #define FTS_DPL 6 /* Data protection level */
1144 #define FTS_DBG 7 /* Debugging */
1145 #define FTS_PSV 8 /* Passive mode */
1146 #define FTS_SPC 9 /* Send port commands */
1147 #define FTS_TYP 10 /* (file) Type */
1148 #define FTS_USN 11 /* Unique server names (for files) */
1149 #define FTS_VBM 12 /* Verbose mode */
1150 #define FTS_ATP 13 /* Authentication type */
1151 #define FTS_CNV 14 /* Filename conversion */
1152 #define FTS_TST 15 /* Test (progress) messages */
1153 #define FTS_PRM 16 /* (file) Permissions */
1154 #define FTS_XLA 17 /* Charset translation */
1155 #define FTS_CSR 18 /* Server charset */
1156 #define FTS_ERR 19 /* Error action */
1157 #define FTS_FNC 20 /* Collision */
1158 #define FTS_SRP 21 /* SRP options */
1159 #define FTS_GFT 22 /* GET automatic file-type switching */
1160 #define FTS_DAT 23 /* Set file dates */
1161 #define FTS_STO 24 /* Server time offset */
1162 #define FTS_APW 25 /* Anonymous password */
1163 #define FTS_DIS 26 /* File-transfer display style */
1164 #define FTS_BUG 27 /* Bug(s) */
1168 #define FTB_SV2 1 /* use SSLv2 */
1170 static struct keytab ftpbugtab[] = {
1171 { "use-ssl-v2", FTB_SV2, 0 }
1173 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1175 /* FTP PUT options (mutually exclusive, not a bitmask) */
1177 #define PUT_UPD 1 /* Update */
1178 #define PUT_RES 2 /* Restart */
1179 #define PUT_SIM 4 /* Simulation */
1180 #define PUT_DIF 8 /* Dates Differ */
1182 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1184 { "append", XYFX_A, 0 }, /* append to old file */
1187 { "ask", XYFX_Q, 0 }, /* ask what to do (not implemented) */
1189 { "backup", XYFX_B, 0 }, /* rename old file */
1191 { "dates-differ", XYFX_M, 0 }, /* accept if dates differ */
1192 { "discard", XYFX_D, 0 }, /* don't accept new file */
1193 { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1195 { "overwrite", XYFX_X, 0 }, /* overwrite the old file */
1196 { "rename", XYFX_R, 0 }, /* rename the incoming file */
1197 #ifndef MAC /* This crashes Mac Kermit. */
1198 { "update", XYFX_U, 0 }, /* replace if newer */
1202 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1206 /* FTP authentication options */
1208 #define FTA_AUTO 0 /* Auto */
1209 #define FTA_SRP 1 /* SRP */
1210 #define FTA_GK5 2 /* Kerberos 5 */
1211 #define FTA_K4 3 /* Kerberos 4 */
1212 #define FTA_SSL 4 /* SSL */
1213 #define FTA_TLS 5 /* TLS */
1215 /* FTP authentication types */
1218 static int ftp_auth_type[FTPATYPS] = {
1220 FTA_GK5, /* GSSAPI Kerberos 5 */
1221 #endif /* FTP_GK5 */
1224 #endif /* FTP_SRP */
1226 FTA_K4, /* Kerberos 4 */
1227 #endif /* FTP_KRB4 */
1235 static struct keytab ftpauth[] = { /* SET FTP AUTHTYPE cmd table */
1236 { "automatic", FTA_AUTO, CM_INV },
1238 { "gssapi-krb5", FTA_GK5, 0 },
1239 #endif /* FTP_GSSAPI */
1241 { "k4", FTA_K4, CM_INV },
1242 #endif /* FTP_KRB4 */
1244 { "k5", FTA_GK5, CM_INV },
1245 #endif /* FTP_GSSAPI */
1247 { "kerberos4", FTA_K4, 0 },
1248 #endif /* FTP_KRB4 */
1250 { "kerberos5", FTA_GK5, CM_INV },
1251 #endif /* FTP_GSSAPI */
1253 { "kerberos_iv",FTA_K4, CM_INV },
1254 #endif /* FTP_KRB4 */
1256 { "kerberos_v", FTA_GK5, CM_INV },
1257 #endif /* FTP_GSSAPI */
1259 { "krb4", FTA_K4, CM_INV },
1260 #endif /* FTP_KRB4 */
1262 { "krb5", FTA_GK5, CM_INV },
1263 #endif /* FTP_GSSAPI */
1265 { "srp", FTA_SRP, 0 },
1266 #endif /* FTP_SRP */
1268 { "ssl", FTA_SSL, 0 },
1269 { "tls", FTA_TLS, 0 },
1273 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1276 #define SRP_CIPHER 1
1278 static struct keytab ftpsrp[] = { /* SET FTP SRP command table */
1279 { "cipher", SRP_CIPHER, 0 },
1280 { "hash", SRP_HASH, 0 },
1283 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1284 #endif /* FTP_SRP */
1285 #endif /* FTP_SECURITY */
1287 static struct keytab ftpset[] = { /* SET FTP commmand table */
1288 { "anonymous-password", FTS_APW, 0 },
1290 { "authtype", FTS_ATP, 0 },
1291 { "autoauthentication", FTS_AUT, 0 },
1292 { "autoencryption", FTS_CRY, 0 },
1293 #endif /* FTP_SECURITY */
1294 { "autologin", FTS_LOG, 0 },
1295 { "bug", FTS_BUG, 0 },
1297 { "character-set-translation",FTS_XLA, 0 },
1298 #endif /* NOCSETS */
1299 { "collision", FTS_FNC, 0 },
1301 { "command-protection-level", FTS_CPL, 0 },
1302 { "cpl", FTS_CPL, CM_INV },
1303 { "credential-forwarding", FTS_CFW, 0 },
1304 { "da", FTS_DAT, CM_INV|CM_ABR },
1305 { "data-protection-level", FTS_DPL, 0 },
1306 #endif /* FTP_SECURITY */
1307 { "dates", FTS_DAT, 0 },
1308 { "debug", FTS_DBG, 0 },
1309 { "display", FTS_DIS, 0 },
1311 { "dpl", FTS_DPL, CM_INV },
1312 #endif /* FTP_SECURITY */
1313 { "error-action", FTS_ERR, 0 },
1314 { "filenames", FTS_CNV, 0 },
1315 { "get-filetype-switching", FTS_GFT, 0 },
1316 { "passive-mode", FTS_PSV, 0 },
1317 { "pasv", FTS_PSV, CM_INV },
1318 { "permissions", FTS_PRM, 0 },
1319 { "progress-messages", FTS_TST, 0 },
1320 { "send-port-commands", FTS_SPC, 0 },
1322 { "server-character-set", FTS_CSR, 0 },
1323 #endif /* NOCSETS */
1324 { "server-time-offset", FTS_STO, 0 },
1326 { "srp", FTS_SRP, 0 },
1328 { "srp", FTS_SRP, CM_INV },
1329 #endif /* FTP_SRP */
1330 { "type", FTS_TYP, 0 },
1331 { "unique-server-names", FTS_USN, 0 },
1332 { "verbose-mode", FTS_VBM, 0 },
1335 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1338 GET and PUT switches are approximately the same as Kermit GET and SEND,
1339 and use the same SND_xxx definitions, but hijack a couple for FTP use.
1340 Don't just make up new ones, since the number of SND_xxx options must be
1341 known in advance for the switch-parsing arrays.
1343 #define SND_USN SND_PRO /* /UNIQUE instead of /PROTOCOL */
1344 #define SND_PRM SND_PIP /* /PERMISSIONS instead of /PIPES */
1345 #define SND_TEN SND_CAL /* /TENEX instead of /CALIBRATE */
1347 static struct keytab putswi[] = { /* FTP PUT switch table */
1348 { "/after", SND_AFT, CM_ARG },
1350 { "/array", SND_ARR, CM_ARG },
1351 #endif /* PUTARRAY */
1352 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1353 { "/as-name", SND_ASN, CM_ARG },
1354 { "/ascii", SND_TXT, CM_INV },
1355 { "/b", SND_BIN, CM_INV|CM_ABR },
1356 { "/before", SND_BEF, CM_ARG },
1357 { "/binary", SND_BIN, 0 },
1359 { "/command", SND_CMD, CM_PSH },
1360 #endif /* PUTPIPE */
1362 /* This works but it's dangerous */
1364 { "/dates-differ", SND_DIF, CM_INV },
1365 #endif /* DOUPDATE */
1366 #endif /* COMMENT */
1367 { "/delete", SND_DEL, 0 },
1369 { "/dotfiles", SND_DOT, 0 },
1370 #endif /* UNIXOROSK */
1371 { "/error-action", SND_ERR, CM_ARG },
1372 { "/except", SND_EXC, CM_ARG },
1373 { "/filenames", SND_NAM, CM_ARG },
1376 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1378 #endif /* PIPESEND */
1380 { "/followlinks", SND_LNK, 0 },
1381 #endif /* CKSYMLINK */
1383 { "/image", SND_IMG, 0 },
1385 { "/image", SND_BIN, CM_INV },
1387 { "/larger-than", SND_LAR, CM_ARG },
1388 { "/listfile", SND_FIL, CM_ARG },
1390 { "/local-character-set", SND_CSL, CM_ARG },
1391 #endif /* NOCSETS */
1393 { "/move-to", SND_MOV, CM_ARG },
1394 #endif /* CK_TMPDIR */
1395 { "/nobackupfiles", SND_NOB, 0 },
1397 { "/nodotfiles", SND_NOD, 0 },
1398 #endif /* UNIXOROSK */
1400 { "/nofollowlinks", SND_NLK, 0 },
1401 #endif /* CKSYMLINK */
1403 { "/not-after", SND_NAF, CM_ARG },
1404 { "/not-before", SND_NBE, CM_ARG },
1406 { "/permissions", SND_PRM, CM_ARG },
1408 { "/permissions", SND_PRM, CM_ARG|CM_INV },
1410 { "/quiet", SND_SHH, 0 },
1412 { "/recover", SND_RES, 0 },
1413 #endif /* FTP_RESTART */
1415 { "/recursive", SND_REC, 0 },
1416 #endif /* RECURSIVE */
1417 { "/rename-to", SND_REN, CM_ARG },
1419 { "/restart", SND_RES, CM_INV },
1420 #endif /* FTP_RESTART */
1422 { "/server-character-set", SND_CSR, CM_ARG },
1423 #endif /* NOCSETS */
1424 { "/server-rename-to", SND_SRN, CM_ARG },
1425 { "/simulate", SND_SIM, 0 },
1426 { "/since", SND_AFT, CM_INV|CM_ARG },
1427 { "/smaller-than", SND_SMA, CM_ARG },
1429 { "/starting-at", SND_STA, CM_ARG },
1430 #endif /* COMMENT */
1432 { "/subdirectories", SND_REC, CM_INV },
1433 #endif /* RECURSIVE */
1434 { "/tenex", SND_TEN, 0 },
1435 { "/text", SND_TXT, 0 },
1437 { "/transparent", SND_XPA, 0 },
1438 #endif /* NOCSETS */
1439 { "/type", SND_TYP, CM_ARG },
1441 { "/update", SND_UPD, 0 },
1442 #endif /* DOUPDATE */
1443 { "/unique-server-names", SND_USN, 0 },
1446 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1448 static struct keytab getswi[] = { /* FTP [M]GET switch table */
1449 { "/after", SND_AFT, CM_INV },
1450 { "/as", SND_ASN, CM_ARG|CM_INV|CM_ABR },
1451 { "/as-name", SND_ASN, CM_ARG },
1452 { "/ascii", SND_TXT, CM_INV },
1453 { "/before", SND_BEF, CM_INV },
1454 { "/binary", SND_BIN, 0 },
1455 { "/collision", SND_COL, CM_ARG },
1457 { "/command", SND_CMD, CM_PSH },
1458 #endif /* PUTPIPE */
1459 { "/delete", SND_DEL, 0 },
1460 { "/error-action", SND_ERR, CM_ARG },
1461 { "/except", SND_EXC, CM_ARG },
1462 { "/filenames", SND_NAM, CM_ARG },
1465 { "/filter", SND_FLT, CM_ARG|CM_PSH },
1467 #endif /* PIPESEND */
1469 { "/image", SND_IMG, 0 },
1471 { "/image", SND_BIN, CM_INV },
1473 { "/larger-than", SND_LAR, CM_ARG },
1474 { "/listfile", SND_FIL, CM_ARG },
1476 { "/local-character-set", SND_CSL, CM_ARG },
1477 #endif /* NOCSETS */
1478 { "/match", SND_PAT, CM_ARG },
1479 { "/ml", SND_MLS, CM_INV|CM_ABR },
1480 { "/mls", SND_MLS, CM_INV|CM_ABR },
1481 { "/mlsd", SND_MLS, 0 },
1482 { "/mlst", SND_MLS, CM_INV },
1484 { "/move-to", SND_MOV, CM_ARG },
1485 #endif /* CK_TMPDIR */
1486 { "/namelist", SND_NML, CM_ARG },
1487 { "/nlst", SND_NLS, 0 },
1488 { "/nobackupfiles", SND_NOB, 0 },
1489 { "/nodotfiles", SND_NOD, 0 },
1491 { "/dates-differ", SND_DIF, CM_INV },
1492 #endif /* DOUPDATE */
1493 { "/not-after", SND_NAF, CM_INV },
1494 { "/not-before", SND_NBE, CM_INV },
1495 { "/permissions", SND_PRM, CM_INV },
1496 { "/quiet", SND_SHH, 0 },
1498 { "/recover", SND_RES, 0 },
1499 #endif /* FTP_RESTART */
1501 { "/recursive", SND_REC, 0 },
1502 #endif /* RECURSIVE */
1503 { "/rename-to", SND_REN, CM_ARG },
1505 { "/restart", SND_RES, CM_INV },
1506 #endif /* FTP_RESTART */
1508 { "/server-character-set", SND_CSR, CM_ARG },
1509 #endif /* NOCSETS */
1510 { "/server-rename-to", SND_SRN, CM_ARG },
1511 { "/smaller-than", SND_SMA, CM_ARG },
1513 { "/subdirectories", SND_REC, CM_INV },
1514 #endif /* RECURSIVE */
1515 { "/text", SND_TXT, 0 },
1516 { "/tenex", SND_TEN, 0 },
1518 { "/transparent", SND_XPA, 0 },
1519 #endif /* NOCSETS */
1520 { "/to-screen", SND_MAI, 0 },
1522 { "/update", SND_UPD, CM_INV },
1523 #endif /* DOUPDATE */
1526 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1528 static struct keytab delswi[] = { /* FTP [M]DELETE switch table */
1529 { "/error-action", SND_ERR, CM_ARG },
1530 { "/except", SND_EXC, CM_ARG },
1531 { "/filenames", SND_NAM, CM_ARG },
1532 { "/larger-than", SND_LAR, CM_ARG },
1533 { "/nobackupfiles", SND_NOB, 0 },
1535 { "/nodotfiles", SND_NOD, 0 },
1536 #endif /* UNIXOROSK */
1537 { "/quiet", SND_SHH, 0 },
1539 { "/recursive", SND_REC, 0 },
1540 #endif /* RECURSIVE */
1541 { "/smaller-than", SND_SMA, CM_ARG },
1543 { "/subdirectories", SND_REC, CM_INV },
1544 #endif /* RECURSIVE */
1547 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1549 static struct keytab fntab[] = { /* Filename conversion keyword table */
1550 { "automatic", 2, CNV_AUTO },
1551 { "converted", 1, CNV_CNV },
1552 { "literal", 0, CNV_LIT }
1554 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1556 static struct keytab ftptyp[] = { /* SET FTP TYPE table */
1557 { "ascii", FTT_ASC, 0 },
1558 { "binary", FTT_BIN, 0 },
1559 { "tenex", FTT_TEN, 0 },
1560 { "text", FTT_ASC, CM_INV },
1563 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1566 static struct keytab ftppro[] = { /* SET FTP PROTECTION-LEVEL table */
1567 { "clear", FPL_CLR, 0 },
1568 { "confidential", FPL_CON, 0 },
1569 { "private", FPL_PRV, 0 },
1570 { "safe", FPL_SAF, 0 },
1573 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1574 #endif /* FTP_SECURITY */
1576 /* Definitions for FTP from RFC765. */
1580 #define REPLY_PRELIM 1 /* Positive preliminary */
1581 #define REPLY_COMPLETE 2 /* Positive completion */
1582 #define REPLY_CONTINUE 3 /* Positive intermediate */
1583 #define REPLY_TRANSIENT 4 /* Transient negative completion */
1584 #define REPLY_ERROR 5 /* Permanent negative completion */
1585 #define REPLY_SECURE 6 /* Security encoded message */
1587 /* Form codes and names */
1589 #define FORM_N 1 /* Non-print */
1590 #define FORM_T 2 /* Telnet format effectors */
1591 #define FORM_C 3 /* Carriage control (ASA) */
1593 /* Structure codes and names */
1595 #define STRU_F 1 /* File (no record structure) */
1596 #define STRU_R 2 /* Record structure */
1597 #define STRU_P 3 /* Page structure */
1599 /* Mode types and names */
1601 #define MODE_S 1 /* Stream */
1602 #define MODE_B 2 /* Block */
1603 #define MODE_C 3 /* Compressed */
1605 /* Protection levels and names */
1607 #define PROT_C 1 /* Clear */
1608 #define PROT_S 2 /* Safe */
1609 #define PROT_P 3 /* Private */
1610 #define PROT_E 4 /* Confidential */
1612 #ifdef COMMENT /* Not used */
1614 char *strunames[] = {"0", "File", "Record", "Page" };
1615 char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" };
1616 char *modenames[] = {"0", "Stream", "Block", "Compressed" };
1617 char *levelnames[] = {"0", "Clear", "Safe", "Private", "Confidential" };
1618 #endif /* FTP_NAMES */
1622 #define REC_ESC '\377' /* Record-mode Escape */
1623 #define REC_EOR '\001' /* Record-mode End-of-Record */
1624 #define REC_EOF '\002' /* Record-mode End-of-File */
1628 #define BLK_EOR 0x80 /* Block is End-of-Record */
1629 #define BLK_EOF 0x40 /* Block is End-of-File */
1630 #define BLK_REPLY_ERRORS 0x20 /* Block might have errors */
1631 #define BLK_RESTART 0x10 /* Block is Restart Marker */
1632 #define BLK_BYTECOUNT 2 /* Bytes in this block */
1633 #endif /* COMMENT */
1635 #define RADIX_ENCODE 0 /* radix_encode() function codes */
1636 #define RADIX_DECODE 1
1639 The default setpbsz() value in the Unix FTP client is 1<<20 (1MB). This
1640 results in a serious performance degradation due to the increased number
1641 of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1642 network i/o. So instead we set the value to 1<<13 (8K), about half the size
1643 of the typical TCP window. Maybe we should add a command to allow the value
1646 #define DEFAULT_PBSZ 1<<13
1650 _PROTOTYP(int remtxt, (char **) );
1651 _PROTOTYP(char * gskreason, (int) );
1652 _PROTOTYP(static int ftpclose,(void));
1653 _PROTOTYP(static int zzsend, (int, CHAR));
1654 _PROTOTYP(static int getreply,(int,int,int,int,int));
1655 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1656 _PROTOTYP(static int setpbsz,(unsigned int));
1657 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1658 int,int,char *,int,int,int));
1659 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1660 _PROTOTYP(static int fts_cpl,(int));
1661 _PROTOTYP(static int fts_dpl,(int));
1663 _PROTOTYP(static int ftp_auth, (void));
1664 #endif /* FTP_SECURITY */
1665 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1666 _PROTOTYP(static int ftp_login, (char *));
1667 _PROTOTYP(static int ftp_reset, (void));
1668 _PROTOTYP(static int ftp_rename, (char *, char *));
1669 _PROTOTYP(static int ftp_umask, (char *));
1670 _PROTOTYP(static int secure_flush, (int));
1672 _PROTOTYP(static int secure_putc, (char, int));
1673 #endif /* COMMENT */
1674 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1675 _PROTOTYP(static int scommand, (char *));
1676 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1677 _PROTOTYP(static int secure_getc, (int, int));
1678 _PROTOTYP(static int secure_getbyte, (int, int));
1679 _PROTOTYP(static int secure_read, (int, char *, int));
1680 _PROTOTYP(static int initconn, (void));
1681 _PROTOTYP(static int dataconn, (char *));
1682 _PROTOTYP(static int setprotbuf,(unsigned int));
1683 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1685 _PROTOTYP(static char * radix_error,(int));
1686 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1687 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1689 _PROTOTYP(static VOID mlsreset, (void));
1690 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1691 _PROTOTYP(static VOID lostpeer, (void));
1692 _PROTOTYP(static VOID cancel_remote, (int));
1693 _PROTOTYP(static VOID changetype, (int, int));
1695 _PROTOTYP(static sigtype cmdcancel, (int));
1698 _PROTOTYP(static int srp_reset, ());
1699 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1700 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1701 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1702 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1703 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1704 _PROTOTYP(static int srp_selcipher, (char *));
1705 _PROTOTYP(static int srp_selhash, (char *));
1706 #endif /* FTP_SRP */
1709 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1710 #endif /* FTP_GSSAPI */
1712 /* D O F T P A R G -- Do an FTP command-line argument. */
1725 #define FT_SECURE 10
1726 #define FT_VERIFY 11
1728 static struct keytab ftpztab[] = {
1729 { "!gss", FT_NOGSS, 0 },
1730 { "!krb4", FT_NOK4, 0 },
1731 { "!srp", FT_NOSRP, 0 },
1732 { "!ssl", FT_NOSSL, 0 },
1733 { "!tls", FT_NOTLS, 0 },
1734 { "cert", FT_CERTFI, CM_ARG },
1735 { "certsok", FT_OKCERT, 0 },
1736 { "debug", FT_DEBUG, 0 },
1737 { "key", FT_KEY, CM_ARG },
1738 { "nogss", FT_NOGSS, 0 },
1739 { "nokrb4", FT_NOK4, 0 },
1740 { "nosrp", FT_NOSRP, 0 },
1741 { "nossl", FT_NOSSL, 0 },
1742 { "notls", FT_NOTLS, 0 },
1744 { "secure", FT_SECURE, 0 },
1745 #endif /* COMMENT */
1746 { "verify", FT_VERIFY, CM_ARG },
1749 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1752 The following cipher and hash tables should be replaced with
1753 dynamicly created versions based upon the linked library.
1755 #define SRP_BLOWFISH_ECB 1
1756 #define SRP_BLOWFISH_CBC 2
1757 #define SRP_BLOWFISH_CFB64 3
1758 #define SRP_BLOWFISH_OFB64 4
1759 #define SRP_CAST5_ECB 5
1760 #define SRP_CAST5_CBC 6
1761 #define SRP_CAST5_CFB64 7
1762 #define SRP_CAST5_OFB64 8
1763 #define SRP_DES_ECB 9
1764 #define SRP_DES_CBC 10
1765 #define SRP_DES_CFB64 11
1766 #define SRP_DES_OFB64 12
1767 #define SRP_DES3_ECB 13
1768 #define SRP_DES3_CBC 14
1769 #define SRP_DES3_CFB64 15
1770 #define SRP_DES3_OFB64 16
1772 static struct keytab ciphertab[] = {
1773 { "blowfish_ecb", SRP_BLOWFISH_ECB, 0 },
1774 { "blowfish_cbc", SRP_BLOWFISH_CBC, 0 },
1775 { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1776 { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1777 { "cast5_ecb", SRP_CAST5_ECB, 0 },
1778 { "cast5_cbc", SRP_CAST5_CBC, 0 },
1779 { "cast5_cfb64", SRP_CAST5_CFB64, 0 },
1780 { "cast5_ofb64", SRP_CAST5_OFB64, 0 },
1781 { "des_ecb", SRP_DES_ECB, 0 },
1782 { "des_cbc", SRP_DES_CBC, 0 },
1783 { "des_cfb64", SRP_DES_CFB64, 0 },
1784 { "des_ofb64", SRP_DES_OFB64, 0 },
1785 { "des3_ecb", SRP_DES3_ECB, 0 },
1786 { "des3_cbc", SRP_DES3_CBC, 0 },
1787 { "des3_cfb64", SRP_DES3_CFB64, 0 },
1788 { "des3_ofb64", SRP_DES3_OFB64, 0 },
1792 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1796 static struct keytab hashtab[] = {
1797 { "md5", SRP_MD5, 0 },
1799 { "sha", SRP_SHA, 0 },
1802 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1804 #endif /* FTP_SECURITY */
1807 strval(s1,s2) char * s1, * s2; {
1810 return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1814 static char * rfnptr = NULL;
1815 static int rfnlen = 0;
1816 static char rfnbuf[RFNBUFSIZ]; /* Remote filename translate buffer */
1817 static char * xgnbp = NULL;
1820 strgetc() { /* Helper function for xgnbyte() */
1826 c = (unsigned) *xgnbp++;
1827 return(((unsigned) c) & 0xff);
1830 static int /* Helper function for xpnbyte() */
1835 #endif /* CK_ANSIC */
1837 rfnlen = rfnptr - rfnbuf;
1838 if (rfnlen >= (RFNBUFSIZ - 1))
1850 #endif /* CK_ANSIC */
1857 bytswap(c0,c1) int * c0, * c1; {
1863 #endif /* NOCSETS */
1866 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
1867 int ftplogactive = 0;
1868 long ftplogprev = 0L;
1873 extern char diafil[];
1874 long d1, d2, t1, t2;
1877 debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
1878 debug(F110,"ftp cx log buf",ftplogbuf,0);
1880 if (!ftplogactive || !ftplogbuf[0]) /* No active record */
1883 ftplogactive = 0; /* Record is not active */
1885 d1 = mjd((char *)ftplogbuf); /* Get start date of this session */
1886 ckstrncpy(buf,ckdate(),31); /* Get current date */
1887 d2 = mjd(buf); /* Convert them to mjds */
1888 p = ftplogbuf; /* Get start time */
1890 p[14] = NUL; /* Convert to seconds */
1891 t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
1894 p = buf; /* Get end time */
1897 t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
1898 t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
1902 strncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
1903 strncat(ftplogbuf,p,CXLOGBUFL);
1906 debug(F101,"ftp cx log dialog","",dialog);
1907 if (dialog) { /* If logging */
1909 x = diaopn(diafil,1,1); /* Open log in append mode */
1911 debug(F101,"ftp cx log open","",x);
1912 x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
1913 debug(F101,"ftp cx log write","",x);
1914 x = zclose(ZDIFIL); /* Close the log */
1915 debug(F101,"ftp cx log close","",x);
1922 ftplogend(); /* Previous session not closed out? */
1924 ftplogactive = 1; /* Record is active */
1926 ckmakxmsg(ftplogbuf,CXLOGBUFL,
1927 ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
1928 " T=FTP N=", strval(ftp_host,NULL)," H=",myhost," ",NULL,NULL);
1929 debug(F110,"ftp cx log begin",ftplogbuf,0);
1931 #endif /* CKLOGDIAL */
1933 static char * dummy[2] = { NULL, NULL };
1935 static struct keytab modetab[] = {
1941 int /* Called from ckuusy.c */
1946 #endif /* CK_ANSIC */
1950 extern char **xargv, *xarg0;
1951 extern int xargc, stayflg, haveftpuid;
1952 extern char uidbuf[];
1954 xp = *xargv+1; /* Pointer for bundled args */
1956 if (ckstrchr("MuDPkcHzm",c)) { /* Options that take arguments */
1958 fatal("?Invalid argument bundling");
1961 if ((xargc < 1) || (**xargv == '-')) {
1962 fatal("?Required argument missing");
1965 switch (c) { /* Big switch on arg */
1966 case 'h': /* help */
1967 printf("C-Kermit's FTP client command-line personality. Usage:\n");
1968 printf(" %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
1969 printf("Options:\n");
1970 printf(" -h = help (this message)\n");
1971 printf(" -m mode = \"passive\" (default) or \"active\"\n");
1972 printf(" -u name = username for autologin (or -M)\n");
1973 printf(" -P password = password for autologin (RISKY)\n");
1974 printf(" -A = autologin anonymously\n");
1975 printf(" -D directory = cd after autologin\n");
1976 printf(" -b = force binary mode\n");
1977 printf(" -a = force text (\"ascii\") mode (or -T)\n");
1978 printf(" -d = debug (double to add timestamps)\n");
1979 printf(" -n = no autologin\n");
1980 printf(" -v = verbose (default)\n");
1981 printf(" -q = quiet\n");
1982 printf(" -S = Stay (issue command prompt when done)\n");
1983 printf(" -Y = do not execute Kermit init file\n");
1984 printf(" -p files = files to put after autologin (or -s)\n");
1985 printf(" -g files = files to get after autologin\n");
1986 printf(" -R = recursive (for use with -p)\n");
1989 printf("\nSecurity options:\n");
1990 printf(" -k realm = Kerberos 4 realm\n");
1991 printf(" -f = Kerboros 5 credentials forwarding\n");
1992 printf(" -x = autoencryption mode\n");
1993 printf(" -c cipher = SRP cipher type\n");
1994 printf(" -H hash = SRP encryption hash\n");
1995 printf(" -z option = Security options\n");
1996 #endif /* FTP_SECURITY */
1998 printf("\n-p or -g, if given, should be last. Example:\n");
1999 printf(" ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2001 doexit(GOOD_EXIT,-1);
2004 case 'R': /* Recursive */
2008 case 'd': /* Debug */
2014 deblog = debopn("debug.log",0);
2018 /* fall thru on purpose */
2020 case 't': /* Trace */
2024 case 'n': /* No autologin */
2028 case 'i': /* No prompt */
2029 case 'v': /* Verbose */
2030 break; /* (ignored) */
2032 case 'q': /* Quiet */
2036 case 'S': /* Stay */
2041 case 'u': /* My User Name */
2042 if ((int)strlen(*xargv) > 63) {
2043 fatal("username too long");
2045 ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2050 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2054 case 'T': /* Text */
2055 case 'a': /* "ascii" */
2056 case 'b': /* Binary */
2057 binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2065 case 's': { /* Send (= Put) */
2068 fatal("Only one FTP action at a time please");
2071 fatal("invalid argument bundling after -s");
2073 nfils = 0; /* Initialize file counter */
2074 havefiles = 0; /* Assume nothing to send */
2075 cmlist = xargv + 1; /* Remember this pointer */
2077 while (++xargv, --xargc > 0) { /* Traverse the list */
2084 if (!strcmp(*xargv,".")) {
2089 #endif /* RECURSIVE */
2090 if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2094 } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2099 xargc++, xargv--; /* Adjust argv/argc */
2102 fatal("No files to put");
2104 fatal("No files to get");
2110 case 'D': /* Directory */
2111 makestr(&ftp_rdir,*xargv);
2114 case 'm': /* Mode (Active/Passive */
2115 ftp_psv = lookup(modetab,*xargv,2,NULL);
2116 if (ftp_psv < 0) fatal("Invalid mode");
2120 makestr(&ftp_tmp,*xargv); /* You-Know-What */
2123 case 'Y': /* No initialization file */
2124 break; /* (already done in prescan) */
2127 case 'U': { /* URL */
2128 /* These are set by urlparse() - any not set are NULL */
2131 Kermit has accepted host:port notation since many years before URLs were
2132 invented. Unfortunately, URLs conflict with this notation. Thus "ftp
2133 host:449" looks like a URL and results in service = host and host = 449.
2134 Here we try to catch this situation transparently to the user.
2136 if (ckstrcmp(g_url.svc,"ftp",-1,0)
2138 && ckstrcmp(g_url.svc,"ftps",-1,0)
2145 g_url.por = g_url.hos;
2146 g_url.hos = g_url.svc;
2149 ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2150 g_url.svc," host=",g_url.hos);
2154 makestr(&ftp_host,g_url.hos);
2157 ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2158 makestr(&ftp_logname,uidbuf);
2161 makestr(&ftp_tmp,g_url.psw);
2166 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2167 makestr(&ftp_logname,uidbuf);
2170 fatal("Only one FTP action at a time please");
2175 dummy[0] = g_url.pth;
2187 case 'k': { /* K4 Realm */
2189 ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2190 #endif /* FTP_KRB4 */
2191 if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2197 if (ftp_deb) printf("K5 Credentials Forwarding\n");
2198 #else /* FTP_GSSAPI */
2199 printf("K5 Credentials Forwarding not supported\n");
2200 #endif /* FTP_GSSAPI */
2205 if (ftp_deb) printf("Autoencryption\n");
2208 case 'c': { /* Cipher */
2210 if (!srp_selcipher(*xargv)) {
2211 if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2213 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2215 printf("?SRP not supported\n");
2216 #endif /* FTP_SRP */
2221 if (!srp_selhash(*xargv)) {
2222 if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2224 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2226 printf("?SRP not supported\n");
2227 #endif /* FTP_SRP */
2231 /* *xargv contains a value of the form tag=value */
2232 /* we need to lookup the tag and save the value */
2233 char * p = NULL, * q = NULL;
2235 y = ckindex("=",p,0,0,1);
2238 x = lookup(ftpztab,p,nftpztab,&z);
2240 printf("?Invalid security option: \"%s\"\n",p);
2243 printf("Security option: \"%s",p);
2244 if (ftpztab[z].flgs & CM_ARG) {
2246 fatal("?Missing required value");
2249 fatal("?Missing required value");
2253 switch (ftpztab[z].kwval) { /* -z options w/args */
2256 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2257 if (ftp_auth_type[z] == FTA_GK5) {
2259 y < (FTPATYPS-1) && ftp_auth_type[y];
2262 ftp_auth_type[y] = ftp_auth_type[y+1];
2263 ftp_auth_type[FTPATYPS-1] = 0;
2267 #endif /* FTP_GSSAPI */
2271 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2272 if (ftp_auth_type[z] == FTA_K4) {
2274 y < (FTPATYPS-1) && ftp_auth_type[y];
2277 ftp_auth_type[y] = ftp_auth_type[y+1];
2278 ftp_auth_type[FTPATYPS-1] = 0;
2282 #endif /* FTP_KRB4 */
2286 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2287 if (ftp_auth_type[z] == FTA_SRP) {
2289 y < (FTPATYPS-1) && ftp_auth_type[y];
2292 ftp_auth_type[y] = ftp_auth_type[y+1];
2293 ftp_auth_type[FTPATYPS-1] = 0;
2297 #endif /* FTP_SRP */
2301 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2302 if (ftp_auth_type[z] == FTA_SSL) {
2304 y < (FTPATYPS-1) && ftp_auth_type[y];
2307 ftp_auth_type[y] = ftp_auth_type[y+1];
2308 ftp_auth_type[FTPATYPS-1] = 0;
2316 for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2317 if (ftp_auth_type[z] == FTA_TLS) {
2319 y < (FTPATYPS-1) && ftp_auth_type[y];
2322 ftp_auth_type[y] = ftp_auth_type[y+1];
2323 ftp_auth_type[FTPATYPS-1] = 0;
2331 makestr(&ssl_rsa_cert_file,q);
2336 ssl_certsok_flag = 1;
2345 deblog = debopn("debug.log",0);
2351 makestr(&ssl_rsa_key_file,q);
2360 printf("?Bad number: %s\n",q);
2361 ssl_verify_flag = atoi(q);
2366 if (ftp_deb) printf("\"\n");
2370 #endif /* FTP_SECURITY */
2374 "unknown command-line option, type \"ftp -h\" for help"
2378 c = *++xp; /* See if options are bundled */
2391 return(connected ? loggedin : 0);
2396 return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2400 ftscreen(n, c, z, s) int n; char c; long z; char * s; {
2401 if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2403 ckscreen(SCR_PT,'S',0L,"");
2411 /* g m s t i m e r -- Millisecond timer */
2416 /* For those versions of ztime() that also set global ztmsec. */
2421 if (!*p) return(0L);
2422 z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2423 return(z * 1000 + ztmsec);
2425 return((long)time(NULL) * 1000L);
2426 #endif /* HAVE_MSECS */
2430 /* d o s e t f t p -- The SET FTP command */
2435 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2439 case FTS_FNC: /* Filename collision action */
2440 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2442 if ((y = cmcfm()) < 0)
2447 case FTS_CNV: /* Filename conversion */
2448 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2450 if ((y = cmcfm()) < 0)
2455 case FTS_DBG: /* Debug messages */
2456 return(seton(&ftp_deb));
2458 case FTS_LOG: /* Auto-login */
2459 return(seton(&ftp_log));
2461 case FTS_PSV: /* Passive mode */
2462 return(dosetftppsv());
2464 case FTS_SPC: /* Send port commands */
2465 x = seton(&ftp_spc);
2466 if (x > 0) sendport = ftp_spc;
2469 case FTS_TYP: /* Type */
2470 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2472 if ((y = cmcfm()) < 0) return(y);
2475 tenex = (ftp_typ == FTT_TEN);
2478 case FTS_USN: /* Unique server names */
2479 return(seton(&ftp_usn));
2481 case FTS_VBM: /* Verbose mode */
2482 if ((x = seton(&ftp_vbm)) < 0) /* Per-command copy */
2484 ftp_vbx = ftp_vbm; /* Global sticky copy */
2487 case FTS_TST: /* "if (testing)" messages */
2488 return(seton(&testing));
2490 case FTS_PRM: /* Send permissions */
2491 return(setonaut(&ftp_prm));
2493 case FTS_AUT: /* Auto-authentication */
2494 return(seton(&ftp_aut));
2496 case FTS_ERR: /* Error action */
2497 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2499 if ((y = cmcfm()) < 0)
2502 return(success = 1);
2505 case FTS_XLA: /* Translation */
2506 return(seton(&ftp_xla));
2508 case FTS_CSR: /* Server charset */
2509 if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2511 if ((y = cmcfm()) < 0)
2514 ftp_xla = 1; /* Also enable translation */
2515 return(success = 1);
2516 #endif /* NOCSETS */
2519 return(seton(&get_auto)); /* GET-filetype-switching */
2522 return(seton(&ftp_dates)); /* Set file dates */
2524 case FTS_STO: { /* Server time offset */
2525 char * s, * p = NULL;
2527 if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2529 if (!strcmp(s,"+0")) {
2531 } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2532 printf("?Invalid time offset\n");
2535 makestr(&p,s); /* Make a safe copy the string */
2536 if ((x = cmcfm()) < 0) { /* Get confirmation */
2541 fts_sto = p; /* Confirmed - set the string. */
2542 return(success = 1);
2546 if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2548 makestr(&ftp_apw, *s ? s : NULL);
2549 return(success = 1);
2553 if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2558 return seton(&ftp_bug_use_ssl_v2);
2566 case FTS_CRY: /* Auto-encryption */
2567 return(seton(&ftp_cry));
2569 case FTS_CFW: /* Credential-forwarding */
2570 return(seton(&ftp_cfw));
2572 case FTS_CPL: /* Command protection level */
2573 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2574 if ((y = cmcfm()) < 0) return(y);
2575 success = fts_cpl(x);
2578 case FTS_DPL: /* Data protection level */
2579 if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2580 if ((y = cmcfm()) < 0) return(y);
2581 success = fts_dpl(x);
2584 case FTS_ATP: { /* FTP Auth Type */
2585 int i, j, atypes[8];
2587 for (i = 0; i < 8; i++) {
2588 if ((y = cmkey(ftpauth,nftpauth,"",
2589 (i == 0) ? "automatic" : "",
2595 if (i > 0 && (y == FTA_AUTO)) {
2596 printf("?Choice may only be used in first position.\r\n");
2599 for (j = 0; j < i; j++) {
2600 if (atypes[j] == y) {
2601 printf("\r\n?Choice has already been used.\r\n");
2606 if (y == FTA_AUTO) {
2613 if ((z = cmcfm()) < 0)
2615 if (atypes[0] == FTA_AUTO) {
2618 ftp_auth_type[i++] = FTA_GK5;
2619 #endif /* FTP_GSSAPI */
2621 ftp_auth_type[i++] = FTA_SRP;
2622 #endif /* FTP_SRP */
2624 ftp_auth_type[i++] = FTA_K4;
2625 #endif /* FTP_KRB4 */
2627 ftp_auth_type[i++] = FTA_TLS;
2628 ftp_auth_type[i++] = FTA_SSL;
2630 ftp_auth_type[i] = 0;
2632 for (i = 0; i < 8; i++)
2633 ftp_auth_type[i] = atypes[i];
2635 return(success = 1);
2640 if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2644 if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2646 if ((z = cmcfm()) < 0)
2648 success = !srp_selcipher(ciphertab[x].kwd);
2651 if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2653 if ((z = cmcfm()) < 0)
2655 success = !srp_selhash(hashtab[x].kwd);
2656 return(success = 1);
2658 if ((z = cmcfm()) < 0)
2663 if ((z = cmcfm()) < 0)
2666 #endif /* FTP_SRP */
2667 #endif /* FTP_SECURITY */
2670 doxdis(2); /* 2 == ftp */
2671 return(success = 1);
2684 printf(" ftp closing %s...\n",ftp_host);
2686 return((x > -1) ? 1 : 0);
2689 /* o p e n f t p -- Parse FTP hostname & port and open */
2692 openftp(s,opn_tls) char * s; int opn_tls; {
2693 char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2694 int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2696 struct FDB sw, fl, cm;
2697 extern int nnetdir; /* Network services directory */
2698 extern int nhcount; /* Lookup result */
2699 extern char *nh_p[]; /* Network directory entry pointers */
2700 extern char *nh_p2[]; /* Network directory entry nettype */
2703 if (!*s) return(-2);
2705 makestr(&hostname,s);
2706 hostsave = hostname;
2707 makestr(&ftp_logname,NULL);
2711 debug(F110,"ftp open",hostname,0);
2713 if (sav_psv > -1) { /* Restore prevailing active/passive */
2714 ftp_psv = sav_psv; /* selection in case it was */
2715 sav_psv = -1; /* temporarily overriden by a switch */
2717 if (sav_log > -1) { /* Ditto for autologin */
2721 cmfdbi(&sw, /* Switches */
2723 "Service name or port;\n or switch",
2725 "", /* addtl string data */
2726 nftpswi, /* addtl numeric data 1: tbl size */
2727 4, /* addtl numeric data 2: none */
2728 xxstring, /* Processing function */
2729 ftpswitab, /* Keyword table */
2730 &fl /* Pointer to next FDB */
2732 cmfdbi(&fl, /* A host name or address */
2735 "xYzBoo", /* default */
2736 "", /* addtl string data */
2737 0, /* addtl numeric data 1 */
2738 0, /* addtl numeric data 2 */
2743 cmfdbi(&cm, /* Command confirmation */
2756 rc = cmfdb(&sw); /* Parse a service name or a switch */
2760 if (cmresult.fcode == _CMCFM) { /* Done? */
2762 } else if (cmresult.fcode == _CMFLD) { /* Port */
2763 if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2764 makestr(&service,cmresult.sresult);
2766 makestr(&service,opn_tls?"ftps":"ftp");
2767 } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2768 c = cmgbrk(); /* get break character */
2769 getval = (c == ':' || c == '=');
2771 if (getval && !(cmresult.kflags & CM_ARG)) {
2772 printf("?This switch does not take arguments\n");
2775 if (!getval && (cmresult.kflags & CM_ARG)) {
2776 printf("?This switch requires an argument\n");
2779 switch (cmresult.nresult) { /* Switch */
2780 case OPN_ANO: /* /ANONYMOUS */
2784 case OPN_NIN: /* /NOINIT */
2787 case OPN_NOL: /* /NOLOGIN */
2790 makestr(&ftp_logname,NULL);
2792 case OPN_PSW: /* /PASSWORD */
2793 if (!anonymous) /* Don't log real passwords */
2795 rc = cmfld("Password for FTP server","",&p,xxstring);
2797 makestr(&ftp_tmp,NULL);
2798 } else if (rc < 0) {
2801 makestr(&ftp_tmp,brstrip(p));
2805 case OPN_USR: /* /USER */
2806 rc = cmfld("Username for FTP server","",&p,xxstring);
2808 makestr(&ftp_logname,NULL);
2809 } else if (rc < 0) {
2815 makestr(&ftp_logname,brstrip(p));
2819 rc = cmfld("Account for FTP server","",&p,xxstring);
2821 makestr(&ftp_acc,NULL);
2822 } else if (rc < 0) {
2825 makestr(&ftp_acc,brstrip(p));
2841 if (n == 0) { /* After first time through */
2842 cmfdbi(&sw, /* accept only switches */
2844 "\nCarriage return to confirm to command, or switch",
2856 debug(F100,"ftp openftp while exit","",0);
2858 debug(F101,"ftp openftp cmcfm rc","",rc);
2861 #endif /* COMMENT */
2863 if (opn_psv > -1) { /* /PASSIVE or /ACTIVE switch given */
2867 if (nologin || haveuser) { /* /NOLOGIN or /USER switch given */
2869 ftp_log = haveuser ? 1 : 0;
2871 if (*hostname == '=') { /* Bypass directory lookup */
2872 hostname++; /* if hostname starts with '=' */
2874 } else if (isdigit(*hostname)) { /* or if it starts with a digit */
2878 makestr(&service,opn_tls?"ftps":"ftp");
2881 if (!havehost && nnetdir > 0) { /* If there is a networks directory */
2882 lunet(hostname); /* Look up the name */
2883 debug(F111,"ftp openftp lunet",hostname,nhcount);
2886 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
2887 success = ftpopen(hostname,service,opn_tls);
2888 debug(F101,"ftp openftp A ftpopen success","",success);
2892 for (i = 0; i < nhcount; i++) {
2893 if (nh_p2[i]) /* If network type specified */
2894 if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
2897 makestr(&hostname,nh_p[i]);
2898 debug(F111,"ftpopen lunet substitution",hostname,i);
2900 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
2901 success = ftpopen(hostname,service,opn_tls);
2902 debug(F101,"ftp openftp B ftpopen success","",success);
2907 if (!found) { /* E.g. if no network types match */
2909 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
2910 success = ftpopen(hostname,service,opn_tls);
2911 debug(F101,"ftp openftp C ftpopen success","",success);
2918 printf(" ftp open trying \"%s %s\"...\n",hostname,service);
2919 success = ftpopen(hostname,service,opn_tls);
2920 debug(F111,"ftp openftp D ftpopen success",hostname,success);
2921 debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
2928 debug(F101,"ftp openftp xopenftp rc","",rc);
2929 if (hostsave) free(hostsave);
2930 if (service) free(service);
2931 if (rc < 0 && ftp_logname) {
2946 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
2949 makestr(&ftp_acc,brstrip(s));
2951 printf(" ftp account: \"%s\"\n",ftp_acc);
2952 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
2957 doftpusr() { /* Log in as USER */
2959 char *s, * acct = "";
2961 debok = 0; /* Don't log */
2962 if ((x = cmfld("Remote username or ID","",&s,xxstring)) < 0)
2964 ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
2965 if ((x = cmfld("Remote password","",&s,xxstring)) < 0)
2968 ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
2969 if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
2970 "", &s, xxstring)) < 0)
2976 acct = &tmpbuf[x+2];
2977 ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
2981 printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
2982 success = ftp_user(line,tmpbuf,acct);
2985 #endif /* CKLOGDIAL */
2989 /* DO (various FTP commands)... */
2992 doftptyp(type) int type; { /* TYPE */
2995 changetype(ftp_typ,ftp_vbm);
3000 doftpxmkd(s,vbm) char * s; int vbm; { /* MKDIR action */
3001 int lcs = -1, rcs = -1;
3005 if (lcs < 0) lcs = fcharset;
3007 if (rcs < 0) rcs = ftp_csr;
3009 #endif /* NOCSETS */
3010 debug(F110,"ftp doftpmkd",s,0);
3011 if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3012 return(success = 1);
3013 if (ftpcode == 500 || ftpcode == 502) {
3015 printf("MKD command not recognized, trying XMKD\n");
3016 if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3017 return(success = 1);
3019 return(success = 0);
3023 doftpmkd() { /* MKDIR parse */
3026 if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3029 ckstrncpy(line,s,LINBUFSIZ);
3031 printf(" ftp mkdir \"%s\"...\n",line);
3032 return(success = doftpxmkd(line,-1));
3036 doftprmd() { /* RMDIR */
3037 int x, lcs = -1, rcs = -1;
3039 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3042 ckstrncpy(line,s,LINBUFSIZ);
3044 printf(" ftp rmdir \"%s\"...\n",line);
3048 if (lcs < 0) lcs = fcharset;
3050 if (rcs < 0) rcs = ftp_csr;
3052 #endif /* NOCSETS */
3053 if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3054 return(success = 1);
3055 if (ftpcode == 500 || ftpcode == 502) {
3057 printf("RMD command not recognized, trying XMKD\n");
3058 success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3065 doftpren() { /* RENAME */
3068 if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3070 ckstrncpy(line,s,LINBUFSIZ);
3071 if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3073 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3074 if ((x = cmcfm()) < 0)
3078 printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3079 success = ftp_rename(line,tmpbuf);
3084 doftpres() { /* RESET (log out without close) */
3086 if ((x = cmcfm()) < 0)
3090 printf(" ftp reset...\n");
3091 return(success = ftp_reset());
3095 doftpxhlp() { /* HELP */
3098 if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3101 ckstrncpy(line,s,LINBUFSIZ);
3103 printf(" ftp help \"%s\"...\n",line);
3104 /* No need to translate -- all FTP commands are ASCII */
3105 return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3109 doftpdir(cx) int cx; { /* [V]DIRECTORY */
3110 int x, lcs = 0, rcs = 0, xlate = 0;
3111 char * p, * s, * m = "";
3112 if (cx == FTP_VDI) {
3113 switch (servertype) {
3124 if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3126 if ((x = remtxt(&s)) < 0)
3132 #endif /* NOCSETS */
3134 ckstrncpy(line,s,LINBUFSIZ);
3139 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
3140 lcs = ftp_csl; /* Local charset */
3141 if (lcs < 0) lcs = fcharset;
3142 if (lcs < 0) xlate = 0;
3144 if (xlate) { /* Still ON? */
3145 rcs = ftp_csx; /* Remote (Server) charset */
3146 if (rcs < 0) rcs = ftp_csr;
3147 if (rcs < 0) xlate = 0;
3149 #endif /* NOCSETS */
3155 printf("Directory of files %s at %s:\n", line, ftp_host);
3157 printf("Directory of files at %s:\n", ftp_host);
3159 debug(F111,"doftpdir",s,cx);
3161 if (cx == FTP_DIR) {
3162 /* Translation of line[] is done inside recvrequest() */
3163 /* when it calls ftpcmd(). */
3165 (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3167 success = 1; /* VDIR - one file at a time... */
3168 p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3170 if (!ftp_vbm && !quiet)
3172 while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3173 if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3177 p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3178 debug(F110,"ftp vdir file",s,0);
3184 doftppwd() { /* PWD */
3185 int x, lcs = -1, rcs = -1;
3189 if (lcs < 0) lcs = fcharset;
3191 if (rcs < 0) rcs = ftp_csr;
3193 #endif /* NOCSETS */
3194 if ((x = cmcfm()) < 0)
3197 if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3199 } else if (ftpcode == 500 || ftpcode == 502) {
3201 printf("PWD command not recognized, trying XPWD\n");
3202 success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3208 doftpcwd(s,vbm) char * s; int vbm; { /* CD (CWD) */
3209 int lcs = -1, rcs = -1;
3213 if (lcs < 0) lcs = fcharset;
3215 if (rcs < 0) rcs = ftp_csr;
3217 #endif /* NOCSETS */
3219 debug(F110,"ftp doftpcwd",s,0);
3220 if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3221 return(success = 1);
3222 if (ftpcode == 500 || ftpcode == 502) {
3224 printf("CWD command not recognized, trying XCWD\n");
3225 if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3226 return(success = 1);
3228 return(success = 0);
3232 doftpcdup() { /* CDUP */
3233 debug(F100,"ftp doftpcdup","",0);
3234 if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3235 return(success = 1);
3236 if (ftpcode == 500 || ftpcode == 502) {
3238 printf("CDUP command not recognized, trying XCUP\n");
3239 if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3240 return(success = 1);
3242 return(success = 0);
3245 /* s y n c d i r -- Synchronizes client & server directories */
3247 /* Used with recursive PUTs; Returns 0 on failure, 1 on success */
3249 static int cdlevel = 0, cdsimlvl = 0;
3252 syncdir(local,sim) char * local; int sim; {
3253 char buf[CKMAXPATH+1];
3254 char tmp[CKMAXPATH+1];
3255 char msgbuf[CKMAXPATH+64];
3256 char c, * p = local, * s = buf, * q = buf;
3257 int i, k = 0, done = 0, itsadir = 0, saveq;
3259 debug(F110,"ftp syncdir local (new)",local,0);
3260 debug(F110,"ftp syncdir putpath (old)",putpath,0);
3262 itsadir = isdir(local);
3265 while ((*s = *p)) { /* Copy the argument filename */
3266 if (++k == CKMAXPATH) /* so we can poke it. */
3268 if (*s == '/') /* Pointer to rightmost dirsep */
3274 *q = NUL; /* Keep just the path part */
3276 debug(F110,"ftp syncdir buf",buf,0);
3277 if (!strcmp(buf,putpath)) { /* Same as for previous file? */
3278 if (itsadir) { /* It's a directory? */
3279 if (doftpcwd(local,0)) { /* Try to CD to it */
3280 doftpcdup(); /* Worked - CD back up */
3281 } else if (sim) { /* Simulating... */
3282 if (fdispla == XYFD_B) {
3283 printf("WOULD CREATE DIRECTORY %s\n",local);
3284 } else if (fdispla) {
3285 ckmakmsg(msgbuf,CKMAXPATH,
3286 "WOULD CREATE DIRECTORY",local,NULL,NULL);
3287 ftscreen(SCR_ST,ST_MSG,0l,msgbuf);
3289 /* See note above */
3291 } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3294 if (fdispla == XYFD_B) {
3295 printf("CREATED DIRECTORY %s\n",local);
3296 } else if (fdispla) {
3297 ckmakmsg(msgbuf,CKMAXPATH+64,
3298 "CREATED DIRECTORY ",local,NULL,NULL);
3299 ftscreen(SCR_ST,ST_MSG,0l,msgbuf);
3303 debug(F110,"ftp syncdir no change",buf,0);
3304 return(1); /* Yes, done. */
3306 ckstrncpy(tmp,buf,CKMAXPATH+1); /* Make a safe (pre-poked) copy */
3307 debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3310 s = putpath; /* Old */
3312 debug(F110,"ftp syncdir A p",p,0);
3313 debug(F110,"ftp syncdir A s",s,0);
3315 while (*p != NUL && *s != NUL && *p == *s) p++,s++;
3317 if (*s == '/' && !*p) s++; /* Don't count initial slash */
3319 debug(F110,"ftp syncdir B p",p,0);
3320 debug(F110,"ftp syncdir B s",s,0);
3322 /* p and s now point to the leftmost spot where they differ */
3324 if (*s) { /* We have to back up */
3325 k = 1; /* How many levels */
3326 while ((c = *s++)) { /* Count dirseps */
3330 for (i = 0; i < k; i++) { /* Do that many CDUPs */
3331 debug(F111,"ftp syncdir up",p,i+1);
3332 if (sim && cdsimlvl) {
3342 if (!*p) /* If we don't have to go down */
3343 goto xcwd; /* we're done. */
3345 while (p > buf && *p && *p != '/') /* If in middle of segment */
3346 p--; /* back up to beginning */
3347 if (*p == '/') /* and terminate there */
3350 s = p; /* Point to start of new down path. */
3351 while (1) { /* Loop through characters. */
3352 if (*s == '/' || !*s) { /* Have a segment. */
3353 if (!*s) /* If end of string, */
3354 done++; /* after this segment we're done. */
3356 *s = NUL; /* NUL out the separator. */
3357 if (*p) { /* If segment is not empty */
3358 debug(F110,"ftp syncdir down segment",p,0);
3359 if (!doftpcwd(p,0)) { /* Try to CD to it */
3361 if (fdispla == XYFD_B) {
3362 printf("WOULD CREATE DIRECTORY %s\n",local);
3363 } else if (fdispla) {
3364 ckmakmsg(msgbuf,CKMAXPATH,"WOULD CREATE DIRECTORY",
3366 ftscreen(SCR_ST,ST_MSG,0l,msgbuf);
3370 if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3372 Suppose we are executing SEND /RECURSIVE. Locally we have a directory
3373 FOO but the remote has a regular file with the same name. We can't CD
3374 to it, can't MKDIR it either. There's no way out but to fail and let
3375 the user handle the problem.
3380 if (fdispla == XYFD_B) {
3381 printf("CREATED DIRECTORY %s\n",p);
3382 } else if (fdispla) {
3383 ckmakmsg(msgbuf,CKMAXPATH,
3384 "CREATED DIRECTORY ",p,NULL,NULL);
3385 ftscreen(SCR_ST,ST_MSG,0l,msgbuf);
3387 if (!doftpcwd(p,0)) { /* Try again to CD */
3395 if (done) /* Quit if no next segment */
3397 p = s+1; /* Point to next segment */
3399 s++; /* Point to next source char */
3403 ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3411 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3413 debug(F111,"ftp year ",s,xx->tm_year);
3414 debug(F111,"ftp month",s,xx->tm_mon);
3415 debug(F111,"ftp day ",s,xx->tm_mday);
3416 debug(F111,"ftp hour ",s,xx->tm_hour);
3417 debug(F111,"ftp min ",s,xx->tm_min);
3418 debug(F111,"ftp sec ",s,xx->tm_sec);
3423 /* t m c o m p a r e -- Compare two struct tm's */
3425 /* Like strcmp() but for struct tm's */
3426 /* Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3429 tmcompare(xx,yy) struct tm * xx, * yy; {
3431 if (xx->tm_year < yy->tm_year) /* First year less than second */
3433 if (xx->tm_year > yy->tm_year) /* First year greater than second */
3436 /* Years are equal so compare months */
3438 if (xx->tm_mon < yy->tm_mon) /* And so on... */
3440 if (xx->tm_mon > yy->tm_mon)
3443 if (xx->tm_mday < yy->tm_mday)
3445 if (xx->tm_mday > yy->tm_mday)
3448 if (xx->tm_hour < yy->tm_hour)
3450 if (xx->tm_hour > yy->tm_hour)
3453 if (xx->tm_min < yy->tm_min)
3455 if (xx->tm_min > yy->tm_min)
3458 if (xx->tm_sec < yy->tm_sec)
3460 if (xx->tm_sec > yy->tm_sec)
3465 #endif /* DOUPDATE */
3467 #ifndef HAVE_TIMEGM /* For platforms that do not have timegm() */
3468 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3469 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3472 /* Macro for whether a given year is a leap year. */
3473 #define ISLEAP(year) \
3474 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3475 #endif /* HAVE_TIMEGM */
3477 /* m k u t i m e -- Like mktime() but argument is already UTC */
3481 mkutime(struct tm * tm)
3483 mkutime(tm) struct tm * tm;
3484 #endif /* CK_ANSIC */
3487 return(timegm(tm)); /* Have system service, use it. */
3490 Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3491 Given a struct tm representing a calendar time in UTC, convert it to
3492 seconds since epoch. Returns (time_t) -1 if the time is not
3493 convertable. Note that this function does not canonicalize the provided
3494 struct tm, nor does it allow out-of-range values or years before 1970.
3495 Result should be identical with timegm().
3500 We do allow some ill-formed dates, but we don't do anything special
3501 with them and our callers really shouldn't pass them to us. Do
3502 explicitly disallow the ones that would cause invalid array accesses
3503 or other algorithm problems.
3507 debug(F101,"mkutime tm_mon","",tm->tm_mon);
3508 debug(F101,"mkutime tm_year","",tm->tm_year);
3511 if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3512 return((time_t) -1);
3514 /* Convert to time_t. */
3515 for (i = 1970; i < tm->tm_year + 1900; i++)
3516 result += 365 + ISLEAP(i);
3517 for (i = 0; i < tm->tm_mon; i++)
3518 result += MONTHDAYS[i];
3519 if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3521 result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3522 result = 60 * result + tm->tm_min;
3523 result = 60 * result + tm->tm_sec;
3524 debug(F101,"mkutime result","",result);
3526 #endif /* HAVE_TIMEGM */
3531 s e t m o d t i m e -- Set file modification time.
3533 f = char * filename;
3534 t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3536 UNIX-specific; isolates mainline code from hideous #ifdefs.
3544 setmodtime(char * f, time_t t)
3546 setmodtime(f,t) char * f; time_t t;
3547 #endif /* CK_ANSIC */
3556 struct timeval tp[2];
3574 #endif /* SYSUTIMEH */
3578 if (stat(f,&sb) < 0) {
3579 debug(F111,"setmodtime stat failure",f,errno);
3583 tp[0].tv_sec = sb.st_atime; /* Access time first */
3584 tp[1].tv_sec = t; /* Update time second */
3585 debug(F111,"setmodtime BSD44",f,t);
3588 tp.timep[0] = t; /* Set modif. time to creation date */
3589 tp.timep[1] = sb.st_atime; /* Don't change the access time */
3590 debug(F111,"setmodtime V7",f,t);
3593 tp.modtime = t; /* Set modif. time to creation date */
3594 tp.actime = sb.st_atime; /* Don't change the access time */
3595 debug(F111,"setmodtime SYSUTIMEH",f,t);
3597 tp.mtime = t; /* Set modif. time to creation date */
3598 tp.atime = sb.st_atime; /* Don't change the access time */
3599 debug(F111,"setmodtime (other)",f,t);
3600 #endif /* SYSUTIMEH */
3604 /* Try to set the file date */
3608 debug(F111,"setmodtime utimes()","BSD44",x);
3613 The following produces the nonsensical warning:
3614 Argument of type "const struct utimbuf *" is incompatible with
3615 parameter of type "const struct utimbuf *". If you can make it
3616 go away, be my guest.
3618 const struct utimbuf * t2 = &tp;
3623 debug(F111,"setmodtime utime()","other",x);
3629 debug(F101,"setmodtime result","",rc);
3635 c h k m o d t i m e -- Check/Set file modification time.
3640 0 if local older than remote,
3641 1 if modtimes are equal,
3642 2 if local newer than remote.
3643 1 = Set (local file's modtime from remote's); returns:
3648 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3650 struct _stat statbuf;
3652 struct stat statbuf;
3654 struct tm * tmlocal = NULL;
3656 int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3657 char * s, timebuf[64];
3659 debug(F111,"chkmodtime",local,mdtmok);
3660 if (!mdtmok) /* Server supports MDTM? */
3661 return(-1); /* No don't bother. */
3666 if (lcs < 0) lcs = fcharset;
3668 if (rcs < 0) rcs = ftp_csr;
3670 #endif /* NOCSETS */
3673 rc = stat(local,&statbuf);
3674 if (rc == 0) { /* Get local file's mod time */
3675 tmlocal = gmtime(&statbuf.st_mtime); /* Convert to struct tm */
3678 dbtime(local,tmlocal);
3683 /* Get remote file's mod time as yyyymmddhhmmss */
3685 if (havemdtm) { /* Already got it from MLSD? */
3688 } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3690 bzero((char *)&tmremote, sizeof(struct tm));
3692 while ((c = *s++)) { /* Skip past response code */
3700 debug(F111,"ftp chkmodtime string",s,flag);
3701 if (fts_sto) { /* User gave server time offset? */
3703 debug(F110,"ftp chkmodtime offset",fts_sto,0);
3704 ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3705 if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3706 ckstrncpy(timebuf,p,64); /* Convert to MDTM format */
3707 timebuf[8] = timebuf[9]; /* h */
3708 timebuf[9] = timebuf[10]; /* h */
3709 timebuf[10] = timebuf[12]; /* m */
3710 timebuf[11] = timebuf[13]; /* m */
3711 timebuf[12] = timebuf[12]; /* s */
3712 timebuf[13] = timebuf[13]; /* s */
3715 debug(F110,"ftp chkmodtime adjust",s,0);
3718 if (flag) { /* Convert to struct tm */
3720 int y2kbug = 0; /* Seen in Kerberos 4 FTP servers */
3721 if (!ckstrcmp(s,"191",3,0)) {
3722 pat = "%05d%02d%02d%02d%02d%02d";
3724 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3726 pat = "%04d%02d%02d%02d%02d%02d";
3728 if (sscanf(s, /* Parse into struct tm */
3730 &(tmremote.tm_year),
3732 &(tmremote.tm_mday),
3733 &(tmremote.tm_hour),
3737 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3738 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
3742 debug(F100,"SERVER TIME FOLLOWS:","",0);
3743 dbtime(remote,&tmremote);
3750 } else { /* Failed */
3751 debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
3752 if (ftpcode == 500 || /* Command unrecognized */
3753 ftpcode == 502 || /* Command not implemented */
3754 ftpcode == 202) /* Command superfluous */
3755 mdtmok = 0; /* Don't ask this server again */
3758 if (fc == 0) { /* Compare */
3759 if (havedate == 1) { /* Only if we have both file dates */
3761 Compare with local file's time. We don't use
3762 clock time (time_t) here in case of signed/unsigned
3769 dbtime("LOCAL",tmlocal);
3770 dbtime("REMOT",&tmremote);
3773 #endif /* COMMENT */
3774 xx = tmcompare(tmlocal,&tmremote);
3775 debug(F101,"chkmodtime tmcompare","",xx);
3778 } else if (ftp_dates) { /* Set */
3780 Here we must convert struct tm to time_t
3781 without applying timezone conversion, for which
3782 there is no portable API. The method is hidden
3783 in mkutime(), defined above.
3786 utc = mkutime(&tmremote);
3787 debug(F111,"ftp chkmodtime mkutime",remote,utc);
3788 if (utc != (time_t)-1)
3789 return(setmodtime(local,utc));
3794 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
3797 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
3798 char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
3807 #endif /* GFTIMER */
3808 char fullname[CKMAXPATH+1];
3810 debug(F110,"ftp getfile remote A",remote,0);
3811 debug(F110,"ftp getfile local A",local,0);
3812 debug(F110,"ftp getfile pipename",pipename,0);
3813 if (!remote) remote = "";
3816 /* Automatic type switching? */
3817 if (xfermode == XMODE_A && patterns && get_auto && !forcetype) {
3819 x = matchname(remote,0,servertype);
3820 debug(F111,"ftp getfile matchname",remote,x);
3822 case 0: ftp_typ = FTT_ASC; break;
3823 case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
3824 default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
3826 changetype(ftp_typ,ftp_vbm);
3827 binary = ftp_typ; /* For file-transfer display */
3829 #endif /* PATTERNS */
3832 ftp_csx = -1; /* For file-transfer display */
3833 ftp_csl = -1; /* ... */
3835 if (rcs > -1) /* -1 means no translation */
3836 if (ftp_typ == FTT_ASC) /* File type is "ascii"? */
3837 if (fcs < 0) /* File charset not forced? */
3838 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
3839 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
3840 debug(F110,"ftp getfile","initxlate",0);
3841 initxlate(rcs,fcs); /* NB: opposite order of PUT */
3846 #endif /* NOCSETS */
3848 if (!pipename && (!local || !local[0]))
3851 out2screen = !strcmp(local,"-");
3855 ckstrncpy(fullname,pipename,CKMAXPATH+1);
3857 zfnqfp(local,CKMAXPATH,fullname);
3859 ckstrncpy(fullname,local,CKMAXPATH+1);
3861 if (!out2screen && displa && fdispla) { /* Screen */
3862 ftscreen(SCR_FN,'F',(long)pktnum,remote);
3863 ftscreen(SCR_AN,0,0L,fullname);
3864 ftscreen(SCR_FS,0,fsize,"");
3866 tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
3867 tlog(F110," as",fullname,0);
3868 debug(F111,"ftp getfile size",remote,fsize);
3869 debug(F111,"ftp getfile local",local,out2screen);
3871 ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
3873 t0 = gmstimer(); /* Start time */
3874 debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
3875 rc = recvrequest("RETR",
3878 append ? "ab" : "wb",
3886 t1 = gmstimer(); /* End time */
3887 debug(F111,"ftp getfile t1",remote,t1);
3888 debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
3890 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
3891 fpxfsecs = sec; /* (for doxlog()) */
3893 sec = (t1 - t0) / 1000;
3895 #endif /* GFTIMER */
3896 debug(F111,"ftp recvrequest rc",remote,rc);
3897 if (cancelfile || cancelgroup) {
3898 debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
3899 ftscreen(SCR_ST,ST_INT,0l,"");
3900 } else if (rc > 0) {
3901 debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
3902 ftscreen(SCR_ST,ST_SKIP,0l,cmarg);
3903 } else if (rc < 0) {
3905 case -4: /* Network error */
3906 case -2: /* File error */
3907 ftscreen(SCR_ST,ST_MSG,0l,ck_errstr());
3910 ftscreen(SCR_ST,ST_MSG,0l,"Failure to make data connection");
3913 ftscreen(SCR_ST,ST_INT,0l,""); /* (should be covered above) */
3916 ftscreen(SCR_ST,ST_MSG,0l,&ftp_reply_str[4]);
3918 } else { /* Tudo bem */
3919 ftscreen(SCR_PT,'Z',0L,"");
3921 ftscreen(SCR_ST,ST_OK,0L,""); /* For screen */
3922 makestr(&rrfspec,remote); /* For WHERE command */
3923 makestr(&rfspec,fullname);
3926 if (ftp_dates) /* If FTP DATES ON... */
3927 if (!pipename && !out2screen) /* and it's a real file */
3928 if (rc < 1 && rc != -3) /* and it wasn't skipped */
3929 if (connected) /* and we still have a connection */
3930 if (zchki(local) > -1) { /* and the file wasn't discarded */
3931 chkmodtime(local,remote,1); /* set local file date */
3932 debug(F110,"ftp get set date",local,0);
3934 filcnt++; /* Used by \v(filenum) */
3938 tlog(F100," recovery skipped","",0);
3939 } else if (rc == 0) {
3940 tlog(F101," complete, size", "", fsize);
3941 } else if (cancelfile) {
3942 tlog(F100," canceled by user","",0);
3944 tlog(F110," failed:",ftp_reply_str,0);
3947 doxlog(what,local,fsize,ftp_typ,rc,"");
3953 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
3954 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
3958 local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
3959 char * local, * remote, * mvto, *rnto, *srvrn;
3960 int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg;
3964 char asname[CKMAXPATH+1];
3965 char fullname[CKMAXPATH+1];
3966 int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
3967 int xlate = 0, restart = 0, mt = -1;
3968 char * s = NULL, * cmd = NULL;
3969 ULONG t0 = 0, t1 = 0; /* Times for stats */
3970 int ofcs = 0, orcs = 0;
3976 #endif /* GFTIMER */
3977 debug(F111,"ftp putfile flg",local,flg);
3978 debug(F110,"ftp putfile srv_renam",srvrn,0);
3979 debug(F101,"ftp putfile fcs","",fcs);
3980 debug(F101,"ftp putfile rcs","",rcs);
3982 ofcs = fcs; /* Save charset args */
3986 restart = flg & PUT_RES;
3990 /* FTP protocol command to send to server */
3991 cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
3993 if (x_cnv == SET_AUTO) { /* Name conversion is auto */
3994 if (alike) { /* If server & client are alike */
3995 nc = 0; /* no conversion */
3996 } else { /* If they are different */
3997 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
3998 nc = -1; /* only minimal conversions needed */
3999 else /* otherwise */
4000 nc = 1; /* full conversion */
4002 } else /* Not auto - do what user said */
4005 /* If Transfer Mode is Automatic, determine file type */
4006 if (xfermode == XMODE_A && filepeek && !pipesend) {
4007 if (isdir(local)) { /* If it's a directory */
4008 k = FT_BIN; /* skip the file scan */
4010 debug(F110,"FTP PUT calling scanfile",local,0);
4011 k = scanfile(local,&o,nscanfile); /* Scan the file */
4013 debug(F111,"FTP PUT scanfile",local,k);
4014 if (k > -1 && !forcetype) {
4015 ftp_typ = (k == FT_BIN) ? 1 : 0;
4016 if (xft > -1 && ftp_typ != xft) {
4018 tlog(F110,"ftp put SKIP (Type):", local, 0);
4021 if (ftp_typ == 1 && tenex) /* User said TENEX? */
4026 ftp_csx = -1; /* For file-transfer display */
4027 ftp_csl = -1; /* ... */
4029 if (rcs > -1) { /* -1 means no translation */
4030 if (ftp_typ == 0) { /* File type is "ascii"? */
4031 if (fcs < 0) { /* File charset not forced? */
4032 if (k < 0) { /* If we didn't scan */
4033 fcs = fcharset; /* use prevailing FILE CHARACTER-SET */
4034 } else { /* If we did scan, use scan result */
4036 case FT_TEXT: /* Unknown text */
4039 case FT_7BIT: /* 7-bit text */
4042 case FT_8BIT: /* 8-bit text */
4045 case FT_UTF8: /* UTF-8 */
4048 case FT_UCS2: /* UCS-2 */
4050 if (o > -1) /* Input file byte order */
4060 if (fcs > -1 && rcs > -1) { /* Set up translation functions */
4061 debug(F110,"ftp putfile","initxlate",0);
4063 debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4068 #endif /* NOCSETS */
4070 binary = ftp_typ; /* For file-transfer display */
4073 if (recursive) { /* If sending recursively, */
4074 if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4075 return(-1); /* Don't PUT if it fails. */
4076 else if (isdir(local)) /* It's a directory */
4077 return(0); /* Don't send it! */
4079 if (*remote) { /* If an as-name template was given */
4081 if (cmd_quoting) { /* and COMMAND QUOTING is ON */
4082 y = CKMAXPATH; /* evaluate it for this file */
4084 zzstring(remote,&s,&y);
4087 ckstrncpy(asname,remote,CKMAXPATH); /* (or take it literally) */
4088 } else { /* No as-name */
4089 nzltor(local,asname,nc,0,CKMAXPATH); /* use local name strip path */
4090 debug(F110,"FTP PUT nzltor",asname,0);
4092 /* Preliminary messages and log entries */
4095 zfnqfp(local,CKMAXPATH,fullname);
4096 if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4097 fullname[CKMAXPATH] = NUL;
4099 if (displa && fdispla) { /* Screen */
4100 ftscreen(SCR_FN,'F',(long)pktnum,local);
4101 ftscreen(SCR_AN,0,0L,asname);
4102 ftscreen(SCR_FS,0,fsize,"");
4105 if (flg & (PUT_UPD|PUT_DIF)) { /* Date-checking modes... */
4106 mt = chkmodtime(fullname,asname,0);
4107 debug(F111,"ftp putfile chkmodtime",asname,mt);
4108 if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4109 tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4110 ftscreen(SCR_ST,ST_SKIP,SKP_DAT,fullname); /* Skip this one */
4113 } else if (mt == 1) { /* Times are equal */
4114 tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4115 ftscreen(SCR_ST,ST_SKIP,SKP_EQU,fullname); /* Skip it */
4119 /* Local file is newer */
4120 tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4121 "ftp put /update TEXT:", fullname, 0);
4122 } else if (flg & PUT_RES) {
4123 tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4124 "ftp put /recover TEXT:", fullname, 0);
4126 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4129 tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4130 #endif /* DOUPDATE */
4131 tlog(F110," as",asname,0);
4135 debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4136 tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4137 tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4138 } else if (!ftp_typ) {
4139 tlog(F110," character sets:","no conversion",0);
4140 fcs = ofcs; /* Binary file but we still must */
4141 rcs = orcs; /* translate its name */
4143 #endif /* NOCSETS */
4147 t0 = gmstimer(); /* Start time */
4148 if (flg & PUT_SIM) { /* rc > 0 is a skip reason code */
4149 if (flg & (PUT_UPD|PUT_DIF)) { /* (see SKP_xxx in ckcker.h) */
4150 rc = (mt < 0) ? /* Update mode... */
4151 SKP_XNX : /* Remote file doesn't exist */
4152 SKP_XUP; /* Remote file is older */
4154 rc = SKP_SIM; /* "Would be sent", period. */
4157 rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4159 t1 = gmstimer(); /* End time */
4160 filcnt++; /* File number */
4163 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4164 fpxfsecs = sec; /* (for doxlog()) */
4166 sec = (t1 - t0) / 1000;
4168 #endif /* GFTIMER */
4170 debug(F111,"ftp sendrequest rc",local,rc);
4172 if (cancelfile || cancelgroup) {
4173 debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4174 ftscreen(SCR_ST,ST_INT,0l,"");
4175 } else if (rc > 0) {
4176 debug(F101,"ftp put skipped",local,rc);
4177 ftscreen(SCR_ST,ST_SKIP,rc,fullname);
4178 } else if (rc < 0) {
4179 debug(F111,"ftp put error",local,ftpcode);
4180 ftscreen(SCR_ST,ST_MSG,0L,&ftp_reply_str[4]);
4182 debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4183 ftscreen(SCR_PT,'Z',0L,"");
4184 debug(F111,"ftp put ST_OK",local,rc);
4185 ftscreen(SCR_ST,ST_OK,0L,"");
4186 debug(F110,"ftp put old sfspec",sfspec,0);
4187 makestr(&sfspec,fullname); /* For WHERE command */
4188 debug(F110,"ftp put new sfspec",sfspec,0);
4189 debug(F110,"ftp put old srfspec",srfspec,0);
4190 makestr(&srfspec,asname);
4191 debug(F110,"ftp put new srfspec",srfspec,0);
4194 /* Final log entries */
4200 tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4201 else if (rc == SKP_XUP)
4202 tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4203 else if (rc == SKP_SIM)
4204 tlog(F100," /simulate: WOULD BE SENT","",0);
4206 tlog(F110," skipped:",gskreason(rc),0);
4207 } else if (rc == 0) {
4208 tlog(F101," complete, size", "", fsize);
4209 } else if (cancelfile) {
4210 tlog(F100," canceled by user","",0);
4212 tlog(F110," failed:",ftp_reply_str,0);
4215 doxlog(what,local,fsize,ftp_typ,rc,"");
4219 if (rc < 0) /* PUT did not succeed */
4220 return(-1); /* so done. */
4222 if (flg & PUT_SIM) /* Simulating, skip the rest. */
4226 /* Set permissions too? */
4228 if (prm) { /* Change permissions? */
4229 s = zgperm(local); /* Get perms of local file */
4232 if (x > 3) s += (x - 3);
4234 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4236 ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4237 tlog(F110, x ? " chmod" : " chmod failed",
4247 /* Disposition of source file */
4251 tlog(F110, (x > -1) ?
4252 " deleted" : " failed to delete",
4259 x = zrename(local,mvto);
4260 tlog(F110, (x > -1) ?
4261 " moved source to" : " failed to move source to",
4267 /* ftscreen(SCR_ST,ST_MSG,0L,mvto); */
4272 int y; /* Pass it thru the evaluator */
4273 extern int cmd_quoting; /* for \v(filename) */
4274 if (cmd_quoting) { /* But only if cmd_quoting is on */
4277 zzstring(rnto,&s,&y);
4283 x = zrename(local,s);
4284 tlog(F110, (x > -1) ?
4285 " renamed source file to" :
4286 " failed to rename source file to",
4292 /* ftscreen(SCR_ST,ST_MSG,0L,s); */
4296 /* Disposition of destination file */
4298 if (srvrn) { /* /SERVER-RENAME: */
4301 int y; /* Pass it thru the evaluator */
4302 extern int cmd_quoting; /* for \v(filename) */
4303 debug(F111,"ftp putfile srvrn",s,1);
4305 if (cmd_quoting) { /* But only if cmd_quoting is on */
4307 s = (char *)fullname; /* We can recycle this buffer now */
4308 zzstring(srvrn,&s,&y);
4309 s = (char *)fullname;
4312 debug(F111,"ftp putfile srvrn",s,2);
4315 x = ftp_rename(asname,s);
4316 debug(F111,"ftp putfile ftp_rename",asname,x);
4317 tlog(F110, (x > 0) ?
4318 " renamed destination file to" :
4319 " failed to rename destination file to",
4330 /* xxout must only be used for ASCII transfers */
4336 #endif /* CK_ANSIC */
4342 /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4344 if (zzout(dout,(CHAR)'\015') < 0)
4351 if (zzout(dout,(CHAR)'\015') < 0)
4359 if (zzout(dout,(CHAR)'\015') < 0)
4366 if (zzout(dout,(CHAR)c) < 0)
4377 #endif /* CK_ANSIC */
4387 #endif /* CK_ANSIC */
4393 ispathsep(c) int c; {
4394 switch (servertype) {
4398 return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4402 return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4404 return((c == '>') ? 1 : 0);
4406 return((c == '/') ? 1 : 0);
4413 extern int ck_repaint();
4414 #endif /* CK_CURSES */
4419 x = conchk(); /* Any chars waiting at console? */
4420 if (x-- > 0) { /* Yes... */
4421 c = coninc(5); /* Get one */
4423 case 032: /* Ctrl-X or X */
4425 case 'Z': cancelgroup++; /* fall thru on purpose */
4426 case 030: /* Ctrl-Z or Z */
4428 case 'X': cancelfile++; rc++; break;
4432 case 014: /* Ctrl-L or L or Ctrl-W */
4434 ck_repaint(); /* Refresh screen */
4435 #endif /* CK_CURSES */
4438 while (x-- > 0) /* Soak up any rest */
4443 /* zzsend - used by buffered output macros. */
4447 zzsend(int fd, CHAR c)
4449 zzsend(fd,c) int fd; CHAR c;
4450 #endif /* CK_ANSIC */
4454 debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4455 debug(F101,"zzsend nout","",nout);
4456 debug(F111,"zzsend","secure?",ftpissecure());
4458 if (iscanceled()) /* Check for cancellation */
4460 rc = (!ftpissecure()) ?
4461 send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4462 secure_putbuf(fd, ucbuf, nout);
4468 if (rc > -1 && fdispla != XYFD_B) {
4470 ftscreen(SCR_PT,'D',spackets,NULL);
4475 /* c m d l i n p u t -- Command-line PUT */
4478 cmdlinput(stay) int stay; {
4479 int x, rc = 0, done = 0, good = 0, status = 0;
4480 ULONG t0, t1; /* Times for stats */
4485 #endif /* GFTIMER */
4487 if (quiet) { /* -q really means quiet */
4497 what = W_FTP|W_SEND;
4504 t0 = gmstimer(); /* Record starting time */
4506 while (!done && !cancelgroup) { /* Loop for all files */
4509 x = gnfile(); /* Get next file from list(s) */
4510 if (x == 0) /* (see gnfile() comments...) */
4514 case 1: /* File to send */
4515 rc = putfile(FTP_PUT, /* Function (PUT, APPEND) */
4516 filnam, /* Local file to send */
4517 filnam, /* Remote name for file */
4518 forcetype, /* Text/binary mode forced */
4520 NULL, /* No move-to */
4521 NULL, /* No rename-to */
4522 NULL, /* No server-rename */
4523 ftp_cnv, /* Filename conversion */
4524 0, /* Unique-server-names */
4525 -1, /* All file types */
4526 0, /* No permissions */
4527 -1, /* No character sets */
4528 -1, /* No character sets */
4529 0 /* No update or restart */
4536 continue; /* Or break? */
4541 continue; /* Or break? */
4543 case 0: /* No more files, done */
4549 printf("?%s: file not found - \"%s\"\n",
4550 puterror ? "Fatal" : "Warning",
4553 continue; /* or break? */
4555 printf("?Warning access denied - \"%s\"\n", filnam);
4556 continue; /* or break? */
4558 printf("?Too many files match\n");
4563 printf("?No files selected\n");
4567 printf("?getnextfile() - unknown failure\n");
4574 else if (cancelfile && good < 1)
4580 lastxfer = W_FTP|W_SEND;
4583 t1 = gmstimer(); /* End time */
4585 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4586 if (!sec) sec = 0.001;
4589 sec = (t1 - t0) / 1000;
4591 #endif /* GFTIMER */
4592 tfcps = (long) (tfc / sec);
4594 lastxfer = W_FTP|W_SEND;
4597 ftscreen(SCR_TC,0,0L,"");
4600 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4605 /* d o f t p p u t -- Parse and execute PUT, MPUT, and APPEND */
4609 doftpput(int cx, int who) /* who == 1 for ftp, 0 for kermit */
4611 doftpput(cx,who) int cx, who;
4612 #endif /* CK_ANSIC */
4614 struct FDB sf, fl, sw, cm;
4615 int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4616 int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4619 int x_csl, x_csr = -1; /* Local and remote charsets */
4622 char c, * p; /* Workers */
4624 int range[2]; /* Array range */
4625 char ** ap = NULL; /* Array pointer */
4626 int arrayx = -1; /* Array index */
4627 #endif /* PUTARRAY */
4628 ULONG t0 = 0L, t1 = 0L; /* Times for stats */
4633 #endif /* GFTIMER */
4635 struct stringint { /* Temporary array for switch values */
4640 success = 0; /* Assume failure */
4641 forcetype = 0; /* No /TEXT or /BINARY given yet */
4642 out2screen = 0; /* Not outputting file to screen */
4643 putflags = 0; /* PUT options */
4644 x_cnv = ftp_cnv; /* Filename conversion */
4645 x_usn = ftp_usn; /* Unique server names */
4646 x_prm = ftp_prm; /* Permissions */
4647 if (x_prm == SET_AUTO) /* Permissions AUTO */
4651 x_csr = ftp_csr; /* Inherit global server charset */
4656 #endif /* NOCSETS */
4658 makestr(&filefile,NULL); /* No filename list file yet. */
4659 makestr(&srv_renam,NULL); /* Clear /SERVER-RENAME: */
4660 makestr(&snd_rename,NULL); /* PUT /RENAME */
4661 makestr(&snd_move,NULL); /* PUT /MOVE */
4662 putpath[0] = NUL; /* Initialize for syncdir(). */
4663 puterror = ftp_err; /* Inherit global error action. */
4664 what = W_SEND|W_FTP; /* What we're doing (sending w/FTP) */
4665 asnambuf[0] = NUL; /* Clear as-name buffer */
4667 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
4668 ftp_typ = g_ftp_typ;
4669 /* g_ftp_typ = -1; */
4671 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
4672 pv[i].sval = NULL; /* to null pointers */
4673 pv[i].ival = -1; /* and -1 int values */
4675 if (who == 0) { /* Called with unprefixed command */
4677 case XXRSEN: pv[SND_RES].ival = 1; break;
4678 case XXCSEN: pv[SND_CMD].ival = 1; break;
4679 case XXMOVE: pv[SND_DEL].ival = 1; break;
4680 case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
4681 case XXMSE: mput++; break;
4687 cmfdbi(&sw, /* First FDB - command switches */
4689 "Filename, or switch", /* hlpmsg */
4691 "", /* addtl string data */
4692 nputswi, /* addtl numeric data 1: tbl size */
4693 4, /* addtl numeric data 2: 4 = cmswi */
4694 xxstring, /* Processing function */
4695 putswi, /* Keyword table */
4696 &sf /* Pointer to next FDB */
4698 cmfdbi(&fl, /* 3rd FDB - local filespec */
4702 "", /* addtl string data */
4703 0, /* addtl numeric data 1 */
4704 0, /* addtl numeric data 2 */
4709 cmfdbi(&cm, /* 4th FDB - Confirmation */
4713 "", /* addtl string data */
4714 0, /* addtl numeric data 1 */
4715 0, /* addtl numeric data 2 */
4722 cmfdbi(&sf, /* 2nd FDB - file to send */
4726 "", /* addtl string data */
4727 /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
4728 nolinks | x_recurse, /* addtl numeric data 1 */
4729 0, /* dirflg 0 means "not dirs only" */
4736 #endif /* COMMENT */
4739 while (1) { /* Parse zero or more switches */
4740 x = cmfdb(&sw); /* Parse something */
4741 debug(F101,"ftp put cmfdb A","",x);
4742 debug(F101,"ftp put fcode A","",cmresult.fcode);
4743 if (x < 0) /* Error */
4744 goto xputx; /* or reparse needed */
4745 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
4747 c = cmgbrk(); /* Get break character */
4748 getval = (c == ':' || c == '='); /* to see how they ended the switch */
4749 if (getval && !(cmresult.kflags & CM_ARG)) {
4750 printf("?This switch does not take arguments\n");
4754 if (!getval && (cmgkwflgs() & CM_ARG)) {
4755 printf("?This switch requires an argument\n");
4759 n = cmresult.nresult; /* Numeric result = switch value */
4760 debug(F101,"ftp put switch","",n);
4762 switch (n) { /* Process the switch */
4763 case SND_AFT: /* Send /AFTER:date-time */
4764 case SND_BEF: /* Send /BEFORE:date-time */
4765 case SND_NAF: /* Send /NOT-AFTER:date-time */
4766 case SND_NBE: /* Send /NOT-BEFORE:date-time */
4768 if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
4770 printf("?Date-time required\n");
4776 makestr(&(pv[n].sval),s);
4779 case SND_ASN: /* /AS-NAME: */
4780 debug(F101,"ftp put /as-name getval","",getval);
4782 if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
4784 printf("?name required\n");
4789 makestr(&(pv[n].sval),brstrip(s));
4790 debug(F110,"ftp put /as-name 1",pv[n].sval,0);
4791 if (pv[n].sval) pv[n].ival = 1;
4795 case SND_ARR: /* /ARRAY */
4798 if ((x = cmfld("Array name (a single letter will do)",
4808 if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
4809 printf("?Bad array: %s\n",s);
4812 if (!(ap = a_ptr[x])) {
4813 printf("?No such array: %s\n",s);
4817 pv[SND_CMD].ival = 0; /* Undo any conflicting ones... */
4818 pv[SND_RES].ival = 0;
4819 pv[SND_FIL].ival = 0;
4822 #endif /* PUTARRAY */
4824 case SND_BIN: /* /BINARY */
4825 case SND_TXT: /* /TEXT or /ASCII */
4826 case SND_TEN: /* /TENEX */
4827 pv[SND_BIN].ival = 0;
4828 pv[SND_TXT].ival = 0;
4829 pv[SND_TEN].ival = 0;
4834 case SND_CMD: /* These take no args */
4836 printf("?Sorry, system command access is disabled\n");
4841 else if (sndfilter) {
4842 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
4846 #endif /* PIPESEND */
4847 sw.hlpmsg = "Command, or switch"; /* Change help message */
4848 pv[n].ival = 1; /* Just set the flag */
4849 pv[SND_ARR].ival = 0;
4851 #endif /* PUTPIPE */
4856 goto again; /* Because CMIFI params changed... */
4860 #endif /* CKSYMLINK */
4863 case SND_RES: /* /RECOVER (resend) */
4864 pv[SND_ARR].ival = 0; /* fall thru on purpose... */
4865 #endif /* FTP_RESTART */
4868 case SND_DEL: /* /DELETE */
4869 case SND_SHH: /* /QUIET */
4870 case SND_UPD: /* /UPDATE */
4871 case SND_SIM: /* /UPDATE */
4872 case SND_USN: /* /UNIQUE */
4873 pv[n].ival = 1; /* Just set the flag */
4876 case SND_REC: /* /RECURSIVE */
4877 recursive = 2; /* Must be set before cmifi() */
4879 goto again; /* Because CMIFI params changed... */
4883 case SND_DOT: /* /DOTFILES */
4886 case SND_NOD: /* /NODOTFILES */
4889 #endif /* UNIXOROSK */
4891 case SND_ERR: /* /ERROR-ACTION */
4892 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
4897 case SND_EXC: /* Excludes */
4899 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
4901 printf("?Pattern required\n");
4906 if (s) if (!*s) s = NULL;
4907 makestr(&(pv[n].sval),s);
4912 case SND_PRM: /* /PERMISSIONS */
4915 else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
4917 pv[SND_PRM].ival = x;
4921 case SND_FLT: /* /FILTER */
4922 debug(F101,"ftp put /filter getval","",getval);
4924 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
4930 if (*s) s = brstrip(s);
4932 for (x = 0; x < y; x++) { /* Make sure they included "\v(...)" */
4933 if (s[x] != '\\') continue;
4934 if (s[x+1] == 'v') break;
4938 "?Filter must contain a replacement variable for filename.\n"
4943 if (s) if (!*s) s = NULL;
4944 makestr(&(pv[n].sval),s);
4948 #endif /* PIPESEND */
4950 case SND_NAM: /* /FILENAMES */
4952 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
4954 debug(F101,"ftp put /filenames","",x);
4958 case SND_SMA: /* Smaller / larger than */
4961 if ((x = cmnum("Size in bytes","0",10,&y,xxstring)) < 0)
4966 case SND_FIL: /* Name of file containing filenames */
4968 if ((x = cmifi("Name of file containing list of filenames",
4969 "",&s,&y,xxstring)) < 0) {
4971 printf("?Filename required\n");
4975 } else if (y && iswild(s)) {
4976 printf("?Wildcards not allowed\n");
4980 if (s) if (!*s) s = NULL;
4981 makestr(&(pv[n].sval),s);
4984 pv[SND_ARR].ival = 0;
4991 case SND_MOV: /* MOVE after */
4992 case SND_REN: /* RENAME after */
4993 case SND_SRN: { /* SERVER-RENAME after */
4997 m = "device and/or directory for source file after sending";
5000 m = "new name for source file after sending";
5003 m = "new name for destination file after sending";
5007 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5009 printf("%s\n", n == SND_MOV ?
5010 "?Destination required" :
5011 "?New name required"
5017 if (s) if (!*s) s = NULL;
5018 makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5019 pv[n].ival = (pv[n].sval) ? 1 : 0;
5022 case SND_STA: /* Starting position (= PSEND) */
5024 if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5029 case SND_TYP: /* /TYPE */
5031 if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5033 pv[n].ival = (x == 2) ? -1 : x;
5037 case SND_CSL: /* Local character set */
5038 case SND_CSR: /* Remote (server) charset */
5039 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5040 return((x == -3) ? -2 : x);
5046 x_xla = 1; /* Overrides global OFF setting */
5049 case SND_XPA: /* Transparent */
5054 #endif /* NOCSETS */
5058 if (pv[SND_RES].ival > 0) { /* /RECOVER */
5059 if (sndfilter || pv[SND_FLT].ival > 0) {
5060 printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5064 if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5065 printf("WARNING: Server says it doesn't support REST.\n");
5067 #endif /* PIPESEND */
5075 switch (cmresult.fcode) { /* How did we get out of switch loop */
5076 case _CMIFI: /* Input filename */
5077 if (pv[SND_FIL].ival > 0) {
5078 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5082 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5083 if (pv[SND_ARR].ival > 0)
5084 ckstrncpy(asnambuf,line,CKMAXPATH);
5086 wild = cmresult.nresult; /* Wild flag */
5087 debug(F111,"ftp put wild",line,wild);
5088 if (!wild && !recursive && !mput)
5091 case _CMFLD: /* Field */
5092 /* Only allowed with /COMMAND and /ARRAY */
5093 if (pv[SND_FIL].ival > 0) {
5094 printf("?You may not give a PUT filespec and a /LISTFILE\n");
5098 /* For MPUT it's OK to have filespecs that don't match any files */
5101 if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5104 printf("?Off limits: %s\n",cmresult.sresult);
5107 printf("?%s - \"%s\"\n",
5108 iswild(cmresult.sresult) ?
5109 "No files match" : "File not found",
5115 ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5116 if (pv[SND_ARR].ival > 0)
5117 ckstrncpy(asnambuf,line,CKMAXPATH);
5119 case _CMCFM: /* Confirmation */
5123 printf("?Unexpected function code: %d\n",cmresult.fcode);
5127 debug(F110,"ftp put string",s,0);
5128 debug(F101,"ftp put confirmed","",confirmed);
5130 /* Save and change protocol and transfer mode */
5131 /* Global values are restored in main parse loop */
5136 g_skipbup = skipbup;
5138 if (pv[SND_NOB].ival > -1) { /* /NOBACKUP (skip backup file) */
5139 g_skipbup = skipbup;
5142 if (pv[SND_TYP].ival > -1) { /* /TYPE */
5143 xfiletype = pv[SND_TYP].ival;
5147 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
5148 forcetype = 1; /* So skip file scan */
5149 ftp_typ = FTT_BIN; /* Set binary */
5150 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
5153 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
5156 } else if (ftp_cmdlin && xfermode == XMODE_M) {
5163 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
5164 debug(F110,"PUT /COMMAND before stripping",s,0);
5166 debug(F110,"PUT /COMMAND after stripping",s,0);
5168 printf("?Sorry, a command to send from is required\n");
5174 #endif /* PIPESEND */
5176 /* Set up /MOVE and /RENAME */
5178 if (pv[SND_DEL].ival > 0 &&
5179 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5180 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5185 if (pv[SND_MOV].ival > 0) {
5187 char * p = pv[SND_MOV].sval;
5189 if (!isdir(p)) { /* Check directory */
5192 s = (char *)malloc(len + 4);
5194 strcpy(s,p); /* safe */
5196 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5198 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5199 #endif /* datageneral */
5206 #endif /* NOMKDIR */
5209 printf("?Can't create \"%s\"\n",p);
5215 printf("?Directory \"%s\" not found\n",p);
5218 #endif /* CK_MKDIR */
5220 makestr(&snd_move,p);
5222 #endif /* CK_TMPDIR */
5224 if (pv[SND_REN].ival > 0) { /* /RENAME */
5225 char * p = pv[SND_REN].sval;
5228 printf("?New name required for /RENAME\n");
5234 /* If name given is wild, rename string must contain variables */
5239 if (!strcmp(tmpbuf,p)) {
5241 "?/RENAME for file group must contain variables such as \\v(filename)\n"
5248 makestr(&snd_rename,p);
5249 debug(F110,"FTP snd_rename",snd_rename,0);
5251 if (pv[SND_SRN].ival > 0) { /* /SERVER-RENAME */
5252 char * p = pv[SND_SRN].sval;
5255 printf("?New name required for /SERVER-RENAME\n");
5265 if (!strcmp(tmpbuf,p)) {
5267 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5274 makestr(&srv_renam,p);
5275 debug(F110,"ftp put srv_renam",srv_renam,0);
5277 if (!confirmed) { /* CR not typed yet, get more fields */
5279 if (mput) { /* MPUT or MMOVE */
5280 nfils = 0; /* We already have the first one */
5282 if (cmresult.fcode == _CMIFI) {
5283 /* First filespec is valid */
5284 msfiles[nfils++] = line; /* Store pointer */
5285 lp = line + (int)strlen(line) + 1; /* Point past it */
5286 debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5288 /* First filespec matches no files */
5289 debug(F110,"ftp put mput skipping first filespec",
5295 /* Parse a filespec, a "field", or confirmation */
5297 cmfdbi(&sf, /* 1st FDB - file to send */
5301 "", /* addtl string data */
5302 nolinks | x_recurse, /* addtl numeric data 1 */
5303 0, /* dirflg 0 means "not dirs only" */
5308 cmfdbi(&fl, /* 2nd FDB - local filespec */
5312 "", /* addtl string data */
5313 0, /* addtl numeric data 1 */
5314 0, /* addtl numeric data 2 */
5319 cmfdbi(&cm, /* 3rd FDB - Confirmation */
5331 while (!confirmed) { /* Get more filenames */
5332 x = cmfdb(&sf); /* Parse something */
5333 debug(F101,"ftp put cmfdb B","",x);
5334 debug(F101,"ftp put fcode B","",cmresult.fcode);
5335 if (x < 0) /* Error */
5336 goto xputx; /* or reparse needed */
5337 switch (cmresult.fcode) {
5338 case _CMCFM: /* End of command */
5341 debug(F100,"ftp put mput no files match","",0);
5342 printf("?No files match MPUT list\n");
5347 case _CMFLD: /* No match */
5348 debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5350 case _CMIFI: /* Good match */
5351 s = cmresult.sresult;
5352 msfiles[nfils++] = lp; /* Got one, count, point to it, */
5353 p = lp; /* remember pointer, */
5354 while ((*lp++ = *s++)) /* and copy it into buffer */
5355 if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5356 printf("?MPUT list too long\n");
5361 debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5362 if (nfils == 1) /* Take care of \v(filespec) */
5365 zfnqfp(p,TMPBUFSIZ,tmpbuf);
5368 if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5369 strcat(fspec,p); /* safe */
5370 strcat(fspec," "); /* safe */
5373 printf("WARNING - \\v(filespec) buffer overflow\n");
5375 debug(F101,"doxput filespec buffer overflow","",0);
5376 #endif /* COMMENT */
5380 #endif /* NOMSEND */
5381 } else { /* Regular PUT */
5383 if ((x = cmtxt(wild ?
5384 "\nOptional as-name template containing replacement variables \
5385 like \\v(filename)" :
5386 "Optional name to send it with",
5390 if (p) if (!*p) p = NULL;
5394 makestr(&(pv[SND_ASN].sval),p);
5395 if (pv[SND_ASN].sval)
5396 pv[SND_ASN].ival = 1;
5397 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5401 /* Set cmarg2 from as-name, however we got it. */
5404 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5406 p = brstrip(pv[SND_ASN].sval);
5407 ckstrncpy(asnambuf,p,CKMAXPATH+1);
5409 debug(F110,"ftp put asnambuf",asnambuf,0);
5411 if (pv[SND_FIL].ival > 0) {
5413 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5414 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5415 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5419 makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5420 debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5424 if (confirmed && !line[0] && !filefile) {
5426 if (filehead) { /* OK if we have a SEND-LIST */
5427 nfils = filesinlist;
5428 sndsrc = nfils; /* Like MSEND */
5429 addlist = 1; /* But using a different list... */
5430 filenext = filehead;
5433 #endif /* NOMSEND */
5434 printf("?Filename required but not given\n");
5439 addlist = 0; /* Don't use SEND-LIST. */
5440 #endif /* NOMSEND */
5442 if (mput) { /* MPUT (rather than PUT) */
5444 cmlist = msfiles; /* List of filespecs */
5445 sndsrc = nfils; /* rather filespec and as-name */
5446 #endif /* NOMSEND */
5448 } else if (filefile) { /* File contains list of filenames */
5455 } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5457 /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5458 nfils = sndsrc = -1;
5462 printf("?Read access denied - \"%s\"\n", s);
5467 if (s != line) /* We might already have done this. */
5468 ckstrncpy(line,s,LINBUFSIZ); /* Copy of string just parsed. */
5471 debug(F110,"doxput line=s",line,0);
5473 cmarg = line; /* File to send */
5476 zfnqfp(cmarg,fspeclen,fspec); /* Get full name */
5477 #endif /* NOMSEND */
5479 if (!mput) { /* For all but MPUT... */
5481 if (pv[SND_CMD].ival > 0) /* /COMMAND sets pipesend flag */
5483 debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5484 if (pipesend && filefile) {
5485 printf("?Invalid switch combination\n");
5489 #endif /* PIPESEND */
5492 /* If as-name given and filespec is wild, as-name must contain variables */
5493 if ((wild || mput) && asnambuf[0]) {
5496 zzstring(asnambuf,&s,&x);
5497 if (!strcmp(tmpbuf,asnambuf)) {
5499 "?As-name for file group must contain variables such as \\v(filename)\n"
5510 if (pv[SND_SHH].ival > 0) { /* SEND /QUIET... */
5512 debug(F101,"ftp put display","",fdispla);
5519 #ifdef PUTARRAY /* SEND /ARRAY... */
5520 if (pv[SND_ARR].ival > 0) {
5521 if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5522 if (range[0] == -1) /* If low end of range not specified */
5523 range[0] = 1; /* default to 1 */
5524 if (range[1] == -1) /* If high not specified */
5525 range[1] = a_dim[arrayx]; /* default to size of array */
5526 if ((range[0] < 0) || /* Check range */
5527 (range[0] > a_dim[arrayx]) ||
5528 (range[1] < range[0]) ||
5529 (range[1] > a_dim[arrayx])) {
5530 printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5534 sndarray = ap; /* Array pointer */
5535 sndxin = arrayx; /* Array index */
5536 sndxlo = range[0]; /* Array range */
5538 sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5540 ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5543 #endif /* PUTARRAY */
5547 if (pv[SND_ARR].ival < 1) { /* File selection & disposition... */
5548 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
5550 if (pv[SND_AFT].ival > 0) /* Copy SEND criteria */
5551 ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5552 if (pv[SND_BEF].ival > 0)
5553 ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5554 if (pv[SND_NAF].ival > 0)
5555 ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5556 if (pv[SND_NBE].ival > 0)
5557 ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5558 if (pv[SND_EXC].ival > 0)
5559 makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5560 if (pv[SND_SMA].ival > -1)
5561 sndsmaller = pv[SND_SMA].ival;
5562 if (pv[SND_LAR].ival > -1)
5563 sndlarger = pv[SND_LAR].ival;
5564 if (pv[SND_NAM].ival > -1)
5565 x_cnv = pv[SND_NAM].ival;
5566 if (pv[SND_USN].ival > -1)
5567 x_usn = pv[SND_USN].ival;
5568 if (pv[SND_ERR].ival > -1)
5569 puterror = pv[SND_ERR].ival;
5572 if (pv[SND_UPD].ival > 0) {
5574 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5578 putflags |= PUT_UPD;
5582 /* This works but it's useless, maybe dangerous */
5583 if (pv[SND_DIF].ival > 0) {
5585 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5589 putflags |= PUT_DIF;
5592 #endif /* COMMENT */
5593 #endif /* DOUPDATE */
5595 if (pv[SND_SIM].ival > 0)
5596 putflags |= PUT_SIM;
5598 if (pv[SND_PRM].ival > -1) {
5601 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5605 x_prm = pv[SND_PRM].ival;
5607 printf("?/PERMISSIONS switch is not supported\n");
5611 if (pv[SND_RES].ival > 0) {
5613 printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5617 if (x_usn || putflags) {
5618 printf("?Conflicting switches: /RECOVER %s\n",
5619 x_usn && putflags ? "/UNIQUE /UPDATE" :
5620 (x_usn ? "/UNIQUE" : "/UPDATE")
5627 (x_csl == FC_UCS2 ||
5630 x_csr == FC_UTF8)) {
5631 printf("?/RECOVER can not be used with Unicode translation\n");
5635 #endif /* NOCSETS */
5638 #endif /* FTP_RESTART */
5640 debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5641 debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5644 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
5645 if (!pv[SND_FLT].sval) {
5648 sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5649 if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5651 debug(F110,"ftp put /FILTER", sndfilter, 0);
5653 if (sndfilter || pipesend) /* No /UPDATE or /RESTART */
5654 if (putflags) /* with pipes or filters */
5656 #endif /* PIPESEND */
5658 tfc = 0L; /* Initialize stats and counters */
5663 if (wild) /* (is this necessary?) */
5666 t0 = gmstimer(); /* Record starting time */
5668 done = 0; /* Loop control */
5673 while (!done && !cancelgroup) { /* Loop for all files */
5674 /* or until canceled. */
5677 If we are using a proxy, we don't use the local file list;
5678 instead we use the list on the remote machine which we want
5679 sent to someone else, and we use remglob() to get the names.
5680 But in that case we shouldn't even be executing this routine;
5683 #endif /* FTP_PROXY */
5686 x = gnfile(); /* Get next file from list(s) */
5688 if (x == 0) /* (see gnfile() comments...) */
5690 debug(F111,"FTP PUT gnfile",filnam,x);
5693 case 1: /* File to send */
5696 if (asnambuf[0]) { /* As-name */
5697 int n; char *p; /* to be evaluated... */
5700 zzstring(asnambuf,&p,&n);
5702 debug(F110,"ftp put asname",s2,0);
5705 rc = putfile(cx, /* Function (PUT, APPEND) */
5706 filnam, s2, /* Name to send, as-name */
5707 forcetype, moving, /* Parameters from switches... */
5708 snd_move, snd_rename, srv_renam,
5709 x_cnv, x_usn, xfiletype, x_prm,
5711 x_csl, (!x_xla ? -1 : x_csr),
5714 #endif /* NOCSETS */
5717 debug(F111,"ftp put putfile rc",filnam,rc);
5718 debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
5719 debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
5730 printf("?Fatal upload error: %s\n",filnam);
5735 case 0: /* No more files, done */
5739 printf("?%s: file not found - \"%s\"\n",
5740 puterror ? "Fatal" : "Warning",
5751 printf("?Fatal: file not found - \"%s\"\n", filnam);
5756 continue; /* Not readable, keep going */
5759 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
5764 printf("?Warning access denied - \"%s\"\n", filnam);
5767 case -4: /* Canceled */
5770 #endif /* COMMENT */
5772 printf("?Too many files match\n");
5777 printf("?No files selected\n");
5781 printf("?getnextfile() - unknown failure\n");
5789 } else if (!doftpcdup())
5796 else if (cancelfile && good < 1)
5805 t1 = gmstimer(); /* End time */
5806 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
5807 if (!sec) sec = 0.001;
5810 sec = (t1 - t0) / 1000;
5812 #endif /* GFTIMER */
5813 tfcps = (long) (tfc / sec);
5815 lastxfer = W_FTP|W_SEND;
5818 ftscreen(SCR_TC,0,0L,"");
5820 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
5824 ftreset(); /* Undo switch effects */
5830 static char ** mgetlist = NULL; /* For MGET */
5831 static int mgetn = 0, mgetx = 0;
5832 static char xtmpbuf[4096];
5837 Get files specified by -g command-line option.
5838 File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
5841 cmdlinget(stay) int stay; {
5842 int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
5843 int lcs = -1, rcs = -1, xlate = 0;
5847 char * s, * s2, * s3;
5848 ULONG t0, t1; /* Times for stats */
5853 #endif /* GFTIMER */
5855 if (quiet) { /* -q really means quiet */
5865 what = W_FTP|W_RECV;
5871 makestr(&havemdtm,NULL);
5879 debug(F101,"ftp cmdlinget nfils","",nfils);
5881 if (ftp_cnv == CNV_AUTO) { /* Name conversion is auto */
5882 if (alike) { /* If server & client are alike */
5883 nc = 0; /* no conversion */
5884 } else { /* If they are different */
5885 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
5886 nc = -1; /* only minimal conversions needed */
5887 else /* otherwise */
5888 nc = 1; /* full conversion */
5890 } else /* Not auto - do what user said */
5894 doexit(BAD_EXIT,-1);
5896 t0 = gmstimer(); /* Starting time for this batch */
5899 if (xlate) { /* SET FTP CHARACTER-SET-TRANSLATION */
5900 lcs = ftp_csl; /* Local charset */
5901 if (lcs < 0) lcs = fcharset;
5902 if (lcs < 0) xlate = 0;
5904 if (xlate) { /* Still ON? */
5905 rcs = ftp_csx; /* Remote (Server) charset */
5906 if (rcs < 0) rcs = ftp_csr;
5907 if (rcs < 0) xlate = 0;
5909 #endif /* NOCSETS */
5911 If we have only one file and it is a directory, then we ask for a
5912 listing of its contents, rather than retrieving the directory file
5913 itself. This is what (e.g.) Netscape does.
5916 if (doftpcwd((char *)cmlist[mgetx],-1)) {
5917 /* If we can CD to it, it must be a directory */
5919 cmlist[mgetx] = "*";
5922 (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
5928 The following is to work around UNIX servers which, when given a command
5929 like "NLST path/blah" (not wild) returns the basename without the path.
5931 if (!done && servertype == SYS_UNIX && nfils == 1) {
5932 mget = iswild(cmlist[mgetx]);
5934 if (!mget && !done) { /* Invoked by command-line FTP URL */
5936 printf("DOING GET...\n");
5938 cancelfile = 0; /* This file not canceled yet */
5940 rc = 0; /* Initial return code */
5943 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
5944 if (x == REPLY_COMPLETE)
5945 fsize = atol(&ftp_reply_str[4]);
5947 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
5948 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
5950 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
5953 /* If local file already exists, take collision action */
5958 case XYFX_A: /* Append */
5961 case XYFX_R: /* Rename */
5962 case XYFX_B: { /* Backup */
5965 znewn(s2,&p); /* Make unique name */
5966 debug(F110,"ftp cmdlinget znewn",p,0);
5967 if (ftp_fnc == XYFX_B) { /* Backup existing file */
5969 debug(F111,"ftp cmdlinget backup zrename",p,x);
5970 } else { /* Rename incoming file */
5971 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
5973 debug(F111,"ftp cmdlinget rename incoming",p,x);
5976 printf("?Backup/Rename failed\n");
5977 return(success = 0);
5981 case XYFX_D: /* Discard */
5982 ftscreen(SCR_FN,'F',0L,s);
5983 ftscreen(SCR_ST,ST_SKIP,SKP_NAM,s);
5984 tlog(F100," refused: name","",0);
5985 debug(F110,"ftp cmdlinget skip name",s2,0);
5988 case XYFX_X: /* Overwrite */
5989 case XYFX_U: /* Update (already handled above) */
5990 case XYFX_M: /* ditto */
5994 rc = getfile(s, /* Remote name */
5995 s2, /* Local name */
5996 0, /* Recover/Restart */
5997 append, /* Append */
5998 NULL, /* Pipename */
5999 0, /* Translate charsets */
6000 -1, /* File charset (none) */
6001 -1 /* Server charset (none) */
6003 debug(F111,"ftp cmdlinget rc",s,rc);
6004 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6005 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6007 if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6008 rc = getfile(&s[1], /* Remote name without leading '/' */
6009 s2, /* Local name */
6010 0, /* Recover/Restart */
6011 append, /* Append */
6012 NULL, /* Pipename */
6013 0, /* Translate charsets */
6014 -1, /* File charset (none) */
6015 -1 /* Server charset (none) */
6031 if (ftp_deb && !done)
6032 printf("DOING MGET...\n");
6033 while (!done && !cancelgroup) {
6034 cancelfile = 0; /* This file not canceled yet */
6035 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6041 s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6044 debug(F111,"ftp cmdlinget remote_files B",s,0);
6051 The semantics of NLST are ill-defined. Suppose we have just sent
6052 NLST /path/[a-z]*. Most servers send back names like /path/foo,
6053 /path/bar, etc. But some send back only foo and bar, and subsequent
6054 RETR commands based on the pathless names are not going to work.
6056 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6057 if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6058 int len, left = 4096;
6059 char * tmp = xtmpbuf;
6060 len = s3 - cmlist[mgetx] + 1;
6061 ckstrncpy(tmp,cmlist[mgetx],left);
6064 ckstrncpy(tmp,s,left);
6066 debug(F111,"ftp cmdlinget remote_files X",s,0);
6069 first = 0; /* Not first any more */
6071 debug(F111,"ftp cmdlinget havetype",s,havetype);
6072 if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6073 debug(F110,"ftp cmdlinget not-a-file",s,0);
6076 rc = 0; /* Initial return code */
6077 if (havesize > -1L) { /* Already have file size? */
6079 } else { /* No - must ask server */
6081 Prior to sending the NLST command we necessarily put the
6082 server into ASCII mode. We must now put it back into the
6083 the requested mode so the upcoming SIZE command returns
6084 right kind of size; this is especially important for
6085 GET /RECOVER; otherwise the server returns the "ASCII" size
6086 of the file, rather than its true size.
6088 changetype(ftp_typ,0); /* Change to requested type */
6091 x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6092 if (x == REPLY_COMPLETE)
6093 fsize = atol(&ftp_reply_str[4]);
6096 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
6097 debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6099 nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6102 /* If local file already exists, take collision action */
6107 case XYFX_A: /* Append */
6110 case XYFX_R: /* Rename */
6111 case XYFX_B: { /* Backup */
6114 znewn(s2,&p); /* Make unique name */
6115 debug(F110,"ftp cmdlinget znewn",p,0);
6116 if (ftp_fnc == XYFX_B) { /* Backup existing file */
6118 debug(F111,"ftp cmdlinget backup zrename",p,x);
6119 } else { /* Rename incoming file */
6120 x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6122 debug(F111,"ftp cmdlinget rename incoming",p,x);
6125 printf("?Backup/Rename failed\n");
6126 return(success = 0);
6130 case XYFX_D: /* Discard */
6131 ftscreen(SCR_FN,'F',0L,s);
6132 ftscreen(SCR_ST,ST_SKIP,SKP_NAM,s);
6133 tlog(F100," refused: name","",0);
6134 debug(F110,"ftp cmdlinget skip name",s2,0);
6136 case XYFX_X: /* Overwrite */
6137 case XYFX_U: /* Update (already handled above) */
6138 case XYFX_M: /* ditto */
6142 /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6143 rc = getfile(s, /* Remote name */
6144 s2, /* Local name */
6145 0, /* Recover/Restart */
6146 append, /* Append */
6147 NULL, /* Pipename */
6148 0, /* Translate charsets */
6149 -1, /* File charset (none) */
6150 -1 /* Server charset (none) */
6152 debug(F111,"ftp cmdlinget rc",s,rc);
6153 debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6154 debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6177 else if (cancelfile && good < 1)
6183 t1 = gmstimer(); /* End time */
6184 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6185 if (!sec) sec = 0.001;
6188 sec = (t1 - t0) / 1000;
6190 #endif /* GFTIMER */
6192 tfcps = (long) (tfc / sec);
6194 lastxfer = W_FTP|W_RECV;
6197 ftscreen(SCR_TC,0,0L,"");
6199 doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6203 /* d o f t p g e t -- Parse and execute GET, MGET, MDELETE, ... */
6206 Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6207 zstrdat() to convert to UTC-based time_t. But it doesn't make sense from
6208 the user-interface perspective, since the server's directory listings show
6209 its own local times and since we don't know what timezone it's in, there's
6210 no way to reconcile our local times with the server's.
6213 doftpget(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
6214 struct FDB fl, sw, cm;
6215 int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6216 int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6217 int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6218 int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6219 int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6222 long getlarger = -1, getsmaller = -1;
6223 char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6224 char * src = "", * local = "";
6227 int x_csl = -1, x_csr = -1; /* Local and remote charsets */
6229 char c; /* Worker char */
6230 ULONG t0 = 0L, t1; /* Times for stats */
6235 #endif /* GFTIMER */
6237 struct stringint { /* Temporary array for switch values */
6242 success = 0; /* Assume failure */
6243 forcetype = 0; /* No /TEXT or /BINARY given yet */
6244 restart = 0; /* No restart yet */
6245 out2screen = 0; /* No TO-SCREEN switch given yet */
6246 mgetmethod = 0; /* No NLST or MLSD switch yet */
6253 x_cnv = ftp_cnv; /* Filename conversion */
6254 if (x_cnv == CNV_AUTO) { /* Name conversion is auto */
6255 if (alike) { /* If server & client are alike */
6256 x_cnv = 0; /* no conversion */
6257 } else { /* If they are different */
6258 if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6259 x_cnv = -1; /* only minimal conversions needed */
6260 else /* otherwise */
6261 x_cnv = 1; /* full conversion */
6263 } else /* Not auto - do what user said */
6266 x_prm = ftp_prm; /* Permissions */
6267 if (x_prm == SET_AUTO) /* Permissions AUTO */
6271 x_csr = ftp_csr; /* Inherit global server charset */
6272 x_csl = ftp_csl; /* Inherit global local charset */
6273 if (x_csl < 0) /* If none, use current */
6274 x_csl = fcharset; /* file character-set. */
6275 x_xla = ftp_xla; /* Translation On/Off */
6276 #endif /* NOCSETS */
6278 geterror = ftp_err; /* Inherit global error action. */
6279 asnambuf[0] = NUL; /* No as-name yet. */
6280 pipesave = pipesend;
6285 makestr(&havemdtm,NULL);
6287 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
6288 ftp_typ = g_ftp_typ;
6289 /* g_ftp_typ = -1; */
6291 for (i = 0; i <= SND_MAX; i++) { /* Initialize switch values */
6292 pv[i].sval = NULL; /* to null pointers */
6293 pv[i].ival = -1; /* and -1 int values */
6295 zclose(ZMFILE); /* In case it was left open */
6297 x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6299 if (fp_nml) { /* Reset /NAMELIST */
6300 if (fp_nml != stdout)
6304 makestr(&ftp_nml,NULL);
6306 /* Initialize list of remote filespecs */
6309 mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6311 printf("?Memory allocation failure - MGET list\n");
6314 for (i = 0; i < MGETMAX; i++)
6317 mgetn = 0; /* Number of mget arguments */
6318 mgetx = 0; /* Current arg */
6320 if (who == 0) { /* Called with unprefixed command */
6321 if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6324 case XXREGET: pv[SND_RES].ival = 1; break;
6325 case XXRETR: pv[SND_DEL].ival = 1; break;
6327 case XXMGET: mget++; break;
6329 } else { /* FTP command */
6330 if (cx == FTP_GET || cx == FTP_RGE)
6333 case FTP_DEL: /* (fall thru on purpose) */
6334 case FTP_MDE: mdel++; /* (ditto) */
6335 case FTP_GET: /* (ditto) */
6336 case FTP_MGE: mget++; break;
6337 case FTP_RGE: pv[SND_RES].ival = 1; break;
6340 cmfdbi(&sw, /* First FDB - command switches */
6342 "Remote filename;\n or switch", /* hlpmsg */
6344 "", /* addtl string data */
6345 mdel ? ndelswi : ngetswi, /* addtl numeric data 1: tbl size */
6346 4, /* addtl numeric data 2: 4 = cmswi */
6347 xxstring, /* Processing function */
6348 mdel ? delswi : getswi, /* Keyword table */
6349 &fl /* Pointer to next FDB */
6351 cmfdbi(&fl, /* 2nd FDB - remote filename */
6355 "", /* addtl string data */
6356 0, /* addtl numeric data 1 */
6357 0, /* addtl numeric data 2 */
6362 cmfdbi(&cm, /* 3rd FDB - Confirmation */
6366 "", /* addtl string data */
6367 0, /* addtl numeric data 1 */
6368 0, /* addtl numeric data 2 */
6374 while (1) { /* Parse 0 or more switches */
6375 x = cmfdb(&sw); /* Parse something */
6376 debug(F101,"ftp get cmfdb","",x);
6377 if (x < 0) /* Error */
6378 goto xgetx; /* or reparse needed */
6379 if (cmresult.fcode != _CMKEY) /* Break out of loop if not a switch */
6381 c = cmgbrk(); /* Get break character */
6382 getval = (c == ':' || c == '='); /* to see how they ended the switch */
6383 if (getval && !(cmresult.kflags & CM_ARG)) {
6384 printf("?This switch does not take arguments\n");
6388 n = cmresult.nresult; /* Numeric result = switch value */
6389 debug(F101,"ftp get switch","",n);
6391 if (!getval && (cmgkwflgs() & CM_ARG)) {
6392 printf("?This switch requires an argument\n");
6396 switch (n) { /* Process the switch */
6397 case SND_ASN: /* /AS-NAME: */
6398 debug(F101,"ftp get /as-name getval","",getval);
6400 if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6402 printf("?name required\n");
6409 makestr(&(pv[n].sval),s);
6413 case SND_BIN: /* /BINARY */
6414 case SND_TXT: /* /TEXT or /ASCII */
6415 case SND_TEN: /* /TENEX */
6416 pv[SND_BIN].ival = 0;
6417 pv[SND_TXT].ival = 0;
6418 pv[SND_TEN].ival = 0;
6423 case SND_CMD: /* These take no args */
6425 printf("?Sorry, system command access is disabled\n");
6430 else if (rcvfilter) {
6431 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6435 #endif /* PIPESEND */
6436 sw.hlpmsg = "Command, or switch"; /* Change help message */
6437 pv[n].ival = 1; /* Just set the flag */
6438 pv[SND_ARR].ival = 0;
6440 #endif /* PUTPIPE */
6442 case SND_SHH: /* /QUIET */
6443 case SND_RES: /* /RECOVER (reget) */
6444 case SND_NOB: /* /NOBACKUPFILES */
6445 case SND_DEL: /* /DELETE */
6446 case SND_UPD: /* /UPDATE */
6447 case SND_USN: /* /UNIQUE */
6448 case SND_NOD: /* /NODOTFILES */
6449 case SND_REC: /* /RECOVER */
6450 case SND_MAI: /* /TO-SCREEN */
6451 pv[n].ival = 1; /* Just set the flag */
6454 case SND_DIF: /* /DATES-DIFFER */
6455 pv[SND_COL].ival = XYFX_M; /* Now it's a collision option */
6459 case SND_COL: /* /COLLISION: */
6460 if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6463 pv[SND_DIF].ival = 1; /* (phase this out) */
6464 pv[n].ival = x; /* this should be sufficient */
6467 case SND_ERR: /* /ERROR-ACTION */
6468 if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6473 case SND_EXC: /* Exception list */
6475 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6477 printf("?Pattern required\n");
6482 if (s) if (!*s) s = NULL;
6483 makestr(&(pv[n].sval),s);
6490 debug(F101,"ftp get /filter getval","",getval);
6492 if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6499 if (pv[SND_MAI].ival < 1) {
6501 /* Make sure they included "\v(...)" */
6502 for (x = 0; x < y; x++) {
6503 if (s[x] != '\\') continue;
6504 if (s[x+1] == 'v') break;
6508 "?Filter must contain a replacement variable for filename.\n"
6516 makestr(&(pv[n].sval),s);
6519 makestr(&(pv[n].sval),NULL);
6522 #endif /* PIPESEND */
6526 if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6528 debug(F101,"ftp get /filenames","",x);
6532 case SND_SMA: /* Smaller / larger than */
6535 if ((x = cmnum("Size in bytes","0",10,&y,xxstring)) < 0)
6540 case SND_FIL: /* Name of file containing filnames */
6542 if ((x = cmifi("Name of file containing list of filenames",
6543 "",&s,&y,xxstring)) < 0) {
6545 printf("?Filename required\n");
6549 } else if (y && iswild(s)) {
6550 printf("?Wildcards not allowed BBB\n");
6554 if (s) if (!*s) s = NULL;
6555 makestr(&(pv[n].sval),s);
6560 case SND_MOV: /* MOVE after */
6561 case SND_REN: /* RENAME after */
6562 case SND_SRN: { /* SERVER-RENAME */
6567 "Device and/or directory for incoming file after reception";
6570 m = "New name for incoming file after reception";
6573 m = "New name for source file on server after reception";
6577 if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6579 printf("%s\n", n == SND_MOV ?
6580 "?Destination required" :
6581 "?New name required"
6587 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6588 pv[n].ival = (pv[n].sval) ? 1 : 0;
6592 case SND_CSL: /* Local character set */
6593 case SND_CSR: /* Remote (server) charset */
6594 if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6595 return((x == -3) ? -2 : x);
6600 x_xla = 1; /* Overrides global OFF setting */
6603 case SND_XPA: /* Transparent */
6608 #endif /* NOCSETS */
6611 if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6613 makestr(&ftp_nml,s);
6616 case SND_PAT: /* /PATTERN: */
6618 if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6620 makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6621 pv[n].ival = (pv[n].sval) ? 1 : 0;
6624 case SND_NLS: /* /NLST */
6625 pv[n].ival = 1; /* Use NLST */
6626 pv[SND_MLS].ival = 0; /* Don't use MLSD */
6629 case SND_MLS: /* /MLSD */
6630 pv[n].ival = 1; /* Use MLSD */
6631 pv[SND_NLS].ival = 0; /* Don't use NLST */
6634 default: /* /AFTER, /PERMISSIONS, etc... */
6635 printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6645 For GET, we want to parse an optional as-name, like with PUT.
6646 For MGET, we must parse a list of names, and then send NLST or MLSD
6647 commands for each name separately.
6649 switch (cmresult.fcode) { /* How did we get out of switch loop */
6650 case _CMFLD: /* Field */
6652 s = brstrip(cmresult.sresult);
6653 makestr(&(mgetlist[mgetn++]),s);
6654 while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6657 makestr(&(mgetlist[mgetn++]),brstrip(s));
6658 if (mgetn >= MGETMAX) {
6659 printf("?Too many items in MGET list\n");
6663 if ((x = cmcfm()) < 0)
6666 s = brstrip(cmresult.sresult);
6667 ckstrncpy(line,s,LINBUFSIZ);
6668 if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
6672 ckstrncpy(asnambuf,s,CKMAXPATH+1);
6673 if ((x = cmcfm()) < 0)
6677 case _CMCFM: /* Confirmation */
6680 printf("?Unexpected function code: %d\n",cmresult.fcode);
6684 if (pv[SND_REC].ival > 0) /* /RECURSIVE */
6687 if (pv[SND_BIN].ival > 0) { /* /BINARY really means binary... */
6688 forcetype = 1; /* So skip the name-pattern match */
6689 ftp_typ = XYFT_B; /* Set binary */
6690 } else if (pv[SND_TXT].ival > 0) { /* Similarly for /TEXT... */
6693 } else if (pv[SND_TEN].ival > 0) { /* and /TENEX*/
6696 } else if (ftp_cmdlin && xfermode == XMODE_M) {
6701 if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
6703 p = brstrip(pv[SND_ASN].sval); /* As-name */
6704 ckstrncpy(asnambuf,p,CKMAXPATH+1);
6706 debug(F110,"ftp get asnambuf",asnambuf,0);
6709 if (pv[SND_CMD].ival > 0) { /* /COMMAND - strip any braces */
6712 debug(F110,"GET /COMMAND before stripping",p,0);
6714 debug(F110,"GET /COMMAND after stripping",p,0);
6716 printf("?Sorry, a command to write to is required\n");
6723 #endif /* PIPESEND */
6725 /* Set up /MOVE and /RENAME */
6727 if (pv[SND_DEL].ival > 0 &&
6728 (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
6729 printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
6734 if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
6736 char * p = pv[SND_MOV].sval;
6738 if (!isdir(p)) { /* Check directory */
6741 s = (char *)malloc(len + 4);
6743 strcpy(s,p); /* safe */
6745 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
6747 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
6748 #endif /* datageneral */
6755 #endif /* NOMKDIR */
6758 printf("?Can't create \"%s\"\n",p);
6764 printf("?Directory \"%s\" not found\n",p);
6767 #endif /* CK_MKDIR */
6769 makestr(&rcv_move,p);
6772 #endif /* CK_TMPDIR */
6774 if (pv[SND_REN].ival > 0) { /* /RENAME */
6775 char * p = pv[SND_REN].sval;
6778 printf("?New name required for /RENAME\n");
6784 /* If name given is wild, rename string must contain variables */
6785 if (mget && !getone) {
6789 if (!strcmp(tmpbuf,p)) {
6791 "?/RENAME for file group must contain variables such as \\v(filename)\n"
6799 makestr(&rcv_rename,p);
6800 debug(F110,"FTP rcv_rename",rcv_rename,0);
6802 if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
6803 printf("?Filename required but not given\n");
6806 } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
6807 printf("?You can't give both /LISTFILE and a remote filename\n");
6811 CHECKCONN(); /* Check connection */
6813 if (pv[SND_COL].ival > -1)
6814 x_fnc = pv[SND_COL].ival;
6817 /* If as-name given for MGET, as-name must contain variables */
6818 if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
6821 zzstring(asnambuf,&s,&x);
6822 if (!strcmp(tmpbuf,asnambuf)) {
6824 "?As-name for MGET must contain variables such as \\v(filename)\n"
6834 if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
6838 if (mdel || ftp_deb)
6842 if (pv[SND_DEL].ival > 0) /* /DELETE was specified */
6844 if (pv[SND_EXC].ival > 0)
6845 makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
6846 if (pv[SND_SMA].ival > -1)
6847 getsmaller = pv[SND_SMA].ival;
6848 if (pv[SND_LAR].ival > -1)
6849 getlarger = pv[SND_LAR].ival;
6850 if (pv[SND_NAM].ival > -1)
6851 x_cnv = pv[SND_NAM].ival;
6852 if (pv[SND_ERR].ival > -1)
6853 geterror = pv[SND_ERR].ival;
6854 if (pv[SND_MAI].ival > -1)
6857 if (pv[SND_NLS].ival > 0) { /* Force NLST or MLSD? */
6858 mgetmethod = SND_NLS;
6860 } else if (pv[SND_MLS].ival > 0) {
6861 mgetmethod = SND_MLS;
6866 if (pv[SND_RES].ival > 0) {
6868 printf("?Sorry, GET /RECOVER requires binary mode\n");
6872 /* Not true - the fact that the initial REST fails does not mean */
6873 /* it will fail here. */
6874 } else if (!okrestart) {
6875 printf("WARNING: Server might not support restart...\n");
6876 #endif /* COMMENT */
6880 #endif /* FTP_RESTART */
6883 if (pv[SND_FLT].ival > 0) { /* Have SEND FILTER? */
6885 printf("?Switch conflict: /FILTER and /COMMAND\n");
6889 makestr(&rcvfilter,pv[SND_FLT].sval);
6890 debug(F110,"ftp get /FILTER", rcvfilter, 0);
6892 if (rcvfilter || pipesend) { /* /RESTART */
6894 if (restart) { /* with pipes or filters */
6895 printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
6899 #endif /* FTP_RESTART */
6900 if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
6902 "?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
6907 #endif /* PIPESEND */
6909 tfc = 0L; /* Initialize stats and counters */
6914 if (pv[SND_FIL].ival > 0) {
6915 if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
6916 debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
6917 printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
6921 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
6922 zclose(ZMFILE); /* Failed */
6923 debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
6924 printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
6929 debug(F110,"ftp get listfile first",tmpbuf,0);
6930 makestr(&(mgetlist[0]),tmpbuf);
6932 t0 = gmstimer(); /* Record starting time */
6934 updating = 0; /* Checking dates? */
6935 if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
6937 if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
6939 if (updating) /* These switches force FTP DATES ON */
6942 what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
6944 cancelgroup = 0; /* Group not canceled yet */
6945 if (!(xfermode == XMODE_A && patterns && get_auto && !forcetype))
6946 changetype(ftp_typ,0); /* Change to requested type */
6947 binary = ftp_typ; /* For file-transfer display */
6948 first = 1; /* For MGET list */
6949 done = 0; /* Loop control */
6952 if (dldir && !f_tmpdir) { /* If they have a download directory */
6953 if ((s = zgtdir())) { /* Get current directory */
6954 if (zchdir(dldir)) { /* Change to download directory */
6955 ckstrncpy(savdir,s,TMPDIRLEN);
6956 f_tmpdir = 1; /* Remember that we did this */
6960 #endif /* CK_TMPDIR */
6962 if (ftp_nml) { /* /NAMELIST */
6963 debug(F110,"ftp GET ftp_nml",ftp_nml,0);
6964 if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
6967 fp_nml = fopen(ftp_nml, "wb");
6969 printf("?%s: %s\n",ftp_nml,ck_errstr());
6973 while (!done && !cancelgroup) { /* Loop for all files */
6974 /* or until canceled. */
6976 /* do something here if proxy */
6977 #endif /* FTP_PROXY */
6979 rs_len = 0L; /* REGET position */
6980 cancelfile = 0; /* This file not canceled yet */
6981 haspath = 0; /* Recalculate this each time thru */
6983 if (getone) { /* GET */
6986 src = line; /* Server name */
6988 debug(F111,"ftp get file",s,0);
6989 } else if (mget) { /* MGET */
6990 src = mgetlist[mgetx];
6991 debug(F111,"ftp mget remote_files A",src,first);
6992 s = (char *)remote_files(first,
6993 (CHAR *)mgetlist[mgetx],
6994 (CHAR *)pv[SND_PAT].sval,
6997 debug(F110,"ftp mget remote_files B",s,0);
7001 if (listfile) { /* Names from listfile */
7004 while (!tmpbuf[0]) {
7005 if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7007 debug(F110,"ftp get listfile EOF",
7008 pv[SND_FIL].sval,0);
7009 makestr(&(mgetlist[0]),NULL);
7018 makestr(&(mgetlist[0]),tmpbuf);
7019 debug(F110,"ftp get listfile next",tmpbuf,0);
7020 s = (char *)remote_files(first,
7021 (CHAR *)mgetlist[0],
7022 (CHAR *)pv[SND_PAT].sval,
7025 debug(F110,"ftp mget remote_files C",s,0);
7027 ftscreen(SCR_FN,'F',0L,s);
7028 ftscreen(SCR_ST,ST_MSG,0L,"File not found");
7029 tlog(F110,"ftp get file not found:",s,0);
7032 } else { /* Names from command line */
7035 s = (char *)remote_files(first,
7036 (CHAR *)mgetlist[mgetx],
7037 (CHAR *)pv[SND_PAT].sval,
7043 debug(F111,"ftp mget remote_files D",s,mgetx);
7046 if (!first || mgetx >= mgetn) {
7049 } else if (geterror) {
7059 debug(F111,"ftp mget remote_files E",s,0);
7061 The semantics of NLST are ill-defined. Suppose we have just sent
7062 NLST /path/[a-z]*. Most servers send back names like /path/foo,
7063 /path/bar, etc. But some send back only foo and bar, and subsequent
7064 RETR commands based on the pathless names are not going to work.
7066 if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7068 if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7069 int len, left = 4096;
7070 char * tmp = xtmpbuf;
7071 len = s3 - mgetlist[mgetx] + 1;
7072 ckstrncpy(tmp,mgetlist[mgetx],left);
7075 ckstrncpy(tmp,s,left);
7077 debug(F111,"ftp mget remote_files F",s,0);
7081 skipthis = 0; /* File selection... */
7083 nam = s; /* Filename (without path) */
7084 rc = 0; /* Initial return code */
7087 if (!getone && !skipthis) { /* For MGET and MDELETE... */
7093 debug(F111,"ftp mget havetype",s,havetype);
7094 if (havetype > 0 && havetype != FTYP_FILE) {
7095 /* Server says it's not file... */
7096 debug(F110,"ftp mget not-a-file",s,0);
7100 Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7101 But if the client did not ask for a recursive list, we have to ignore any
7102 server files that include a pathname that extends beyond any path that
7103 was included in the user's request.
7105 User's filespec is blah or path/blah (or other non-UNIX syntax). We need to
7106 get the user's path segment. Then, for each incoming file, if it begins
7107 with the same path segment, we must strip it (point past it).
7109 src = mgetlist[mgetx]; /* In case it moved! */
7111 for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7112 if (ispathsep(src[i])) /* in user's pathname */
7118 usrpath = k; /* User path segment length */
7119 debug(F111,"ftp get usrpath",src,usrpath);
7121 p = s; /* Server filename */
7122 while ((c = *p++)) { /* Look for path in server filename */
7125 nam = p; /* Pathless name (for ckmatch) */
7126 srvpath = p - s; /* Server path segment length */
7129 debug(F111,"ftp get srvpath",s,srvpath);
7133 Here we handle the case where the user said "mget foo" where foo is a
7134 directory name, and the server is sending back names like "foo/file1",
7135 "foo/file2", etc. This is a nasty trick but it's necessary because the
7136 user can't compensate by typing "mget foo/" because then the server is
7137 likely to send back "foo//file1, foo//file2" etc, and we still won't
7140 int srclen = 0, srvlen = 0;
7141 if (src) srclen = strlen(src);
7142 if (s) srvlen = strlen(s);
7143 if (src && (srvlen > srclen)) {
7144 if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7145 char * tmpsrc = NULL;
7146 tmpsrc = (char *)malloc(srclen + 2);
7147 strncpy(tmpsrc,src,srclen);
7148 tmpsrc[srclen] = s[srclen];
7149 tmpsrc[srclen+1] = NUL;
7150 free(mgetlist[mgetx]);
7151 mgetlist[mgetx] = tmpsrc;
7153 src = mgetlist[mgetx];
7159 If as-name not given and server filename includes path that matches
7160 the pathname from the user's file specification, we must trim the common
7161 path prefix from the server's name when constructing the local name.
7163 if (src && /* Wed Sep 25 17:27:48 2002 */
7165 !recursive && /* Thu Sep 19 16:11:59 2002 */
7167 !strncmp(src,s,usrpath)) {
7168 s2 = s + usrpath; /* Local name skips past remote path */
7171 /* This doesn't work if the path prefix contains wildcards! */
7172 haspath = (srvpath > usrpath);
7174 { /* Count path segments instead */
7177 for (p = s; *p; p++)
7178 if (ispathsep(*p)) x1++;
7179 for (p = src; *p; p++) {
7180 if (ispathsep(*p)) x2++;
7182 haspath = recursive ? x1 || x2 : x1 > x2;
7183 debug(F111,"ftp get server path segments",s,x1);
7184 debug(F111,"ftp get user path segments",src,x2);
7187 #endif /* COMMENT */
7188 debug(F111,"ftp get haspath",s+usrpath,haspath);
7190 if (haspath) { /* Server file has path segments? */
7191 if (!recursive) { /* [M]GET /RECURSIVE? */
7193 We did not ask for a recursive listing, but the server is sending us one
7194 anyway (as wu-ftpd is wont to do). We get here if the current filename
7195 includes a path segment beyond any path segment we asked for in our
7196 non-recursive [M]GET command. We MUST skip this file.
7198 debug(F111,"ftp get skipping because of path",s,0);
7202 } else if (getone && !skipthis) { /* GET (not MGET) */
7204 while ((c = *p++)) { /* Handle path in local name */
7206 if (recursive) { /* If recursive, keep it */
7209 } else { /* Otherwise lose it. */
7216 if (!*nam) /* Name without path */
7219 if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7223 if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7225 for (i = 0; i < NSNDEXCEPT; i++) {
7226 if (!rcvexcept[i]) {
7229 xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7230 debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7232 tlog(F100," refused: exception list","",0);
7233 msg = "Refused: Exception List";
7239 if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7245 #endif /* CKREGEX */
7249 if (!x_xla) { /* If translation is off */
7250 x_csl = -2; /* unset the charsets */
7253 ckstrncpy(filnam,s,CKMAXPATH); /* For \v(filename) */
7254 if (!*s2) /* Local name */
7255 s2 = asnambuf; /* As-name */
7257 if (!*s2) /* Sat Nov 16 19:19:39 2002 */
7258 s2 = recursive ? s : nam; /* Fri Jan 10 13:15:19 2003 */
7260 debug(F110,"ftp get filnam ",s,0);
7261 debug(F110,"ftp get asname A",s2,0);
7263 /* Receiving to real file */
7267 #endif /* PIPESEND */
7270 /* Do this here so we can decide whether to skip */
7271 if (cmd_quoting && !skipthis && asnambuf[0]) {
7275 zzstring(asnambuf,&p,&n);
7277 debug(F111,"ftp get asname B",s2,updating);
7281 local = *s2 ? s2 : s;
7283 if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7286 debug(F111,"ftp get DISCARD zchki",local,x);
7289 debug(F110,"ftp get skip name",local,0);
7290 tlog(F100," refused: name","",0);
7291 msg = "Refused: Name";
7296 if (!skipthis && updating) { /* If updating and not yet skipping */
7297 if (zchki(local) > -1) {
7298 x = chkmodtime(local,s,0);
7302 debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7304 debug(F111,"ftp get /update chkmodtime",local,x);
7307 if ((updating == 1 && x > 0) || /* /UPDATE */
7308 (updating == 2 && x == 1)) { /* /DATES-DIFFER */
7310 tlog(F100," refused: date","",0);
7311 msg = "Refused: Date";
7312 debug(F110,"ftp get skip date",local,0);
7316 #endif /* DOUPDATE */
7318 /* Initialize file size to -1 in case server doesn't understand */
7319 /* SIZE command, so xxscreen() will know we don't know the size */
7323 /* Ask for size now only if we need it for selection */
7324 /* because if you're going thru a list 100,000 files to select */
7325 /* a small subset, 100,000 SIZE commands can take hours... */
7328 if (!mdel && !skipthis && /* Don't need size for DELE... */
7329 (getsmaller > -1L || getlarger > -1L)) {
7330 if (havesize > -1L) { /* Already have file size? */
7333 } else { /* No - must ask server */
7335 Prior to sending the NLST command we necessarily put the
7336 server into ASCII mode. We must now put it back into the
7337 the requested mode so the upcoming SIZE command returns
7338 right kind of size; this is especially important for
7339 GET /RECOVER; otherwise the server returns the "ASCII" size
7340 of the file, rather than its true size.
7342 changetype(ftp_typ,0); /* Change to requested type */
7345 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7346 if (x == REPLY_COMPLETE) {
7347 fsize = atol(&ftp_reply_str[4]);
7353 if (getsmaller > -1L && fsize >= getsmaller)
7355 if (getlarger > -1L && fsize <= getlarger)
7358 debug(F111,"ftp get skip size",s,fsize);
7359 tlog(F100," refused: size","",0);
7360 msg = "Refused: Size";
7363 } else if (getone) {
7364 /* SIZE can fail for many reasons. Does the file exist? */
7365 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7366 if (x != REPLY_COMPLETE) {
7367 printf(">>> FILE NOT FOUND: %s\n",s);
7370 #endif /* COMMENT */
7373 if (skipthis) { /* Skipping this file? */
7374 ftscreen(SCR_FN,'F',0L,s);
7376 ftscreen(SCR_ST,ST_ERR,0L,msg);
7378 ftscreen(SCR_ST,ST_SKIP,0L,s);
7381 if (fp_nml) { /* /NAMELIST only - no transfer */
7382 fprintf(fp_nml,"%s\n",s);
7385 if (recursive && haspath && !pipesend
7388 #endif /* PIPESEND */
7395 x = zmkdir(s); /* Try to make the directory */
7396 #endif /* NOMKDIR */
7399 rc = -1; /* Failure is fatal */
7402 ftscreen(SCR_EM,0,0L,"Directory creation failure");
7410 selected++; /* Count this file as selected */
7413 if (!gotsize && !mdel) { /* Didn't get size yet */
7414 if (havesize > -1L) { /* Already have file size? */
7417 } else { /* No - must ask server */
7420 x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7421 if (x == REPLY_COMPLETE) {
7422 fsize = atol(&ftp_reply_str[4]);
7428 if (mdel) { /* [M]DELETE */
7429 if (displa && !ftp_vbm)
7432 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7434 tlog(F110,"ftp mdelete",s,0);
7435 if (displa && !ftp_vbm)
7438 tlog(F110,"ftp mdelete failed:",s,0);
7444 } else if (rcvfilter) { /* [M]GET with filter */
7447 p = tmpbuf; /* Safe - no asname with filter */
7448 zzstring(rcvfilter,&p,&n);
7451 debug(F111,"ftp get rcvfilter",pn,n);
7452 #endif /* PIPESEND */
7454 if (toscreen) s2 = "-";
7455 } else if (pipesend) { /* [M]GET /COMMAND */
7458 p = tmpbuf; /* Safe - no asname with filter */
7459 zzstring(pipename,&p,&n);
7462 debug(F111,"ftp get pipename",pipename,n);
7463 if (toscreen) s2 = "-";
7464 } else { /* [M]GET with no pipes or filters */
7465 debug(F111,"ftp get s2 A",s2,x_cnv);
7467 s2 = "-"; /* (hokey convention for stdout) */
7468 } else if (!*s2) { /* No asname? */
7469 if (x_cnv) { /* If converting */
7470 nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7472 debug(F110,"ftp get nzrtol",s2,0);
7473 } else /* otherwise */
7474 s2 = s; /* use incoming file's name */
7476 debug(F110,"ftp get s2 B",s2,0);
7478 /* If local file already exists, take collision action */
7483 #endif /* PIPESEND */
7486 debug(F111,"ftp get zchki",s2,x);
7487 debug(F111,"ftp get x_fnc",s2,x_fnc);
7489 if (x > -1 && !restart) {
7491 char * newname = NULL;
7494 case XYFX_A: /* Append */
7497 case XYFX_R: /* Rename */
7498 case XYFX_B: /* Backup */
7499 znewn(s2,&newname); /* Make unique name */
7500 debug(F110,"ftp get znewn",newname,0);
7501 if (x_fnc == XYFX_B) { /* Backup existing file */
7502 x = zrename(s2,newname);
7503 debug(F111,"ftp get backup zrename",newname,x);
7504 } else { /* Rename incoming file */
7505 x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7507 debug(F111,"ftp get rename incoming",newname,x);
7510 ftscreen(SCR_EM,0,0L,"Backup/Rename failed");
7515 case XYFX_D: /* Discard (already handled above) */
7516 case XYFX_U: /* Update (ditto) */
7517 case XYFX_M: /* Update (ditto) */
7518 case XYFX_X: /* Overwrite */
7526 debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7527 #endif /* PIPESEND */
7528 if (pipesend && !toscreen)
7532 debug(F101,"ftp get x_xla","",x_xla);
7533 debug(F101,"ftp get x_csl","",x_csl);
7534 debug(F101,"ftp get x_csr","",x_csr);
7535 debug(F101,"ftp get append","",append);
7539 rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7543 debug(F111,"ftp get rc",s,rc);
7544 debug(F111,"ftp get cancelfile",s,cancelfile);
7545 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7546 debug(F111,"ftp get renaming",s,renaming);
7554 if (deleting) { /* GET /DELETE (source file) */
7556 (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7558 tlog(F110, (rc > -1) ?
7559 " deleted" : " failed to delete", s, 0);
7560 } else if (renaming && rcv_rename && !toscreen) {
7561 char *p; /* Rename downloaded file */
7563 char tmpbuf[CKMAXPATH+1];
7567 debug(F111,"ftp get /rename",rcv_rename,0);
7568 zzstring(rcv_rename,&p,&n);
7569 debug(F111,"ftp get /rename",rcv_rename,0);
7574 rc = (zrename(s2,p) < 0) ? -1 : 1;
7575 debug(F111,"doftpget /RENAME zrename",p,rc);
7576 tlog(F110, (rc > -1) ?
7578 " failed to rename to",
7582 } else if (moving && rcv_move && !toscreen) {
7583 char *p; /* Move downloaded file */
7585 char tmpbuf[CKMAXPATH+1];
7589 debug(F111,"ftp get /move-to",rcv_move,0);
7590 zzstring(rcv_move,&p,&n);
7595 debug(F111,"ftp get /move-to",p,0);
7596 rc = (zrename(s2,p) < 0) ? -1 : 1;
7597 debug(F111,"doftpget /MOVE zrename",p,rc);
7598 tlog(F110, (rc > -1) ?
7599 " moved to" : " failed to move to", p, 0);
7601 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7602 char * s = pv[SND_SRN].sval;
7603 char * srvrn = pv[SND_SRN].sval;
7604 char tmpbuf[CKMAXPATH+1];
7606 int y; /* Pass it thru the evaluator */
7607 extern int cmd_quoting; /* for \v(filename) */
7608 debug(F111,"ftp get srv_renam",s,1);
7613 zzstring(srvrn,&s,&y);
7617 debug(F111,"ftp get srv_renam",s,1);
7620 x = ftp_rename(s2,s);
7621 debug(F111,"ftp get ftp_rename",s2,x);
7622 tlog(F110, (x > 0) ?
7623 " renamed source file to" :
7624 " failed to rename source file to",
7640 ftscreen(SCR_EM,0,0L,"Fatal download error");
7647 debug(F101,"ftp get status","",status);
7648 debug(F101,"ftp get cancelgroup","",cancelgroup);
7649 debug(F101,"ftp get cancelfile","",cancelfile);
7650 debug(F101,"ftp get selected","",selected);
7651 debug(F101,"ftp get good","",good);
7655 if (selected == 0) { /* No files met selection criteria */
7656 status = 1; /* which is a kind of success. */
7657 } else if (status > 0) { /* Some files were selected */
7658 if (cancelgroup) /* but MGET was canceled */
7659 status = 0; /* so MGET failed */
7660 else if (cancelfile && good < 1) /* If file was canceled */
7661 status = 0; /* MGET failed if it got no files */
7665 debug(F101,"ftp get success","",success);
7668 pipesend = pipesave; /* Restore global pipe selection */
7669 if (fp_nml) { /* Close /NAMELIST */
7670 if (fp_nml != stdout)
7674 if (x > -1) { /* Download successful */
7676 t1 = gmstimer(); /* End time */
7677 sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
7678 if (!sec) sec = 0.001;
7681 sec = (t1 - t0) / 1000;
7683 #endif /* GFTIMER */
7684 tfcps = (long) (tfc / sec);
7686 lastxfer = W_FTP|W_RECV;
7690 ftscreen(SCR_TC,0,0L,"");
7692 if (f_tmpdir) { /* If we changed to download dir */
7693 zchdir((char *) savdir); /* Go back where we came from */
7696 #endif /* CK_TMPDIR */
7698 for (i = 0; i <= SND_MAX; i++) { /* Free malloc'd memory */
7702 for (i = 0; i < mgetn; i++) /* MGET list too */
7703 makestr(&(mgetlist[i]),NULL);
7705 if (cancelgroup) /* Clear temp-file stack */
7708 ftreset(); /* Undo switch effects */
7713 static struct keytab ftprmt[] = {
7715 { "cdup", XZCDU, 0 },
7716 { "cwd", XZCWD, CM_INV },
7717 { "delete", XZDEL, 0 },
7718 { "directory", XZDIR, 0 },
7719 { "exit", XZXIT, 0 },
7720 { "help", XZHLP, 0 },
7721 { "login", XZLGI, 0 },
7722 { "logout", XZLGO, 0 },
7723 { "mkdir", XZMKD, 0 },
7724 { "pwd", XZPWD, 0 },
7725 { "rename", XZREN, 0 },
7726 { "rmdir", XZRMD, 0 },
7727 { "type", XZTYP, 0 },
7730 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
7733 doftpsite() { /* Send a SITE command */
7736 int lcs = -1, rcs = -1;
7740 if (lcs < 0) lcs = fcharset;
7742 if (rcs < 0) rcs = ftp_csr;
7744 #endif /* NOCSETS */
7745 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
7748 ckstrncpy(line,s,LINBUFSIZ);
7749 if (testing) printf(" ftp site \"%s\"...\n",line);
7750 if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
7752 reply = getreply(0,lcs,rcs,ftp_vbm,0);
7753 } while (reply == REPLY_PRELIM);
7755 return(success = (reply == REPLY_COMPLETE));
7760 dosetftppsv() { /* Passive mode */
7761 x = seton(&ftp_psv);
7762 if (x > 0) passivemode = ftp_psv;
7766 /* d o f t p r m t -- Parse and execute REMOTE commands */
7769 doftprmt(cx,who) int cx, who; { /* who == 1 for ftp, 0 for kermit */
7770 /* cx == 0 means REMOTE */
7771 /* cx != 0 is a XZxxx value */
7778 if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
7783 case XZCDU: /* CDUP */
7784 if ((x = cmcfm()) < 0) return(x);
7785 return(doftpcdup());
7787 case XZCWD: /* RCD */
7788 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
7790 ckstrncpy(line,s,LINBUFSIZ);
7791 return(doftpcwd((char *)line,1));
7792 case XZPWD: /* RPWD */
7794 case XZDEL: /* RDEL */
7795 return(doftpget(FTP_MDE,1));
7796 case XZDIR: /* RDIR */
7797 return(doftpdir(FTP_DIR));
7798 case XZHLP: /* RHELP */
7799 return(doftpxhlp());
7800 case XZMKD: /* RMKDIR */
7802 case XZREN: /* RRENAME */
7804 case XZRMD: /* RRMDIR */
7806 case XZLGO: /* LOGOUT */
7808 case XZXIT: /* EXIT */
7811 printf("?Not usable with FTP - \"%s\"\n", atmbuf);
7816 doxftp() { /* Command parser for built-in FTP */
7821 int lcs = -1, rcs = -1;
7826 if (lcs < 0) lcs = fcharset;
7828 if (rcs < 0) rcs = ftp_csr;
7830 #endif /* NOCSETS */
7832 if (inserver) /* FTP not allowed in IKSD. */
7835 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
7836 ftp_typ = g_ftp_typ;
7837 /* g_ftp_typ = -1; */
7841 We'll set the collision action locally in doftpget() based on whether
7842 ftp_fnc was ever set to a value. if not, we'll use the fncact value.
7844 if (ftp_fnc < 0) /* Inherit global collision action */
7845 ftp_fnc = fncact; /* if none specified for FTP */
7846 #endif /* COMMENT */
7848 /* Restore global verbose mode */
7856 ftp_dates &= 1; /* Undo any previous /UPDATE switch */
7858 dpyactive = 0; /* Reset global transfer-active flag */
7859 printlines = 0; /* Reset printlines */
7861 if (fp_nml) { /* Reset /NAMELIST */
7862 if (fp_nml != stdout)
7866 makestr(&ftp_nml,NULL);
7868 cmfdbi(&kw, /* First FDB - commands */
7870 "Hostname; or FTP command", /* help */
7872 "", /* addtl string data */
7873 nftpcmd, /* addtl numeric data 1: tbl size */
7874 0, /* addtl numeric data 2: none */
7875 xxstring, /* Processing function */
7876 ftpcmdtab, /* Keyword table */
7877 &fl /* Pointer to next FDB */
7879 cmfdbi(&fl, /* A host name or address */
7881 "Hostname or address", /* help */
7883 "", /* addtl string data */
7884 0, /* addtl numeric data 1 */
7885 0, /* addtl numeric data 2 */
7890 x = cmfdb(&kw); /* Parse a hostname or a keyword */
7892 printf("?ftp what? \"help ftp\" for hints\n");
7897 if (cmresult.fcode == _CMFLD) { /* If hostname */
7898 return(openftp(cmresult.sresult,0)); /* go open the connection */
7900 cx = cmresult.nresult;
7903 case FTP_ACC: /* ACCOUNT */
7904 if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
7907 makestr(&ftp_acc,s);
7909 printf(" ftp account: \"%s\"\n",ftp_acc);
7910 success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
7913 case FTP_GUP: /* Go UP */
7914 if ((x = cmcfm()) < 0) return(x);
7916 if (testing) printf(" ftp cd: \"(up)\"\n");
7917 return(success = doftpcdup());
7919 case FTP_CWD: /* CD */
7920 if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
7923 ckstrncpy(line,s,LINBUFSIZ);
7925 printf(" ftp cd: \"%s\"\n", line);
7926 return(success = doftpcwd(line,1));
7928 case FTP_CHM: /* CHMOD */
7929 if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
7931 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7932 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
7935 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
7937 printf(" ftp chmod: %s\n",ftpcmdbuf);
7939 (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
7942 case FTP_CLS: /* CLOSE FTP connection */
7943 if ((y = cmcfm()) < 0)
7947 printf(" ftp closing...\n");
7949 return(success = 1);
7951 case FTP_DIR: /* DIRECTORY of remote files */
7953 return(doftpdir(cx));
7955 case FTP_GET: /* GET a remote file */
7956 case FTP_RGE: /* REGET */
7957 case FTP_MGE: /* MGET */
7958 case FTP_MDE: /* MDELETE */
7959 return(doftpget(cx,1));
7961 case FTP_IDL: /* IDLE */
7962 if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
7964 if ((y = cmcfm()) < 0)
7967 if (z < 0) { /* Display idle timeout */
7969 printf(" ftp query idle timeout...\n");
7970 success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
7971 } else { /* Set idle timeout */
7973 printf(" ftp idle timeout set: %d...\n",z);
7975 (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
7979 case FTP_MKD: /* MKDIR */
7982 case FTP_MOD: /* MODTIME */
7983 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
7986 ckstrncpy(line,s,LINBUFSIZ);
7988 printf(" ftp modtime \"%s\"...\n",line);
7990 if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
7998 bzero((char *)&tmremote, sizeof(struct tm));
8000 while ((c = *s++)) {
8007 if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8015 printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8032 case FTP_OPN: /* OPEN connection */
8034 x = cmfld("IP hostname or address","",&s,xxstring);
8039 ckstrncpy(line,s,LINBUFSIZ);
8041 return(openftp(s,0));
8043 { /* OPEN connection */
8044 char name[TTNAMLEN+1], *p;
8046 extern char ttname[];
8047 if (network) /* If we have a current connection */
8048 ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8050 *name = '\0'; /* as default host */
8051 for (p = name; *p; p++) /* Remove ":service" from end. */
8052 if (*p == ':') { *p = '\0'; break; }
8054 x = cmfld("IP hostname or address",name,&s,xxstring);
8056 cmfdbi(&kw, /* First FDB - commands */
8058 "Hostname or switch", /* help */
8060 "", /* addtl string data */
8061 ntlstab, /* addtl numeric data 1: tbl size */
8062 0, /* addtl numeric data 2: none */
8063 xxstring, /* Processing function */
8064 tlstab, /* Keyword table */
8065 &fl /* Pointer to next FDB */
8067 cmfdbi(&fl, /* A host name or address */
8069 "Hostname or address", /* help */
8071 "", /* addtl string data */
8072 0, /* addtl numeric data 1 */
8073 0, /* addtl numeric data 2 */
8080 x = cmfdb(&kw); /* Parse a hostname or a keyword */
8082 printf("?ftp open what? \"help ftp\" for hints\n");
8087 if (cmresult.fcode == _CMFLD) { /* Hostname */
8088 s = cmresult.sresult;
8090 } else if (cmresult.nresult == OPN_TLS) {
8094 #endif /* USETLSTAB */
8099 ckstrncpy(line,s,LINBUFSIZ);
8101 return(openftp(s,usetls));
8103 #endif /* COMMENT */
8105 case FTP_PUT: /* PUT */
8106 case FTP_MPU: /* MPUT */
8107 case FTP_APP: /* APPEND */
8108 return(doftpput(cx,1));
8110 case FTP_PWD: /* PWD */
8112 if (x > -1) success = x;
8115 case FTP_REN: /* RENAME */
8118 case FTP_RES: /* RESET */
8121 case FTP_HLP: /* (remote) HELP */
8122 return(doftpxhlp());
8124 case FTP_RMD: /* RMDIR */
8127 case FTP_STA: /* STATUS */
8128 if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8131 ckstrncpy(line,s,LINBUFSIZ);
8132 if (testing) printf(" ftp status \"%s\"...\n",line);
8133 success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8136 case FTP_SIT: { /* SITE */
8137 return(doftpsite());
8140 case FTP_SIZ: /* (ask for) SIZE */
8141 if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8144 ckstrncpy(line,s,LINBUFSIZ);
8146 printf(" ftp size \"%s\"...\n",line);
8147 success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8152 case FTP_SYS: /* Ask for server's SYSTEM type */
8153 if ((x = cmcfm()) < 0) return(x);
8156 printf(" ftp system...\n");
8157 success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8160 case FTP_UMA: /* Set/query UMASK */
8161 if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8164 ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8165 if ((x = cmcfm()) < 0) return(x);
8169 printf(" ftp umask \"%s\"...\n",tmpbuf);
8171 printf(" ftp query umask...\n");
8173 success = ftp_umask(tmpbuf);
8180 if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8183 success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8186 case FTP_TYP: /* Type */
8187 if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8189 if ((y = cmcfm()) < 0) return(y);
8193 tenex = (ftp_typ == FTT_TEN);
8194 changetype(ftp_typ,ftp_vbm);
8197 case FTP_CHK: /* Check if remote file(s) exist(s) */
8198 if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8201 success = remote_files(1,(CHAR *)s,NULL,0) ? 1 : 0;
8204 case FTP_FEA: /* RFC2389 */
8205 if ((y = cmcfm()) < 0)
8208 success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8210 if (sfttab[0] > 0) {
8211 ftp_aut = sfttab[SFT_AUTH];
8212 sizeok = sfttab[SFT_SIZE];
8213 mdtmok = sfttab[SFT_MDTM];
8214 mlstok = sfttab[SFT_MLST];
8219 case FTP_OPT: /* RFC2389 */
8220 /* Perhaps this should be a keyword list... */
8221 if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8224 ckstrncpy(line,s,LINBUFSIZ);
8225 if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8227 success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8230 case FTP_ENA: /* FTP ENABLE */
8231 case FTP_DIS: /* FTP DISABLE */
8232 if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8234 if ((y = cmcfm()) < 0) return(y);
8236 case ENA_AUTH: /* OK to use autoauthentication */
8237 ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8238 sfttab[SFT_AUTH] = ftp_aut;
8240 case ENA_FEAT: /* OK to send FEAT command */
8241 featok = (cx == FTP_ENA) ? 1 : 0;
8243 case ENA_MLST: /* OK to use MLST/MLSD */
8244 mlstok = (cx == FTP_ENA) ? 1 : 0;
8245 sfttab[SFT_MLST] = mlstok;
8247 case ENA_MDTM: /* OK to use MDTM */
8248 mdtmok = (cx == FTP_ENA) ? 1 : 0;
8249 sfttab[SFT_MDTM] = mdtmok;
8251 case ENA_SIZE: /* OK to use SIZE */
8252 sizeok = (cx == FTP_ENA) ? 1 : 0;
8253 sfttab[SFT_SIZE] = sizeok;
8256 return(success = 1);
8265 case FPL_CLR: return("clear");
8266 case FPL_PRV: return("private");
8267 case FPL_SAF: return("safe");
8268 case 0: return("(not set)");
8269 default: return("(unknown)");
8278 if (g_ftp_typ > -1) { /* Restore TYPE if saved */
8279 ftp_typ = g_ftp_typ;
8280 /* g_ftp_typ = -1; */
8283 printf("FTP connection: %s\n",connected ?
8290 printf("FTP server type: %s\n",
8291 ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8294 printf("Logged in as: %s\n",
8295 strval(ftp_logname,"(unknown)"));
8297 printf("Not logged in\n");
8299 if (brief) return(0);
8301 printf("\nSET FTP values:\n\n");
8304 printf(" ftp anonymous-password: %s\n",
8305 ftp_apw ? ftp_apw : "(default)"
8307 printf(" ftp auto-login: %s\n",showoff(ftp_log));
8308 printf(" ftp auto-authentication: %s\n",showoff(ftp_aut));
8310 case FTT_ASC: s = "text"; break;
8311 case FTT_BIN: s = "binary"; break;
8312 case FTT_TEN: s = "tenex"; break;
8314 printf(" ftp type: %s\n",s);
8315 printf(" ftp get-filetype-switching: %s\n",showoff(get_auto));
8316 printf(" ftp dates: %s\n",showoff(ftp_dates));
8317 printf(" ftp error-action: %s\n",ftp_err ? "quit":"proceed");
8318 printf(" ftp filenames: %s\n",
8319 ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8321 printf(" ftp debug %s\n",showoff(ftp_deb));
8323 printf(" ftp passive-mode: %s\n",showoff(ftp_psv));
8324 printf(" ftp permissions: %s\n",showooa(ftp_prm));
8325 printf(" ftp verbose-mode: %s\n",showoff(ftp_vbx));
8326 printf(" ftp send-port-commands: %s\n",showoff(ftp_psv));
8327 printf(" ftp unique-server-names: %s\n",showoff(ftp_usn));
8329 /* See note in doxftp() */
8332 #endif /* COMMENT */
8333 printf(" ftp collision: %s\n",
8334 fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8335 printf(" ftp server-time-offset: %s\n",
8336 fts_sto ? fts_sto : "(none)");
8340 printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8341 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8343 printf(" ftp server-character-set: %s\n",fcsinfo[ftp_csr].keyword);
8344 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8346 printf(" file character-set: %s\n",fcsinfo[fcharset].keyword);
8347 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8348 #endif /* NOCSETS */
8354 case XYFD_N: s = "none"; break;
8355 case XYFD_R: s = "serial"; break;
8356 case XYFD_C: s = "fullscreen"; break;
8357 case XYFD_S: s = "crt"; break;
8358 case XYFD_B: s = "brief"; break;
8360 printf(" ftp display: %s\n",s);
8361 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8363 if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8364 printf(" enabled: ");
8365 if (ftp_aut) printf(" AUTH");
8366 if (featok) printf(" FEAT");
8367 if (mdtmok) printf(" MDTM");
8368 if (mlstok) printf(" MLST");
8369 if (sizeok) printf(" SIZE");
8371 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8373 if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8374 printf(" disabled: ");
8375 if (!ftp_aut) printf(" AUTH");
8376 if (!featok) printf(" FEAT");
8377 if (!mdtmok) printf(" MDTM");
8378 if (!mlstok) printf(" MLST");
8379 if (!sizeok) printf(" SIZE");
8381 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8384 case 0: s = "kermit"; break;
8385 case 1: s = "ftp"; break;
8386 case 2: s = "auto"; break;
8389 printf(" get-put-remote: %s\n",s);
8390 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8393 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8396 printf("Available security methods: ");
8399 #endif /* FTP_GSSAPI */
8401 printf("Kerberos4 ");
8402 #endif /* FTP_KRB4 */
8405 #endif /* FTP_SRP */
8408 #endif /* FTP_SSL */
8412 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8413 printf(" ftp authtype: %s\n",strval(auth_type,NULL));
8414 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8415 printf(" ftp auto-encryption: %s\n",showoff(ftp_cry));
8416 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8417 printf(" ftp credential-forwarding: %s\n",showoff(ftp_cfw));
8418 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8419 printf(" ftp command-protection-level: %s\n",shopl(ftp_cpl));
8420 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8421 printf(" ftp data-protection-level: %s\n",shopl(ftp_dpl));
8422 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8423 printf(" ftp secure proxy: %s\n",shopl(ssl_ftp_proxy));
8424 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8426 printf("Available security methods: (none)\n");
8427 if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8428 #endif /* FTP_SECURITY */
8430 if (n <= cmd_rows - 3)
8437 /* FTP HELP text strings */
8439 static char * fhs_ftp[] = {
8440 "Syntax: FTP subcommand [ operands ]",
8441 " Makes an FTP connection, or sends a command to the FTP server.",
8442 " To see a list of available FTP subcommands, type \"ftp ?\".",
8443 " and then use HELP FTP xxx to get help about subcommand xxx.",
8444 " Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8448 static char * fhs_acc[] = { /* ACCOUNT */
8449 "Syntax: FTP ACCOUNT text",
8450 " Sends an account designator to an FTP server that needs one.",
8451 " Most FTP servers do not use accounts; some use them for other",
8452 " other purposes, such as disk-access passwords.",
8455 static char * fhs_app[] = { /* APPEND */
8456 "Syntax: FTP APPEND filname",
8457 " Equivalent to [ FTP ] PUT /APPEND. See HELP FTP PUT.",
8460 static char * fhs_cls[] = { /* BYE, CLOSE */
8461 "Syntax: [ FTP ] BYE",
8462 " Logs out from the FTP server and closes the FTP connection.",
8463 " Also see HELP SET GET-PUT-REMOTE. Synonym: [ FTP ] CLOSE.",
8466 static char * fhs_cwd[] = { /* CD, CWD */
8467 "Syntax: [ FTP ] CD directory",
8468 " Asks the FTP server to change to the given directory.",
8469 " Also see HELP SET GET-PUT-REMOTE. Synonyms: [ FTP ] CWD, RCD, RCWD.",
8472 static char * fhs_gup[] = { /* CDUP, UP */
8474 " Asks the FTP server to change to the parent directory of its current",
8475 " directory. Also see HELP SET GET-PUT-REMOTE. Synonym: FTP UP.",
8478 static char * fhs_chm[] = { /* CHMOD */
8479 "Syntax: FTP CHMOD filename permissions",
8480 " Asks the FTP server to change the permissions, protection, or mode of",
8481 " the given file. The given permissions must be in the syntax of the",
8482 " the server's file system, e.g. an octal number for UNIX. Also see",
8483 " FTP PUT /PERMISSIONS",
8486 static char * fhs_mde[] = { /* DELETE */
8487 "Syntax: FTP DELETE [ switches ] filespec",
8488 " Asks the FTP server to delete the given file or files.",
8489 " Synonym: MDELETE (Kermit makes no distinction between single and",
8490 " multiple file deletion). Optional switches:",
8492 " /ERROR-ACTION:{PROCEED,QUIT}",
8494 " /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8495 " /LARGER-THAN:number",
8498 #endif /* UNIXOROSK */
8501 " /RECURSIVE (depends on server)",
8503 #endif /* RECURSIVE */
8504 " /SMALLER-THAN:number",
8507 static char * fhs_dir[] = { /* DIRECTORY */
8508 "Syntax: FTP DIRECTORY [ filespec ]",
8509 " Asks the server to send a directory listing of the files that match",
8510 " the given filespec, or if none is given, all the files in its current",
8511 " directory. The filespec, including any wildcards, must be in the",
8512 " syntax of the server's file system. Also see HELP SET GET-PUT-REMOTE.",
8513 " Synonym: RDIRECTORY.",
8516 static char * fhs_vdi[] = { /* VDIRECTORY */
8517 "Syntax: FTP VDIRECTORY [ filespec ]",
8518 " Asks the server to send a directory listing of the files that match",
8519 " the given filespec, or if none is given, all the files in its current",
8520 " directory. VDIRECTORY is needed for getting verbose directory",
8521 " listings from certain FTP servers, such as on TOPS-20. Try it if",
8522 " FTP DIRECTORY lists only filenames without details.",
8525 static char * fhs_fea[] = { /* FEATURES */
8526 "Syntax: FTP FEATURES",
8527 " Asks the FTP server to list its special features. Most FTP servers",
8528 " do not recognize this command.",
8531 static char * fhs_mge[] = { /* MGET */
8532 "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8533 " Download a single file or multiple files. Asks the FTP server to send",
8534 " the given file or files. Also see FTP GET. Optional switches:",
8537 " Name under which to store incoming file.",
8538 " Pattern required for for multiple files.",
8539 " /BINARY", /* /IMAGE */
8540 " Force binary mode. Synonym: /IMAGE.",
8541 " /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8542 " What to do if an incoming file has the same name as an existing file.",
8546 " Specifies that the as-name is a command to which the incoming file",
8547 " is to be piped as standard input.",
8548 #endif /* PUTPIPE */
8552 " Download only those files whose modification date-times differ from",
8553 " those of the corresponding local files, or that do not already",
8554 " exist on the local computer.",
8555 #endif /* DOUPDATE */
8558 " Specifies that each file is to be deleted from the server after,",
8559 " and only if, it is successfully downloaded.",
8560 " /ERROR-ACTION:{PROCEED,QUIT}",
8561 " When downloading a group of files, what to do upon failure to",
8562 " transfer a file: quit or proceed to the next one.",
8564 " Exception list: don't download any files that match this pattern.",
8565 " See HELP WILDCARD for pattern syntax.",
8566 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8567 " Whether to convert incoming filenames to local syntax.",
8571 " Pass incoming files through the given command.",
8573 #endif /* PIPESEND */
8574 " /LARGER-THAN:number",
8575 " Only download files that are larger than the given number of bytes.",
8576 " /LISTFILE:filename",
8577 " Obtain the list of files to download from the given file.",
8579 " /LOCAL-CHARACTER-SET:name",
8580 " When downloading in text mode and character-set conversion is",
8581 " desired, this specifies the target set.",
8582 #endif /* NOCSETS */
8584 " Specifies a pattern to be used to select filenames locally from the",
8587 " Forces sending of MLSD (rather than NLST) to get the file list.",
8589 " /MOVE-TO:directory",
8590 " Each file that is downloaded is to be moved to the given local",
8591 " directory immediately after, and only if, it has been received",
8593 #endif /* CK_TMPDIR */
8594 " /NAMELIST:filename",
8595 " Instead of downloading the files, stores the list of files that",
8596 " would be downloaded in the given local file, one filename per line.",
8598 " Forces sending of NLST (rather than MLSD) to get the file list.",
8600 " Don't download any files whose names end with .~<number>~.",
8602 " Don't download any files whose names begin with period (.).",
8604 " Suppress the file-transfer display.",
8606 " /RECOVER", /* /RESTART */
8607 " Resume a download that was previously interrupted from the point of",
8608 " failure. Works only in binary mode. Not supported by all servers.",
8609 " Synonym: /RESTART.",
8610 #endif /* FTP_RESTART */
8612 " /RECURSIVE", /* /SUBDIRECTORIES */
8613 " Create subdirectories automatically if the server sends files",
8614 " recursively and includes pathnames (most don't).",
8615 #endif /* RECURSIVE */
8617 " Each file that is downloaded is to be renamed as indicated just,",
8618 " after, and only if, it has arrived successfully.",
8620 " /SERVER-CHARACTER-SET:name",
8621 " When downloading in text mode and character-set conversion is desired"
8622 , " this specifies the original file's character set on the server.",
8623 #endif /* NOCSETS */
8624 " /SERVER-RENAME:text",
8625 " Each server source file is to be renamed on the server as indicated",
8626 " immediately after, but only if, it has arrived successfully.",
8627 " /SMALLER-THAN:number",
8628 " Download only those files smaller than the given number of bytes.",
8629 " /TEXT", /* /ASCII */
8630 " Force text mode. Synonym: /ASCII.",
8632 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8635 " When downloading in text mode, do not convert chracter-sets.",
8636 #endif /* NOCSETS */
8638 " The downloaded file is to be displayed on the screen.",
8641 " Equivalent to /COLLISION:UPDATE. Download only those files that are",
8642 " newer than than their local counterparts, or that do not exist on",
8643 " the local computer.",
8644 #endif /* DOUPDATE */
8647 static char * fhs_hlp[] = { /* HELP */
8648 "Syntax: FTP HELP [ command [ subcommand... ] ]",
8649 " Asks the FTP server for help about the given command. First use",
8650 " FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
8651 " to get help for command \"xxx\". Synonyms: REMOTE HELP, RHELP.",
8654 static char * fhs_idl[] = { /* IDLE */
8655 "Syntax: FTP IDLE [ number ]",
8656 " If given without a number, this asks the FTP server to tell its",
8657 " current idle-time limit. If given with a number, it asks the server",
8658 " to change its idle-time limit to the given number of seconds.",
8661 static char * fhs_usr[] = { /* USER, LOGIN */
8662 "Syntax: FTP USER username [ password [ account ] ]",
8663 " Log in to the FTP server. To be used when connected but not yet",
8664 " logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
8665 " If you omit the password, and one is required by the server, you are",
8666 " prompted for it. If you omit the account, no account is sent.",
8667 " Synonym: FTP LOGIN.",
8670 static char * fhs_get[] = { /* GET */
8671 "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
8672 " Download a single file. Asks the FTP server to send the given file.",
8673 " The optional as-name is the name to store it under when it arrives;",
8674 " if omitted, the file is stored with the name it arrived with, as",
8675 " modified according to the FTP FILENAMES setting or /FILENAMES: switch",
8676 " value. Aside from the file list and as-name, syntax and options are",
8677 " the same as for FTP MGET, which is used for downloading multiple files."
8680 static char * fhs_mkd[] = { /* MKDIR */
8681 "Syntax: FTP MKDIR directory",
8682 " Asks the FTP server to create a directory with the given name,",
8683 " which must be in the syntax of the server's file system. Synonyms:",
8684 " REMOTE MKDIR, RMKDIR.",
8687 static char * fhs_mod[] = { /* MODTIME */
8688 "Syntax: FTP MODTIME filename",
8689 " Asks the FTP server to send the modification time of the given file,",
8690 " to be displayed on the screen. The date-time format is all numeric:",
8691 " yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
8692 " fractions of seconds).",
8695 static char * fhs_mpu[] = { /* MPUT */
8696 "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
8697 " Uploads files. Sends the given file or files to the FTP server.",
8698 " Also see FTP PUT. Optional switches are:",
8700 " /AFTER:date-time",
8701 " Uploads only those files newer than the given date-time.",
8702 " HELP DATE for info about date-time formats. Synonym: /SINCE.",
8704 " /ARRAY:array-designator",
8705 " Tells Kermit to upload the contents of the given array, rather than",
8707 #endif /* PUTARRAY */
8709 " Name under which to send files.",
8710 " Pattern required for for multiple files.",
8711 " /BEFORE:date-time",
8712 " Upload only those files older than the given date-time.",
8714 " Force binary mode. Synonym: /IMAGE.",
8717 " Specifies that the filespec is a command whose standard output is",
8719 #endif /* PUTPIPE */
8724 " Upload only those files whose modification date-times differ from",
8725 " those on the server, or that don't exist on the server at all.",
8726 #endif /* DOUPDATE */
8727 #endif /* COMMENT */
8730 " Specifies that each source file is to be deleted after, and only if,",
8731 " it is successfully uploaded.",
8733 " Include files whose names begin with period (.).",
8734 " /ERROR-ACTION:{PROCEED,QUIT}",
8735 " When uploading a group of files, what to do upon failure to",
8736 " transfer a file: quit or proceed to the next one.",
8738 " Exception list: don't upload any files that match this pattern.",
8739 " See HELP WILDCARD for pattern syntax.",
8740 " /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8741 " Whether to convert outbound filenames to common syntax.",
8745 " Pass outbound files through the given command.",
8747 #endif /* PIPESEND */
8750 " Send files that are pointed to by symbolic links.",
8752 " Skip over symbolic links (default).",
8753 #endif /* CKSYMLINK */
8754 " /LARGER-THAN:number",
8755 " Only upload files that are larger than the given number of bytes.",
8756 " /LISTFILE:filename",
8757 " Obtain the list of files to upload from the given file.",
8759 " /LOCAL-CHARACTER-SET:name",
8760 " When uploading in text mode and character-set conversion is",
8761 " desired, this specifies the source-file character set.",
8762 #endif /* NOCSETS */
8764 " /MOVE-TO:directory",
8765 " Each source file that is uploaded is to be moved to the given local",
8766 " directory when, and only if, the transfer is successful.",
8767 #endif /* CK_TMPDIR */
8769 " Don't upload any files whose names end with .~<number>~.",
8772 " Don't upload any files whose names begin with period (.).",
8773 #endif /* UNIXOROSK */
8774 " /NOT-AFTER:date-time",
8775 " Upload only files that are not newer than the given date-time",
8776 " /NOT-BEFORE:date-time",
8777 " Upload only files that are not older than the given date-time",
8780 " Ask the server to set the permissions of each file it receives",
8781 " according to the source file's permissions.",
8784 " Suppress the file-transfer display.",
8787 " Resume an upload that was previously interrupted from the point of",
8788 " failure. Synonym: /RESTART.",
8789 #endif /* FTP_RESTART */
8792 " Send files from the given directory and all the directories beneath",
8793 " it. Synonym: /SUBDIRECTORIES.",
8794 #endif /* RECURSIVE */
8796 " Each source file that is uploaded is to be renamed on the local",
8797 " local computer as indicated when and only if, the transfer completes",
8800 " /SERVER-CHARACTER-SET:name",
8801 " When uploading in text mode and character-set conversion is desired,",
8802 " this specifies the character set to which the file should be",
8803 " converted for storage on the server.",
8804 #endif /* NOCSETS */
8805 " /SERVER-RENAME:text",
8806 " Each file that is uploaded is to be renamed as indicated on the",
8807 " server after, and only if, if arrives successfully.",
8809 " Show which files would be sent without actually sending them.",
8810 " /SMALLER-THAN:number",
8811 " Upload only those files smaller than the given number of bytes.",
8813 " Force text mode. Synonym: /ASCII.",
8815 " Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8818 " When uploading in text mode, do not convert chracter-sets.",
8819 #endif /* NOCSETS */
8820 " /TYPE:{TEXT,BINARY}",
8821 " Upload only files of the given type.",
8824 " If a file of the same name exists on the server, upload only if",
8825 " the local file is newer.",
8826 #endif /* DOUPDATE */
8827 " /UNIQUE-SERVER-NAMES",
8828 " Ask the server to compute new names for any incoming file that has",
8829 " the same name as an existing file.",
8832 static char * fhs_opn[] = { /* OPEN */
8834 "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
8835 " Opens a connection to the FTP server on the given host. The default",
8836 " TCP port is 21 (990 if SSL/TLS is used), but a different port number",
8837 " can be supplied if necessary. Optional switches are:",
8839 "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
8840 " Opens a connection to the FTP server on the given host. The default",
8841 " TCP port is 21, but a different port number can be supplied if",
8842 " necessary. Optional switches are:",
8846 " Logs you in anonymously.",
8848 " Supplies the given text as your username.",
8850 " Supplies the given text as your password. If you include a username",
8851 " but omit this switch and the server requires a password, you are",
8852 " prompted for it.",
8854 " Supplies the given text as your account, if required by the server.",
8856 " Forces an active (rather than passive) connection.",
8858 " Forces a passive (rather than active) connection.",
8860 " Inhibits sending initial REST, STRU, and MODE commands, which are",
8861 " well-known standard commands, but to which some servers react badly.",
8863 " Inhibits autologin for this connection only.",
8866 static char * fhs_opt[] = { /* OPTS, OPTIONS */
8867 "Syntax: FTP OPTIONS",
8868 " Asks the FTP server to list its current options. Advanced, new,",
8869 " not supported by most FTP servers.",
8872 static char * fhs_put[] = { /* PUT, SEND */
8873 "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
8874 " Like FTP MPUT, but only one filespec is allowed, and if it is followed",
8875 " by an additional field, this is interpreted as the name under which",
8876 " to send the file or files. See HELP FTP MPUT.",
8879 static char * fhs_pwd[] = { /* PWD */
8881 " Asks the FTP server to reveal its current working directory.",
8882 " Synonyms: REMOTE PWD, RPWD.",
8885 static char * fhs_quo[] = { /* QUOTE */
8886 "Syntax: FTP QUOTE text",
8887 " Sends an FTP protocol command to the FTP server. Use this command",
8888 " for sending commands that Kermit might not support.",
8891 static char * fhs_rge[] = { /* REGET */
8892 "Syntax: FTP REGET",
8893 " Synonym for FTP GET /RECOVER.",
8896 static char * fhs_ren[] = { /* RENAME */
8897 "Syntax: FTP RENAME name1 name1",
8898 " Asks the FTP server to change the name of the file whose name is name1",
8899 " and which resides in the FTP server's file system, to name2. Works",
8900 " only for single files; wildcards are not accepted.",
8903 static char * fhs_res[] = { /* RESET */
8904 "Syntax: FTP RESET",
8905 " Asks the server to log out your session, terminating your access",
8906 " rights, without closing the connection.",
8909 static char * fhs_rmd[] = { /* RMDIR */
8910 "Syntax: FTP RMDIR directory",
8911 " Asks the FTP server to remove the directory whose name is given.",
8912 " This usually requires the directory to be empty. Synonyms: REMOTE",
8916 static char * fhs_sit[] = { /* SITE */
8917 "Syntax: FTP SITE text",
8918 " Sends a site-specific command to the FTP server.",
8921 static char * fhs_siz[] = { /* SIZE */
8922 "Syntax: FTP SIZE filename",
8923 " Asks the FTP server to send a numeric string representing the size",
8924 " of the given file.",
8927 static char * fhs_sta[] = { /* STATUS */
8928 "Syntax: FTP STATUS [ filename ]",
8929 " Asks the FTP server to report its status. If a filename is given,",
8930 " the FTP server should report details about the file.",
8933 static char * fhs_sys[] = { /* SYSTEM */
8934 "Syntax: FTP SYSTEM",
8935 " Asks the FTP server to report its operating system type.",
8938 static char * fhs_typ[] = { /* TYPE */
8939 "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
8940 " Puts the client and server in the indicated transfer mode.",
8941 " ASCII is a synonym for TEXT. TENEX is used only for uploading 8-bit",
8942 " binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
8943 " downloading files from TENEX or TOPS-20 that have been uploaded in",
8947 static char * fhs_uma[] = { /* UMASK */
8948 "Syntax: FTP UMASK number",
8949 " Asks the FTP server to set its file creation mode mask. Applies",
8950 " only (or mainly) to UNIX-based FTP servers.",
8953 static char * fhs_chk[] = { /* CHECK */
8954 "Syntax: FTP CHECK remote-filespec",
8955 " Asks the FTP server if the given file or files exist. If the",
8956 " remote-filespec contains wildcards, this command fails if no server",
8957 " files match, and succeeds if at least one file matches. If the",
8958 " remote-filespec does not contain wildcards, this command succeeds if",
8959 " the given file exists and fails if it does not.",
8962 static char * fhs_ena[] = { /* ENABLE */
8963 "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
8964 " Enables the use of the given FTP protocol command in case it has been",
8965 " disabled (but this is no guarantee that the FTP server understands it)."
8967 " Use SHOW FTP to see which of these commands is enabled and disabled.",
8968 " Also see FTP DISABLE.",
8971 static char * fhs_dis[] = { /* DISABLE */
8972 "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
8973 " Disables the use of the given FTP protocol command.",
8974 " Also see FTP ENABLE.",
8983 if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
8986 if ((x = cmcfm()) < 0)
8990 printf("Sorry, no help available\n");
8994 return(hmsga(fhs_ftp));
8995 case FTP_ACC: /* ACCOUNT */
8996 return(hmsga(fhs_acc));
8997 case FTP_APP: /* APPEND */
8998 return(hmsga(fhs_app));
8999 case FTP_CLS: /* BYE, CLOSE */
9000 return(hmsga(fhs_cls));
9001 case FTP_CWD: /* CD, CWD */
9002 return(hmsga(fhs_cwd));
9003 case FTP_GUP: /* CDUP, UP */
9004 return(hmsga(fhs_gup));
9005 case FTP_CHM: /* CHMOD */
9006 return(hmsga(fhs_chm));
9007 case FTP_MDE: /* DELETE, MDELETE */
9008 return(hmsga(fhs_mde));
9009 case FTP_DIR: /* DIRECTORY */
9010 return(hmsga(fhs_dir));
9011 case FTP_VDI: /* VDIRECTORY */
9012 return(hmsga(fhs_vdi));
9013 case FTP_FEA: /* FEATURES */
9014 return(hmsga(fhs_fea));
9015 case FTP_GET: /* GET */
9016 return(hmsga(fhs_get));
9017 case FTP_HLP: /* HELP */
9018 return(hmsga(fhs_hlp));
9019 case FTP_IDL: /* IDLE */
9020 return(hmsga(fhs_idl));
9021 case FTP_USR: /* USER, LOGIN */
9022 return(hmsga(fhs_usr));
9023 case FTP_MGE: /* MGET */
9024 return(hmsga(fhs_mge));
9025 case FTP_MKD: /* MKDIR */
9026 return(hmsga(fhs_mkd));
9027 case FTP_MOD: /* MODTIME */
9028 return(hmsga(fhs_mod));
9029 case FTP_MPU: /* MPUT */
9030 return(hmsga(fhs_mpu));
9031 case FTP_OPN: /* OPEN */
9032 return(hmsga(fhs_opn));
9033 case FTP_OPT: /* OPTS, OPTIONS */
9034 return(hmsga(fhs_opt));
9035 case FTP_PUT: /* PUT, SEND */
9036 return(hmsga(fhs_put));
9037 case FTP_PWD: /* PWD */
9038 return(hmsga(fhs_pwd));
9039 case FTP_QUO: /* QUOTE */
9040 return(hmsga(fhs_quo));
9041 case FTP_RGE: /* REGET */
9042 return(hmsga(fhs_rge));
9043 case FTP_REN: /* RENAME */
9044 return(hmsga(fhs_ren));
9045 case FTP_RES: /* RESET */
9046 return(hmsga(fhs_res));
9047 case FTP_RMD: /* RMDIR */
9048 return(hmsga(fhs_rmd));
9049 case FTP_SIT: /* SITE */
9050 return(hmsga(fhs_sit));
9051 case FTP_SIZ: /* SIZE */
9052 return(hmsga(fhs_siz));
9053 case FTP_STA: /* STATUS */
9054 return(hmsga(fhs_sta));
9055 case FTP_SYS: /* SYSTEM */
9056 return(hmsga(fhs_sys));
9057 case FTP_TYP: /* TYPE */
9058 return(hmsga(fhs_typ));
9059 case FTP_UMA: /* UMASK */
9060 return(hmsga(fhs_uma));
9061 case FTP_CHK: /* CHECK */
9062 return(hmsga(fhs_chk));
9064 return(hmsga(fhs_ena));
9066 return(hmsga(fhs_dis));
9068 printf("Sorry, help available for this command.\n");
9072 return(success = 0);
9078 if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9082 ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9083 if ((x = cmcfm()) < 0)
9087 printf("Sorry, no help available\n");
9091 printf("\nSyntax: SET FTP parameter value\n");
9092 printf(" Type \"help set ftp ?\" for a list of parameters.\n");
9093 printf(" Type \"help set ftp xxx\" for information about setting\n");
9094 printf(" parameter xxx. Type \"show ftp\" for current values.\n\n");
9098 printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9100 " Activates a workaround for the named bug in the FTP server.\n");
9101 printf(" Type SET FTP BUG ? for a list of names.\n");
9102 printf(" For each bug, the default is OFF\n\n");
9106 case FTS_ATP: /* "authtype" */
9107 printf("\nSyntax: SET FTP AUTHTYPE list\n");
9108 printf(" Specifies an ordered list of authentication methods to be\n"
9110 printf(" when FTP AUTOAUTHENTICATION is ON. The default list is:\n");
9111 printf(" GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9114 case FTS_AUT: /* "autoauthentication" */
9115 printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9116 printf(" Tells whether authentication should be negotiated by the\n");
9117 printf(" FTP OPEN command. Default is ON.\n\n");
9120 case FTS_CRY: /* "autoencryption" */
9121 printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9122 printf(" Tells whether encryption (privacy) should be negotiated\n");
9123 printf(" by the FTP OPEN command. Default is ON.\n\n");
9125 #endif /* FTP_SECURITY */
9127 case FTS_LOG: /* "autologin" */
9128 printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9129 printf(" Tells Kermit whether to try to log you in automatically\n");
9130 printf(" as part of the connection process.\n\n");
9134 printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9135 printf(" Chooses the file-transfer display style for FTP.\n");
9136 printf(" Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9140 case FTS_XLA: /* "character-set-translation" */
9141 printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9142 printf(" Whether to translate character sets when transferring\n");
9143 printf(" text files with FTP. OFF by default.\n\n");
9146 #endif /* NOCSETS */
9147 case FTS_FNC: /* "collision" */
9150 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9152 printf(" Tells what do when an incoming file has the same name as\n");
9153 printf(" an existing file when downloading with FTP.\n\n");
9157 case FTS_CPL: /* "command-protection-level" */
9160 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9164 " Tells what level of protection is applied to the FTP command channel.\n\n");
9166 case FTS_CFW: /* "credential-forwarding" */
9167 printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9168 printf(" Tells whether end-user credentials are to be forwarded\n");
9169 printf(" to the server if supported by the authentication method\n");
9170 printf(" (GSSAPI-KRB5 only).\n\n");
9172 case FTS_DPL: /* "data-protection-level" */
9175 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9179 " Tells what level of protection is applied to the FTP data channel.\n\n");
9181 #endif /* FTP_SECURITY */
9183 case FTS_DBG: /* "debug" */
9184 printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9185 printf(" Whether to print FTP protocol messages.\n\n");
9188 case FTS_ERR: /* "error-action" */
9189 printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9190 printf(" What to do when an error occurs when transferring a group\n")
9192 printf(" of files: quit and fail, or proceed to the next file.\n\n");
9195 case FTS_CNV: /* "filenames" */
9196 printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9197 printf(" What to do with filenames: convert them, take and use them\n"
9199 printf(" literally; or choose what to do automatically based on the\n"
9201 printf(" OS type of the server. The default is AUTO.\n\n");
9204 case FTS_PSV: /* "passive-mode" */
9205 printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9206 printf(" Whether to use passive mode, which helps to get through\n");
9207 printf(" firewalls. ON by default.\n\n");
9210 case FTS_PRM: /* "permissions" */
9211 printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9212 printf(" Whether to try to send file permissions when uploading.\n");
9213 printf(" OFF by default. AUTO means only if client and server\n");
9214 printf(" have the same OS type.\n\n");
9217 case FTS_TST: /* "progress-messages" */
9218 printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9219 printf(" Whether Kermit should print locally-generated feedback\n");
9220 printf(" messages for each non-file-transfer command.");
9221 printf(" ON by default.\n\n");
9224 case FTS_SPC: /* "send-port-commands" */
9225 printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9226 printf(" Whether Kermit should send a new PORT command for each");
9227 printf(" task.\n\n");
9231 case FTS_CSR: /* "server-character-set" */
9232 printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9233 printf(" The name of the character set used for text files on the\n");
9234 printf(" server. Enter a name of '?' for a menu.\n\n");
9236 #endif /* NOCSETS */
9238 case FTS_STO: /* "server-time-offset */
9240 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9242 " Specifies an offset to apply to the server's file timestamps.\n");
9244 " Use this to correct for misconfigured server time or timezone.\n");
9246 " Format: must begin with + or - sign. Hours must be given; minutes\n");
9248 " and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9251 case FTS_TYP: /* "type" */
9252 printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9253 printf(" Establishes the default transfer mode.\n");
9254 printf(" TENEX is used for uploading 8-bit binary files to 36-bit\n");
9255 printf(" platforms such as TENEX and TOPS-20 and for downloading\n");
9256 printf(" them again.\n\n");
9261 printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9262 printf(" Tells whether GET and MGET should automatically switch\n");
9263 printf(" the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9264 printf(" matching the name of each incoming file with its list of\n");
9265 printf(" FILE TEXT-PATTERNS and FILE BINARY-PATTERNS. ON by\n");
9266 printf(" default. SHOW PATTERNS displays the current pattern\n");
9267 printf(" list. HELP SET FILE to see how to change it.\n");
9269 #endif /* PATTERNS */
9271 case FTS_USN: /* "unique-server-names" */
9272 printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9273 printf(" Tells whether to ask the server to create unique names\n");
9274 printf(" for any uploaded file that has the same name as an\n");
9275 printf(" existing file. Default is OFF.\n\n");
9278 case FTS_VBM: /* "verbose-mode" */
9279 printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9280 printf(" Whether to display all responses from the FTP server.\n");
9281 printf(" OFF by default.\n\n");
9285 printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9286 printf(" Whether to set date of incoming files from the file date\n");
9287 printf(" on the server. ON by default. Note: there is no way to\n")
9289 printf(" set the date on files uploaded to the server. Also note\n");
9290 printf(" that not all servers support this feature.\n\n");
9294 printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9295 printf(" Password to supply automatically on anonymous FTP\n");
9296 printf(" connections instead of the default user@host.\n");
9297 printf(" Omit optional text to restore default.\n\n");
9301 printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9315 char srp_user[BUFSIZ]; /* where is BUFSIZ defined? */
9318 #endif /* FTP_SRP */
9320 static int kerror; /* Needed for all auth types */
9322 static struct sockaddr_in hisctladdr;
9323 static struct sockaddr_in hisdataaddr;
9324 static struct sockaddr_in data_addr;
9325 static int data = -1;
9326 static int ptflag = 0;
9327 static struct sockaddr_in myctladdr;
9333 #endif /* COMMENT */
9336 static int cpend = 0; /* No pending replies */
9339 extern SSL *ssl_ftp_con;
9340 extern SSL_CTX *ssl_ftp_ctx;
9341 extern SSL *ssl_ftp_data_con;
9342 extern int ssl_ftp_active_flag;
9343 extern int ssl_ftp_data_active_flag;
9346 /* f t p c m d -- Send a command to the FTP server */
9349 char * cmd: The command to send.
9350 char * arg: The argument (e.g. a filename).
9351 int lcs: The local character set index.
9352 int rcs: The remote (server) character set index.
9353 int vbm: Verbose mode:
9354 0 = force verbosity off
9355 >0 = force verbosity on
9357 If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9358 and neither lcs or rcs is UCS-2, the arg is translated from the local
9359 character set to the remote one before sending the result to the server.
9362 0 on failure with ftpcode = -1
9363 >= 0 on success (getreply() result) with ftpcode = 0.
9365 static char xcmdbuf[RFNBUFSIZ];
9368 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9370 int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9373 if (ftp_deb) /* DEBUG */
9375 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
9377 else if (vbm < 0) /* VERBOSE */
9383 cmdlen = (int)strlen(cmd);
9384 len = cmdlen + (int)strlen(arg) + 1;
9386 if (ftp_deb /* && !dpyactive */ ) {
9388 if (ftp_prx) printf("%s ", ftp_host);
9389 #endif /* FTP_PROXY */
9391 if (!anonymous && strcmp("PASS",cmd) == 0)
9392 printf("PASS XXXX");
9394 printf("%s %s",cmd,arg);
9397 /* bzero(xcmdbuf,RFNBUFSIZ); */
9398 ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9402 debug(F110,"ftpcmd cmd",cmd,0);
9403 debug(F110,"ftpcmd arg",arg,0);
9404 debug(F101,"ftpcmd lcs","",lcs);
9405 debug(F101,"ftpcmd rcs","",rcs);
9409 if (csocket == -1) {
9410 perror("No control connection for command");
9415 oldintr = signal(SIGINT, cmdcancel);
9418 if (*arg && /* If an arg was given */
9419 lcs > -1 && /* and a local charset */
9420 rcs > -1 && /* and a remote charset */
9421 lcs != rcs && /* and the two are not the same */
9422 lcs != FC_UCS2 && /* and neither one is UCS-2 */
9423 rcs != FC_UCS2 /* ... */
9425 initxlate(lcs,rcs); /* Translate arg from lcs to rcs */
9426 xgnbp = arg; /* Global pointer to input string */
9427 rfnptr = rfnbuf; /* Global pointer to output buffer */
9430 if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9431 if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9434 We have to copy here instead of translating directly into
9435 xcmdbuf[] so strputc() can check length. Alternatively we could
9436 write yet another xpnbyte() output function.
9438 if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9439 printf("?FTP command too long: %s + arg\n",cmd);
9443 x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9445 #endif /* NOCSETS */
9447 s = xcmdbuf; /* Command to send to server */
9450 if (deblog) { /* Log it */
9451 if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9452 /* But don't log passwords */
9453 debug(F110,"FTP SENT ","PASS XXXX",0);
9455 debug(F110,"FTP SENT ",s,0);
9460 #ifdef CK_ENCRYPTION
9462 #endif /* CK_ENCRYPTION */
9463 if (scommand(s) == 0) { /* Send it. */
9464 signal(SIGINT, oldintr);
9468 x = !strcmp(cmd,"QUIT"); /* Is it the QUIT command? */
9469 if (x) /* In case we're interrupted */
9470 connected = 0; /* while waiting for the reply... */
9472 fc = 0; /* Function code for getreply() */
9473 if (!strncmp(cmd,"AUTH ",5) /* Must parse AUTH reply */
9475 && strncmp(cmd, "HOST ",5)
9476 #endif /* FTPHOST */
9479 } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9480 fc = GRF_FEAT; /* But FEAT not widely understood */
9481 if (!ftp_deb) /* So suppress error messages */
9484 r = getreply(x, /* Expect connection to close */
9485 lcs,rcs, /* Charsets */
9486 vbm, /* Verbosity */
9487 fc /* Function code */
9492 #ifdef CK_ENCRYPTION
9493 if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9495 "ENC command not supported at server; retrying under MIC...\n");
9499 #endif /* CK_ENCRYPTION */
9501 if (cancelfile && oldintr != SIG_IGN)
9503 #endif /* COMMENT */
9504 signal(SIGINT, oldintr);
9510 debug(F100,"lostpeer","",0);
9512 if (csocket != -1) {
9514 if (ssl_ftp_active_flag) {
9515 SSL_shutdown(ssl_ftp_con);
9516 SSL_free(ssl_ftp_con);
9518 ssl_ftp_active_flag = 0;
9523 socket_close(csocket);
9524 #else /* TCPIPLIB */
9526 shutdown(csocket, 1+1);
9527 #endif /* USE_SHUTDOWN */
9529 #endif /* TCPIPLIB */
9534 if (ssl_ftp_data_active_flag) {
9535 SSL_shutdown(ssl_ftp_data_con);
9536 SSL_free(ssl_ftp_data_con);
9537 ssl_ftp_data_active_flag = 0;
9538 ssl_ftp_data_con = NULL;
9543 #else /* TCPIPLIB */
9545 shutdown(data, 1+1);
9546 #endif /* USE_SHUTDOWN */
9548 #endif /* TCPIPLIB */
9556 ftp_cpl = ftp_dpl = FPL_CLR;
9559 #endif /* CKLOGDIAL */
9562 if (autolocus) /* Auotomatic locus switching... */
9563 setlocus(1,1); /* Switch locus to local. */
9566 DialerSend(OPT_KERMIT_HANGUP, 0);
9572 if (csocket != -1) {
9574 socket_close(csocket);
9575 #else /* TCPIPLIB */
9577 shutdown(csocket, 1+1);
9578 #endif /* USE_SHUTDOWN */
9580 #endif /* TCPIPLIB */
9587 ftp_cpl = ftp_dpl = FPL_CLR;
9591 #endif /* FTP_PROXY */
9601 extern int quitting;
9604 if (!ftp_vbm && !quiet) printlines = 1;
9605 ftpcmd("QUIT",NULL,0,0,ftp_vbm);
9608 if (ssl_ftp_active_flag) {
9609 SSL_shutdown(ssl_ftp_con);
9610 SSL_free(ssl_ftp_con);
9612 ssl_ftp_active_flag = 0;
9617 socket_close(csocket);
9618 #else /* TCPIPLIB */
9620 shutdown(csocket, 1+1);
9621 #endif /* USE_SHUTDOWN */
9623 #endif /* TCPIPLIB */
9639 #endif /* FTP_PROXY */
9644 #endif /* CKLOGDIAL */
9646 /* Unprefixed file management commands are executed locally */
9647 if (autolocus && !ftp_cmdlin && !quitting) {
9652 DialerSend(OPT_KERMIT_HANGUP, 0);
9658 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
9662 printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
9668 #endif /* FTPHOST */
9670 ftp_srvtyp[0] = NUL;
9671 if (!service) service = "";
9672 if (!*service) service = use_tls ? "ftps" : "ftp";
9674 if (!isdigit(service[0])) {
9675 struct servent *destsp;
9676 destsp = getservbyname(service, "tcp");
9678 if (!ckstrcmp(service,"ftp",-1,0)) {
9680 } else if (!ckstrcmp(service,"ftps",-1,0)) {
9683 printf("?Bad port name - \"%s\"\n", service);
9688 ftp_port = destsp->s_port;
9689 ftp_port = ntohs(ftp_port);
9692 ftp_port = atoi(service);
9693 if (ftp_port <= 0) {
9694 printf("?Bad port name - \"%s\"\n", service);
9698 host = ftp_hookup(remote, ftp_port, use_tls);
9700 ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
9701 connected = 1; /* Set FTP defaults */
9702 ftp_cpl = ftp_dpl = FPL_CLR;
9703 curtype = FTT_ASC; /* Server uses ASCII mode */
9707 strcpy(bytename, "8");
9715 && ck_crypt_is_installed()
9719 printf("FTP Command channel is Private (encrypted)\n");
9721 if (setpbsz(DEFAULT_PBSZ) < 0) {
9722 /* a failure here is most likely caused by a mixup */
9723 /* in the session key used by client and server */
9724 printf("?Protection buffer size negotiation failed\n");
9727 if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
9729 printf("FTP Data channel is Private (encrypted)\n");
9732 printf("?Unable to enable encryption on data channel\n");
9740 #endif /* FTP_SECURITY */
9741 if (ftp_log) /* ^^^ */
9749 #endif /* CKLOGDIAL */
9751 DialerSend(OPT_KERMIT_CONNECT, 0);
9753 passivemode = ftp_psv;
9760 if (ucbuf == NULL) {
9761 actualbuf = DEFAULT_PBSZ;
9762 while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
9766 ucbufsiz = actualbuf - FUDGE_FACTOR;
9767 debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
9771 printf("?Can't FTP connect to %s:%s\n",remote,service);
9782 if (ssl_debug_flag) {
9783 fprintf(stderr,"SSL DEBUG ACTIVE\n");
9785 /* for the moment I want the output on screen */
9787 if (ssl_ftp_data_con != NULL) {
9788 SSL_free(ssl_ftp_data_con);
9789 ssl_ftp_data_con = NULL;
9791 if (ssl_ftp_con != NULL) {
9792 SSL_free(ssl_ftp_con);
9795 if (ssl_ftp_ctx != NULL) {
9796 SSL_CTX_free(ssl_ftp_ctx);
9800 /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
9801 * was added to OpenSSL 0.9.6e and 0.9.7. It does not exist in previous
9804 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
9805 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
9807 if (auth_type && !strcmp(auth_type,"TLS")) {
9808 ssl_ftp_ctx=SSL_CTX_new(SSLv3_client_method());
9811 SSL_CTX_set_options(ssl_ftp_ctx,
9812 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
9815 ssl_ftp_ctx = SSL_CTX_new(ftp_bug_use_ssl_v2 ? SSLv23_client_method() :
9816 SSLv3_client_method());
9819 SSL_CTX_set_options(ssl_ftp_ctx,
9820 (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
9821 SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
9824 SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
9825 (pem_password_cb *)ssl_passwd_callback);
9826 SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
9827 SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
9831 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
9833 char path[CKMAXPATH];
9834 extern char exedir[];
9836 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
9837 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
9838 debug(F110,"ftp ssl_auth unable to load path",path,0);
9840 printf("?Unable to load verify-dir: %s\r\n",path);
9843 ckmakmsg(path,CKMAXPATH,
9844 (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
9845 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
9846 debug(F110,"ftp ssl_auth unable to load path",path,0);
9848 printf("?Unable to load verify-dir: %s\r\n",path);
9851 ckmakmsg(path,CKMAXPATH,
9852 (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
9853 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
9854 debug(F110,"ftp ssl_auth unable to load path",path,0);
9856 printf("?Unable to load verify-dir: %s\r\n",path);
9859 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
9860 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
9861 debug(F110,"ftp ssl_auth unable to load path",path,0);
9863 printf("?Unable to load verify-file: %s\r\n",path);
9866 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
9867 "kermit 95/ca_certs.pem",NULL,NULL);
9868 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
9869 debug(F110,"ftp ssl_auth unable to load path",path,0);
9871 printf("?Unable to load verify-file: %s\r\n",path);
9874 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
9875 "kermit 95/ca_certs.pem",NULL,NULL);
9876 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
9877 debug(F110,"ftp ssl_auth unable to load path",path,0);
9879 printf("?Unable to load verify-file: %s\r\n",path);
9883 /* The defaults in the SSL crypto library are not appropriate for OS/2 */
9886 char path[CKMAXPATH];
9887 extern char exedir[];
9889 ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
9890 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0) {
9891 debug(F110,"ftp ssl_auth unable to load path",path,0);
9893 printf("?Unable to load verify-dir: %s\r\n",path);
9895 ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
9896 if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
9897 debug(F110,"ftp ssl_auth unable to load path",path,0);
9899 printf("?Unable to load verify-file: %s\r\n",path);
9904 SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
9907 if (ssl_verify_file &&
9908 SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
9910 "ftp ssl auth unable to load ssl_verify_file",
9915 printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
9917 if (ssl_verify_dir &&
9918 SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
9920 "ftp ssl auth unable to load ssl_verify_dir",
9925 printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
9928 /* set up the new CRL Store */
9929 crl_store = (X509_STORE *)X509_STORE_new();
9932 char path[CKMAXPATH];
9933 extern char exedir[];
9935 ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
9936 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
9937 debug(F110,"ftp ssl auth unable to load dir",path,0);
9939 printf("?Unable to load crl-dir: %s\r\n",path);
9942 ckmakmsg(path,CKMAXPATH,
9943 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
9944 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
9945 debug(F110,"ftp ssl auth unable to load dir",path,0);
9947 printf("?Unable to load crl-dir: %s\r\n",path);
9949 ckmakmsg(path,CKMAXPATH,
9950 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
9951 if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
9952 debug(F110,"ftp ssl auth unable to load dir",path,0);
9954 printf("?Unable to load crl-dir: %s\r\n",path);
9958 ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
9959 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
9960 debug(F110,"ftp ssl auth unable to load file",path,0);
9962 printf("?Unable to load crl-file: %s\r\n",path);
9965 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
9966 "kermit 95/ca_crls.pem",NULL,NULL);
9967 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
9968 debug(F110,"ftp ssl auth unable to load file",path,0);
9970 printf("?Unable to load crl-file: %s\r\n",path);
9972 ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
9973 "kermit 95/ca_crls.pem",NULL,NULL);
9974 if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
9975 debug(F110,"ftp ssl auth unable to load file",path,0);
9977 printf("?Unable to load crl-file: %s\r\n",path);
9982 if (ssl_crl_file || ssl_crl_dir) {
9984 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
9986 "ftp ssl auth unable to load ssl_crl_file",
9991 printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
9994 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
9996 "ftp ssl auth unable to load ssl_crl_dir",
10000 if (ssl_debug_flag)
10001 printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10004 X509_STORE_set_default_paths(crl_store);
10007 SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10008 ssl_client_verify_callback);
10009 ssl_verify_depth = -1;
10010 ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10011 tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10012 SSL_set_fd(ssl_ftp_con,csocket);
10013 SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10014 if (ssl_cipher_list) {
10015 SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10018 if (p = getenv("SSL_CIPHER")) {
10019 SSL_set_cipher_list(ssl_ftp_con,p);
10021 SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10024 if (ssl_debug_flag) {
10025 fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10028 if (SSL_connect(ssl_ftp_con) <= 0) {
10029 static char errbuf[1024];
10030 ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10031 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10032 fprintf(stderr,"%s\n", errbuf);
10034 ssl_ftp_active_flag=0;
10035 SSL_free(ssl_ftp_con);
10036 ssl_ftp_con = NULL;
10038 ssl_ftp_active_flag = 1;
10040 if (!ssl_certsok_flag && !tls_is_krb5(1)) {
10041 char *subject = ssl_get_subject_name(ssl_ftp_con);
10044 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10045 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10046 return(ssl_ftp_active_flag = 0);
10048 if (uq_ok("Warning: Server didn't provide a certificate\n",
10049 "Continue? (Y/N)",3,NULL,0) <= 0) {
10050 debug(F110, "ssl_auth","[SSL - FAILED]",0);
10051 return(ssl_ftp_active_flag = 0);
10054 } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10055 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10056 return(ssl_ftp_active_flag = 0);
10059 debug(F110,"ssl_auth","[SSL - OK]",0);
10060 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10062 if (ssl_debug_flag) {
10063 fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10066 return(ssl_ftp_active_flag);
10068 #endif /* CK_SSL */
10071 cmdcancel(sig) int sig; {
10073 /* In Unix we "chain" to trap(), which prints this */
10076 debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10078 secure_getc(0,1); /* Initialize net input buffers */
10084 if (ptflag) /* proxy... */
10085 longjmp(ptcancel,1);
10086 #endif /* FTP_PROXY */
10087 debug(F100,"ftp cmdcancel chain to trap()...","",0);
10090 debug(F100,"ftp cmdcancel return from trap()...","",0);
10092 debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10099 scommand(char * s) /* Was secure_command() */
10101 scommand(s) char * s;
10102 #endif /* CK_ANSIC */
10104 int length = 0, len2;
10105 char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10107 if (ssl_ftp_active_flag) {
10109 length = strlen(s) + 2;
10110 length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10111 rc = SSL_write(ssl_ftp_con,out,length);
10112 error = SSL_get_error(ssl_ftp_con,rc);
10114 case SSL_ERROR_NONE:
10116 case SSL_ERROR_WANT_WRITE:
10117 case SSL_ERROR_WANT_READ:
10118 case SSL_ERROR_SYSCALL:
10121 int gle = GetLastError();
10124 case SSL_ERROR_WANT_X509_LOOKUP:
10125 case SSL_ERROR_SSL:
10126 case SSL_ERROR_ZERO_RETURN:
10132 #endif /* CK_SSL */
10134 if (auth_type && ftp_cpl != FPL_CLR) {
10136 if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10137 if ((length = srp_encode(ftp_cpl == FPL_PRV,
10141 fprintf(stderr, "SRP failed to encode message\n");
10144 #endif /* FTP_SRP */
10146 if (ck_krb4_is_installed() &&
10147 (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10148 if (ftp_cpl == FPL_PRV) {
10150 krb_mk_priv((CHAR *)s, (CHAR *)out,
10151 strlen(s), ftp_sched,
10156 #endif /* KRB524 */
10157 &myctladdr, &hisctladdr);
10160 krb_mk_safe((CHAR *)s,
10167 #endif /* KRB524 */
10168 &myctladdr, &hisctladdr);
10170 if (length == -1) {
10171 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10172 ftp_cpl == FPL_PRV ? "priv" : "safe");
10176 #endif /* FTP_KRB4 */
10178 /* Scommand (based on level) */
10179 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10180 gss_buffer_desc in_buf, out_buf;
10181 OM_uint32 maj_stat, min_stat;
10184 in_buf.length = strlen(s) + 1;
10185 maj_stat = gss_seal(&min_stat, gcontext,
10186 (ftp_cpl==FPL_PRV), /* private */
10188 &in_buf, &conf_state,
10190 if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10191 user_gss_error(maj_stat, min_stat,
10192 (ftp_cpl==FPL_PRV)?
10193 "gss_seal ENC didn't complete":
10194 "gss_seal MIC didn't complete");
10195 } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10196 fprintf(stderr, "GSSAPI didn't encrypt message");
10199 fprintf(stderr, "sealed (%s) %d bytes\n",
10200 ftp_cpl==FPL_PRV?"ENC":"MIC",
10202 memcpy(out, out_buf.value,
10203 length=out_buf.length);
10204 gss_release_buffer(&min_stat, &out_buf);
10207 #endif /* FTP_GSSAPI */
10208 /* Other auth types go here ... */
10211 if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10212 length, &len2, RADIX_ENCODE))
10214 fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10215 radix_error(kerror));
10219 fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10220 len2 = ckmakmsg(out,
10222 ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10227 send(csocket,(SENDARG2TYPE)out,len2,0);
10229 char out[FTP_BUFSIZ];
10230 int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10231 send(csocket,(SENDARG2TYPE)out,len,0);
10238 static char inbuf[4096];
10239 static int bp = 0, ep = 0;
10245 if (ssl_ftp_active_flag) {
10247 rc = SSL_read(ssl_ftp_con,inbuf,4096);
10248 error = SSL_get_error(ssl_ftp_con,rc);
10250 case SSL_ERROR_NONE:
10252 case SSL_ERROR_WANT_WRITE:
10253 case SSL_ERROR_WANT_READ:
10255 case SSL_ERROR_SYSCALL:
10256 if (rc == 0) { /* EOF */
10260 int gle = GetLastError();
10264 case SSL_ERROR_WANT_X509_LOOKUP:
10265 case SSL_ERROR_SSL:
10266 case SSL_ERROR_ZERO_RETURN:
10271 #endif /* CK_SSL */
10272 rc = recv(csocket,(char *)inbuf,4096,0);
10277 return(inbuf[bp++]);
10280 /* x l a t e c -- Translate a character */
10283 fc = Function code: 0 = translate, 1 = initialize.
10284 c = Character (as int).
10285 incs = Index of charset to translate from.
10286 outcs = Index of charset to translate to.
10293 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10297 static char buf[128];
10301 if (fc == 1) { /* Initialize */
10302 cx = 0; /* Catch-up buffer write index */
10303 xgnbp = buf; /* Catch-up buffer read pointer */
10304 buf[0] = NUL; /* Buffer is empty */
10307 if (cx >= 127) { /* Catch-up buffer full */
10308 debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10309 printf("?Translation buffer overflow\n");
10312 /* Add char to buffer. */
10313 /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10315 debug(F000,"xlatec buf",ckitoa(cx),c);
10319 while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10320 if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0) /* (NULL was xprintc) */
10323 /* If we're caught up, reinitialize the buffer */
10324 return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10325 #endif /* NOCSETS */
10329 /* p a r s e f e a t */
10331 /* Note: for convenience we align keyword values with table indices */
10332 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10334 static struct keytab feattab[] = {
10335 { "$$$$", 0, 0 }, /* Dummy for sfttab[0] */
10336 { "AUTH", SFT_AUTH, 0 },
10337 { "LANG", SFT_LANG, 0 },
10338 { "MDTM", SFT_MDTM, 0 },
10339 { "MLST", SFT_MLST, 0 },
10340 { "PBSZ", SFT_PBSZ, 0 },
10341 { "PROT", SFT_PROT, 0 },
10342 { "REST", SFT_REST, 0 },
10343 { "SIZE", SFT_SIZE, 0 },
10344 { "TVFS", SFT_TVFS, 0 },
10345 { "UTF8", SFT_UTF8, 0 }
10347 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10349 #define FACT_CSET 1
10350 #define FACT_CREA 2
10351 #define FACT_LANG 3
10352 #define FACT_MTYP 4
10353 #define FACT_MDTM 5
10354 #define FACT_PERM 6
10355 #define FACT_SIZE 7
10356 #define FACT_TYPE 8
10357 #define FACT_UNIQ 9
10359 static struct keytab facttab[] = {
10360 { "CHARSET", FACT_CSET, 0 },
10361 { "CREATE", FACT_CREA, 0 },
10362 { "LANG", FACT_LANG, 0 },
10363 { "MEDIA-TYPE", FACT_MTYP, 0 },
10364 { "MODIFY", FACT_MDTM, 0 },
10365 { "PERM", FACT_PERM, 0 },
10366 { "SIZE", FACT_SIZE, 0 },
10367 { "TYPE", FACT_TYPE, 0 },
10368 { "UNIQUE", FACT_UNIQ, 0 }
10370 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10372 static struct keytab ftyptab[] = {
10373 { "CDIR", FTYP_CDIR, 0 },
10374 { "DIR", FTYP_DIR, 0 },
10375 { "FILE", FTYP_FILE, 0 },
10376 { "PDIR", FTYP_PDIR, 0 }
10378 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10381 parsefeat(s) char * s; { /* Parse a FEATURE response */
10388 for (i = 0; i < 4; i++) {
10393 if (s[i] && s[i] != SP)
10396 /* xlookup requires a full (but case independent) match */
10397 i = xlookup(feattab,kwbuf,nfeattab,&x);
10398 debug(F111,"ftp parsefeat",s,i);
10399 if (i < 0 || i > 15)
10403 case SFT_MDTM: /* Controlled by ENABLE/DISABLE */
10404 sfttab[i] = mdtmok;
10405 if (mdtmok) sfttab[0]++;
10407 case SFT_MLST: /* ditto */
10408 sfttab[i] = mlstok;
10409 if (mlstok) sfttab[0]++;
10411 case SFT_SIZE: /* ditto */
10412 sfttab[i] = sizeok;
10413 if (sizeok) sfttab[0]++;
10415 case SFT_AUTH: /* ditto */
10416 sfttab[i] = ftp_aut;
10417 if (ftp_aut) sfttab[0]++;
10419 default: /* Others */
10426 parsefacts(s) char * s; { /* Parse MLS[DT] File Facts */
10429 if (!s) return(NULL);
10430 if (!*s) return(NULL);
10432 /* Maybe we should make a copy of s so we can poke it... */
10434 while ((p = ckstrchr(s,'='))) {
10435 *p = NUL; /* s points to fact */
10436 i = xlookup(facttab,s,nfacttab,&x);
10437 debug(F111,"ftp parsefact fact",s,i);
10439 s = p+1; /* Now s points to arg */
10440 p = ckstrchr(s,';');
10442 p = ckstrchr(s,SP);
10444 debug(F110,"ftp parsefact end-of-val search fail",s,0);
10448 debug(F110,"ftp parsefact valu",s,0);
10450 case FACT_CSET: /* Ignore these for now */
10457 case FACT_MDTM: /* Modtime */
10458 makestr(&havemdtm,s);
10459 debug(F110,"ftp parsefact mdtm",havemdtm,0);
10461 case FACT_SIZE: /* Size */
10462 havesize = atol(s);
10463 debug(F101,"ftp parsefact size","",havesize);
10465 case FACT_TYPE: /* Type */
10466 j = xlookup(ftyptab,s,nftyptab,NULL);
10467 debug(F111,"ftp parsefact type",s,j);
10468 havetype = (j < 1) ? 0 : j;
10472 s = p+1; /* s points next fact or name */
10474 while (*s == SP) /* Skip past spaces. */
10476 if (!*s) /* Make sure we still have a name */
10478 debug(F110,"ftp parsefact name",s,0);
10482 /* g e t r e p l y -- (to an FTP command sent to server) */
10484 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10487 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10488 /* lcs, rcs, vbm parameters as in ftpcmd() */
10489 register int i, c, n;
10495 int originalcode = 0, continuation = 0;
10499 char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10503 auth = (fc == GRF_AUTH);
10506 debug(F101,"ftp getreply lcs","",lcs);
10507 debug(F101,"ftp getreply rcs","",rcs);
10508 if (lcs > -1 && rcs > -1 && lcs != rcs) {
10510 initxlate(rcs,lcs);
10511 xlatec(1,0,rcs,lcs);
10513 #endif /* NOCSETS */
10514 debug(F101,"ftp getreply fc","",fc);
10522 if (ftp_deb) /* DEBUG */
10524 else if (quiet || dpyactive) /* QUIET or File Transfer Active */
10526 else if (vbm < 0) /* VERBOSE */
10531 reply_ptr = reply_buf;
10533 oldintr = signal(SIGINT, cmdcancel);
10534 for (count = 0;; count++) {
10536 dig = n = ftpcode = i = 0;
10537 cp = ftp_reply_str;
10538 while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10539 if (c == IAC) { /* Handle telnet commands */
10540 switch (c = mygetc()) {
10549 if (ssl_ftp_active_flag) {
10551 rc = SSL_write(ssl_ftp_con,obuf,3);
10552 error = SSL_get_error(ssl_ftp_con,rc);
10554 case SSL_ERROR_NONE:
10556 case SSL_ERROR_WANT_WRITE:
10557 case SSL_ERROR_WANT_READ:
10559 case SSL_ERROR_SYSCALL:
10560 if (rc == 0) { /* EOF */
10564 int gle = GetLastError();
10568 case SSL_ERROR_WANT_X509_LOOKUP:
10569 case SSL_ERROR_SSL:
10570 case SSL_ERROR_ZERO_RETURN:
10575 #endif /* CK_SSL */
10576 send(csocket,(SENDARG2TYPE)obuf,3,0);
10586 if (ssl_ftp_active_flag) {
10588 rc = SSL_write(ssl_ftp_con,obuf,3);
10589 error = SSL_get_error(ssl_ftp_con,rc);
10591 case SSL_ERROR_NONE:
10593 case SSL_ERROR_WANT_WRITE:
10594 case SSL_ERROR_WANT_READ:
10595 signal(SIGINT,oldintr);
10597 case SSL_ERROR_SYSCALL:
10598 if (rc == 0) { /* EOF */
10602 int gle = GetLastError();
10606 case SSL_ERROR_WANT_X509_LOOKUP:
10607 case SSL_ERROR_SSL:
10608 case SSL_ERROR_ZERO_RETURN:
10613 #endif /* CK_SSL */
10614 send(csocket,(SENDARG2TYPE)obuf,3,0);
10624 signal(SIGINT,oldintr);
10626 debug(F101,"ftp getreply EOF","",ftpcode);
10634 "Service not available, connection closed by server\n");
10637 signal(SIGINT,oldintr);
10639 debug(F101,"ftp getreply EOF","",ftpcode);
10642 if (n == 0) { /* First digit */
10643 n = c; /* Save it */
10647 !ssl_ftp_active_flag &&
10648 #endif /* CK_SSL */
10649 !ibuf[0] && (n == '6' || continuation)) {
10650 if (c != '\r' && dig > 4)
10655 !ssl_ftp_active_flag &&
10656 #endif /* CK_SSL */
10657 !ibuf[0] && dig == 1 && vbm)
10658 printf("Unauthenticated reply received from server:\n");
10663 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
10666 (ftp_deb || ((vbm || (!auth && n == '5')) &&
10667 (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
10671 if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
10672 printf("%s:",ftp_host);
10673 #endif /* FTP_PROXY */
10680 xlatec(0,c,rcs,lcs);
10684 #endif /* NOCSETS */
10691 !ssl_ftp_active_flag &&
10692 #endif /* CK_SSL */
10693 !ibuf[0] && n != '6')
10695 if (dig < 4 && isdigit(c))
10696 ftpcode = ftpcode * 10 + (c - '0');
10697 if (!pflag && ftpcode == 227)
10699 if (dig > 4 && pflag == 1 && isdigit(c))
10702 if (c != '\r' && c != ')')
10709 if (dig == 4 && c == '-' && n != '6') {
10714 if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
10722 Sometimes we need to print the server reply. printlines is nonzero for any
10723 command where the results are sent back on the control connection rather
10724 than the data connection, e.g. STAT. In the TOPS-20 case, each file line
10725 has ftpcode 213. But if you do this with a UNIX server, it sends "213-Start
10726 STAT", <line with ftpcode == 0>, "213-End" or somesuch. So when printlines
10727 is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
10728 lines from UNIX. Further experimentation needed with other servers. Of
10729 course RFC959 is mute as to the format of the server reply.
10731 'printlines' is also true for PWD and BYE.
10733 (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
10735 /* No, we can't be that clever -- it breaks other things like RPWD... */
10737 (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
10738 #endif /* COMMENT */
10741 char *r = ftp_reply_str;
10742 *q-- = NUL; /* NUL-terminate */
10743 while (*q < '!' && q > r) /* Strip CR, etc */
10745 if (!ftp_deb && printlines) { /* If printing */
10746 if (ftpcode != 0) /* strip ftpcode if any */
10749 printf("%s\n",r); /* and print */
10753 } else { /* Translating */
10754 xgnbp = r; /* Set up strgetc() */
10755 while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
10756 if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) { /* (xprintc) */
10757 signal(SIGINT,oldintr);
10763 #endif /* NOCSETS */
10766 debug(F110,"FTP RCVD ",ftp_reply_str,0);
10768 if (fc == GRF_FEAT) { /* Parsing FEAT command response? */
10769 if (count == 0 && n == '2') {
10770 int i; /* (Re)-init server FEATure table */
10771 debug(F100,"ftp getreply clearing feature table","",0);
10772 for (i = 0; i < 16; i++)
10775 parsefeat((char *)ftp_reply_str);
10780 !ssl_ftp_active_flag &&
10781 #endif /* CK_SSL */
10782 !ibuf[0] && n != '6') {
10783 signal(SIGINT,oldintr);
10784 return(getreply(expecteof,lcs,rcs,vbm,auth));
10786 ibuf[0] = obuf[i] = '\0';
10787 if (ftpcode && n == '6')
10788 if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
10789 printf("Unknown reply: %d %s\n", ftpcode, obuf);
10791 } else safe = (ftpcode == 631);
10792 if (obuf[0] /* if there is a string to decode */
10794 && !ssl_ftp_active_flag /* and not SSL/TLS */
10795 #endif /* CK_SSL */
10798 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
10801 #ifndef CK_ENCRYPTION
10802 else if (ftpcode == 632) {
10803 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
10806 #endif /* CK_ENCRYPTION */
10807 #ifdef NOCONFIDENTIAL
10808 else if (ftpcode == 633) {
10809 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
10812 #endif /* NOCONFIDENTIAL */
10814 int len = FTP_BUFSIZ;
10815 if ((kerror = radix_encode((CHAR *)obuf,
10821 printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
10822 ftpcode, radix_error(kerror), obuf);
10826 else if (strcmp(auth_type, "SRP") == 0) {
10828 outlen = srp_decode(!safe, (CHAR *)ibuf,
10829 (CHAR *) ibuf, len);
10831 printf("Warning: %d reply %s!\n",
10832 ftpcode, safe ? "modified" : "garbled");
10835 ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
10837 printf("%c:", safe ? 'S' : 'P');
10841 #endif /* FTP_SRP */
10843 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
10845 kerror = krb_rd_safe((CHAR *)ibuf, len,
10850 #endif /* KRB524 */
10856 kerror = krb_rd_priv((CHAR *)ibuf, len,
10862 #endif /* KRB524 */
10868 if (kerror != KSUCCESS) {
10869 printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
10870 safe ? "modified" : "garbled",
10871 safe ? "safe" : "priv",
10872 krb_get_err_text(kerror));
10874 } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
10877 printf("reply data too large for buffer\n");
10880 printf("%c:", safe ? 'S' : 'P');
10881 memcpy(ibuf,ftp_msg_data.app_data,
10882 ftp_msg_data.app_length);
10883 ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
10884 FTP_BUFSIZ - ftp_msg_data.app_length);
10888 #endif /* FTP_KRB4 */
10890 else if (strcmp(auth_type, "GSSAPI") == 0) {
10891 gss_buffer_desc xmit_buf, msg_buf;
10892 OM_uint32 maj_stat, min_stat;
10894 xmit_buf.value = ibuf;
10895 xmit_buf.length = len;
10896 /* decrypt/verify the message */
10898 maj_stat = gss_unseal(&min_stat, gcontext,
10899 &xmit_buf, &msg_buf,
10900 &conf_state, NULL);
10901 if (maj_stat != GSS_S_COMPLETE) {
10902 user_gss_error(maj_stat, min_stat,
10903 "failed unsealing reply");
10906 memcpy(ibuf, msg_buf.value, msg_buf.length);
10907 ckstrncpy(&ibuf[msg_buf.length], "\r\n",
10908 FTP_BUFSIZ-msg_buf.length);
10909 gss_release_buffer(&min_stat,&msg_buf);
10911 printf("%c:", safe ? 'S' : 'P');
10915 #endif /* FTP_GSSAPI */
10916 /* Other auth types go here... */
10918 } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
10919 !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
10924 xlatec(0,c,rcs,lcs);
10928 #endif /* NOCSETS */
10931 if (continuation && ftpcode != originalcode) {
10932 if (originalcode == 0)
10933 originalcode = ftpcode;
10939 signal(SIGINT,oldintr);
10940 if (ftpcode == 421 || originalcode == 421) {
10942 if (!xquiet && !ftp_deb)
10943 printf("%s\n",reply_buf);
10945 if ((cancelfile != 0) &&
10947 /* Ultrix 3.0 cc objects violently to this clause */
10948 (oldintr != cmdcancel) &&
10949 #endif /* ULTRIX3 */
10950 (oldintr != SIG_IGN)) {
10952 (*oldintr)(SIGINT);
10956 if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
10957 reply_parse = reply_ptr + strlen(reply_parse);
10958 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
10961 reply_parse = reply_ptr;
10963 while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
10965 debug(F111,"ftp getreply",ftp_reply_str,n - '0');
10973 empty(fd_set * mask, int sec)
10975 empty(mask, sec) fd_set * mask; int sec;
10976 #endif /* CK_ANSIC */
10979 t.tv_sec = (long) sec;
10981 debug(F100,"ftp empty calling select...","",0);
10983 x = select(32, (int *)mask, NULL, NULL, &t);
10985 x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
10986 #endif /* INTSELECT */
10987 debug(F101,"ftp empty select","",x);
10990 #else /* BSDSELECT */
10993 empty(mask, cnt, sec) int * mask, sec;
10996 return(select(mask,cnt,0,0,sec*1000));
10998 #endif /* IBMSELECT */
10999 #endif /* BSDSELECT */
11002 cancelsend(sig) int sig; {
11006 printf(" Canceled...\n");
11007 secure_getc(0,1); /* Initialize net input buffers */
11008 debug(F100,"ftp cancelsend caught SIGINT ","",0);
11011 longjmp(sendcancel, 1);
11019 secure_error(char *fmt, ...)
11022 secure_error(fmt, p1, p2, p3, p4, p5)
11023 char *fmt; int p1, p2, p3, p4, p5;
11024 #endif /* CK_ANSIC */
11030 vfprintf(stderr, fmt, ap);
11033 fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11035 fprintf(stderr, "\n");
11039 * Internal form of settype; changes current type in use with server
11040 * without changing our notion of the type for data transfers.
11041 * Used to change to and from ascii for listings.
11044 changetype(newtype, show) int newtype, show; {
11048 if ((newtype == curtype) && typesent++)
11064 rc = ftpcmd("TYPE",s,-1,-1,show);
11065 if (rc == REPLY_COMPLETE)
11069 /* PUT a file. Returns -1 on error, 0 on success, 1 if file skipped */
11073 doftpsend(void * threadinfo)
11075 doftpsend(threadinfo) VOID * threadinfo;
11079 if (threadinfo) { /* Thread local storage... */
11080 TlsSetValue(TlsIndex,threadinfo);
11081 debug(F100, "doftpsend called with threadinfo block","", 0);
11082 } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11091 #endif /* CK_LOGIN */
11096 debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy);
11098 /* If the connection failed and we are using an HTTP Proxy
11099 * and the reason for the failure was an authentication
11100 * error, then we need to give the user to ability to
11101 * enter a username and password, just like a browser.
11103 * I tried to do all of this within the netopen() call
11104 * but it is much too much work.
11106 while (y != 0 && tcp_http_proxy != NULL ) {
11108 if (tcp_http_proxy_errno == 401 ||
11109 tcp_http_proxy_errno == 407 ) {
11110 char uid[UIDBUFLEN];
11112 struct txtbox tb[2];
11116 tb[0].t_len = UIDBUFLEN;
11117 tb[0].t_lbl = "Proxy Userid: ";
11118 tb[0].t_dflt = NULL;
11122 tb[1].t_lbl = "Proxy Passphrase: ";
11123 tb[1].t_dflt = NULL;
11126 ok = uq_mtxt("Proxy Server Authentication Required\n",
11128 if (ok && uid[0]) {
11129 char * proxy_user, * proxy_pwd;
11131 proxy_user = tcp_http_proxy_user;
11132 proxy_pwd = tcp_http_proxy_pwd;
11134 tcp_http_proxy_user = uid;
11135 tcp_http_proxy_pwd = pwd;
11139 debug(F101,"doftpsend","initconn",y);
11140 memset(pwd,0,PWDSIZ);
11141 tcp_http_proxy_user = proxy_user;
11142 tcp_http_proxy_pwd = proxy_pwd;
11150 #endif /* NOHTTP */
11151 signal(SIGINT, ftpsnd.oldintr);
11153 if (ftpsnd.oldintp)
11154 signal(SIGPIPE, ftpsnd.oldintp);
11155 #endif /* SIGPIPE */
11160 ckThreadEnd(threadinfo);
11165 #endif /* NOHTTP */
11169 ckThreadEnd(threadinfo);
11175 failftpsend(void * threadinfo)
11177 failftpsend(threadinfo) VOID * threadinfo;
11178 #endif /* CK_ANSIC */
11181 if (threadinfo) { /* Thread local storage... */
11182 TlsSetValue(TlsIndex,threadinfo);
11183 debug(F100, "docmdfile called with threadinfo block","", 0);
11184 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11193 #endif /* CK_LOGIN */
11196 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11197 debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11201 if (ssl_ftp_data_active_flag) {
11202 SSL_shutdown(ssl_ftp_data_con);
11203 SSL_free(ssl_ftp_data_con);
11204 ssl_ftp_data_active_flag = 0;
11205 ssl_ftp_data_con = NULL;
11207 #endif /* CK_SSL */
11209 socket_close(data);
11210 #else /* TCPIPLIB */
11211 #ifdef USE_SHUTDOWN
11212 shutdown(data, 1+1);
11213 #endif /* USE_SHUTDOWN */
11215 #endif /* TCPIPLIB */
11219 if (ftpsnd.oldintr)
11220 signal(SIGINT,ftpsnd.oldintr);
11222 if (ftpsnd.oldintp)
11223 signal(SIGPIPE,ftpsnd.oldintp);
11224 #endif /* SIGPIPE */
11227 /* TEST ME IN K95 */
11230 debug(F100,"ftp failftpsend chain to trap()...","",0);
11231 if (ftpsnd.oldintr != SIG_IGN)
11232 (*ftpsnd.oldintr)(SIGINT);
11233 /* NOTREACHED (I hope!) */
11234 debug(F100,"ftp failftpsend return from trap()...","",0);
11241 failftpsend2(void * threadinfo)
11243 failftpsend2(threadinfo) VOID * threadinfo;
11244 #endif /* CK_ANSIC */
11247 if (threadinfo) { /* Thread local storage... */
11248 TlsSetValue(TlsIndex,threadinfo);
11249 debug(F100, "docmdfile called with threadinfo block","", 0);
11250 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11259 #endif /* CK_LOGIN */
11261 debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11264 fpfsecs = gftimer();
11265 #endif /* GFTIMER */
11270 #endif /* PIPESEND */
11271 signal(SIGINT, ftpsnd.oldintr);
11273 if (ftpsnd.oldintp)
11274 signal(SIGPIPE, ftpsnd.oldintp);
11275 #endif /* SIGPIPE */
11280 ckThreadEnd(threadinfo);
11286 if (ssl_ftp_data_active_flag) {
11287 SSL_shutdown(ssl_ftp_data_con);
11288 SSL_free(ssl_ftp_data_con);
11289 ssl_ftp_data_active_flag = 0;
11290 ssl_ftp_data_con = NULL;
11292 #endif /* CK_SSL */
11294 socket_close(data);
11295 #else /* TCPIPLIB */
11296 #ifdef USE_SHUTDOWN
11297 shutdown(data, 1+1);
11298 #endif /* USE_SHUTDOWN */
11300 #endif /* TCPIPLIB */
11306 socket_close(dout);
11307 #else /* TCPIPLIB */
11308 #ifdef USE_SHUTDOWN
11309 shutdown(dout, 1+1);
11310 #endif /* USE_SHUTDOWN */
11312 #endif /* TCPIPLIB */
11314 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11319 /* TEST ME IN K95 */
11322 debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11323 if (ftpsnd.oldintr != SIG_IGN)
11324 (*ftpsnd.oldintr)(SIGINT);
11325 /* NOTREACHED (I hope!) */
11326 debug(F100,"ftp failftpsend2 return from trap()...","",0);
11333 doftpsend2(void * threadinfo)
11335 doftpsend2(threadinfo) VOID * threadinfo;
11338 register int c, d = 0;
11339 int n, t, x, notafile, unique = 0;
11343 if (threadinfo) { /* Thread local storage... */
11344 TlsSetValue(TlsIndex,threadinfo);
11345 debug(F100, "doftpsend2 called with threadinfo block","", 0);
11346 } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11355 #endif /* CK_LOGIN */
11357 buf = ftpsndbuf; /* (not on stack) */
11359 unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11360 notafile = sndarray || pipesend;
11363 if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11365 changetype(FTT_BIN,0); /* Change to binary */
11367 /* Ask for remote file's size */
11368 x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11370 if (x == REPLY_COMPLETE) { /* Have ftpsnd.reply */
11371 p = &ftp_reply_str[4]; /* Parse it */
11372 while (isdigit(*p)) {
11373 sendstart = sendstart * 10 + (int)(*p - '0');
11376 if (*p && *p != CR) { /* Bad number */
11377 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11379 } else if (sendstart > fsize) { /* Remote file bigger than local */
11380 debug(F110,"doftpsend2 big size",ckltoa(fsize),sendstart);
11383 /* Local is newer */
11384 debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11385 if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11386 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11387 sendstart = 0L; /* Send the whole file */
11390 changetype(ftp_typ,0); /* Change back to appropriate type */
11391 if (sendstart > 0L) { /* Still restarting? */
11392 if (sendstart == fsize) { /* Same size - no need to send */
11393 debug(F111,"doftpsend2 /restart SKIP",fsize,sendstart);
11395 ftpsndret = SKP_RES;
11397 ckThreadEnd(threadinfo);
11401 errno = 0; /* Restart needed, seek to the spot */
11402 if (zfseek((long)sendstart) < 0) {
11403 debug(F111,"doftpsend2 zfseek fails",
11404 ftpsnd.local,sendstart);
11405 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11410 ckThreadEnd(threadinfo);
11415 debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11416 x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11417 if (x != REPLY_CONTINUE) {
11422 ckThreadEnd(threadinfo);
11426 ftpsnd.cmd = "STOR";
11429 sendmode = SM_RESEND;
11430 ftpsnd.cmd = "APPE";
11431 #endif /* COMMENT */
11432 /* sendstart = 0L; */
11435 #endif /* FTP_RESTART */
11437 if (unique && !stouarg) /* If we know STOU accepts no arg */
11438 ftpsnd.remote = NULL; /* don't include one. */
11440 x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11441 debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11443 if (x != REPLY_PRELIM && unique) {
11445 RFC959 says STOU does not take an argument. But every FTP server
11446 I've encountered but one accepts the arg and constructs the unique
11447 name from it, which is better than making up a totally random name
11448 for the file, which is what RFC959 calls for. Especially because
11449 there is no way for the client to find out the name chosen by the
11450 server. So we try STOU with the argument first, which works with
11451 most servers, and if it fails we retry it without the arg, for
11452 the benefit of the one picky server that is not "liberal in what
11453 it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11454 which means STOU is not accepted, period.
11456 if ((x == 5) && stouarg && (ftpcode != 502)) {
11457 x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11458 if (x == REPLY_PRELIM) /* If accepted */
11459 stouarg = 0; /* flag no STOU arg for this server */
11462 if (x != REPLY_PRELIM) {
11463 signal(SIGINT, ftpsnd.oldintr);
11465 if (ftpsnd.oldintp)
11466 signal(SIGPIPE, ftpsnd.oldintp);
11467 #endif /* SIGPIPE */
11472 #endif /* PIPESEND */
11475 ckThreadEnd(threadinfo);
11479 dout = dataconn(ftpsnd.lmode); /* Get data connection */
11481 failftpsend2(threadinfo);
11483 ckThreadEnd(threadinfo);
11487 /* Initialize per-file stats */
11488 ffc = 0L; /* Character counter */
11489 cps = oldcps = 0L; /* Thruput */
11491 rftimer(); /* reset f.p. timer */
11492 #endif /* GFTIMER */
11495 ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11496 #endif /* SIGPIPE */
11498 case FTT_BIN: /* Binary mode */
11501 while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11504 debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11505 hexdump("doftpsend2 zxin",buf,16);
11507 if (ssl_ftp_data_active_flag) {
11508 for (bufp = buf; n > 0; n -= d, bufp += d) {
11509 if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11513 if (fdispla != XYFD_B) {
11515 ftscreen(SCR_PT,'D',spackets,NULL);
11519 #endif /* CK_SSL */
11520 for (bufp = buf; n > 0; n -= d, bufp += d) {
11521 if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11526 if (fdispla != XYFD_B) {
11528 ftscreen(SCR_PT,'D',spackets,NULL);
11533 #endif /* CK_SSL */
11538 fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11539 if (d < 0 || (d = secure_flush(dout)) < 0) {
11540 if (d == -1 && errno && errno != EPIPE)
11546 case FTT_ASC: /* Text mode */
11548 if (ftpsnd.xlate) { /* With translation */
11549 initxlate(ftpsnd.incs,ftpsnd.outcs);
11550 while (!cancelfile) {
11551 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11552 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11555 #endif /* NOCSETS */
11556 /* Text mode, no translation */
11557 while (((c = zminchar()) > -1) && !cancelfile) {
11565 #endif /* NOCSETS */
11566 if (dout == -1 || (d = secure_flush(dout)) < 0) {
11567 if (d == -1 && errno && errno != EPIPE)
11573 tfc += ffc; /* Total file chars */
11575 fpfsecs = gftimer();
11576 #endif /* GFTIMER */
11577 zclose(ZIFILE); /* Close input file */
11579 if (sndfilter) /* Undo this (it's per file) */
11581 #endif /* PIPESEND */
11584 if (ssl_ftp_data_active_flag) {
11585 SSL_shutdown(ssl_ftp_data_con);
11586 SSL_free(ssl_ftp_data_con);
11587 ssl_ftp_data_active_flag = 0;
11588 ssl_ftp_data_con = NULL;
11590 #endif /* CK_SSL */
11593 socket_close(dout); /* Close data connection */
11594 #else /* TCPIPLIB */
11595 #ifdef USE_SHUTDOWN
11596 shutdown(dout, 1+1);
11597 #endif /* USE_SHUTDOWN */
11599 #endif /* TCPIPLIB */
11600 ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11601 signal(SIGINT, ftpsnd.oldintr); /* Put back interrupts */
11603 if (ftpsnd.oldintp)
11604 signal(SIGPIPE, ftpsnd.oldintp);
11605 #endif /* SIGPIPE */
11606 if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
11607 debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
11610 ckThreadEnd(threadinfo);
11613 } else if (cancelfile) {
11614 debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
11617 ckThreadEnd(threadinfo);
11621 debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
11624 ckThreadEnd(threadinfo);
11629 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
11630 char *cmd, *local, *remote; int xlate, incs, outcs, restart;
11632 if (!remote) remote = ""; /* Check args */
11633 if (!*remote) remote = local;
11634 if (!local) local = "";
11635 if (!*local) return(-1);
11636 if (!cmd) cmd = "";
11637 if (!*cmd) cmd = "STOR";
11639 debug(F111,"ftp sendrequest restart",local,restart);
11641 nout = 0; /* Init output buffer count */
11642 ftpsnd.bytes = 0; /* File input byte count */
11647 proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
11650 #endif /* FTP_PROXY */
11652 changetype(ftp_typ,0); /* Change type for this file */
11654 ftpsnd.oldintr = NULL; /* Set up interrupt handler */
11655 ftpsnd.oldintp = NULL;
11656 ftpsnd.restart = restart;
11657 ftpsnd.xlate = xlate;
11658 ftpsnd.lmode = "wb";
11660 #ifdef PIPESEND /* Use Kermit API for file i/o... */
11662 char * p = NULL, * q;
11665 if (cmd_quoting && (p = (char *) malloc(n + 1))) {
11667 debug(F110,"sendrequest pipesend filter",sndfilter,0);
11668 zzstring(sndfilter,&p,&n);
11669 debug(F111,"sendrequest pipename",q,n);
11671 printf("?Sorry, send filter + filename too long, %d max.\n",
11677 ckstrncpy(filnam,q,CKMAXPATH+1);
11684 if (sndfilter) /* If sending thru a filter */
11685 pipesend = 1; /* set this for open and i/o */
11686 #endif /* PIPESEND */
11688 if (openi(local) == 0) /* Try to open the input file */
11692 ftpsnd.incs = incs;
11693 ftpsnd.outcs = outcs;
11695 ftpsnd.local = local;
11696 ftpsnd.remote = remote;
11697 ftpsnd.oldintr = signal(SIGINT, cancelsend);
11700 if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
11704 if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
11711 cancelrecv(sig) int sig; {
11715 secure_getc(0,1); /* Initialize net input buffers */
11716 printf(" Canceling...\n");
11717 debug(F100,"ftp cancelrecv caught SIGINT","",0);
11720 if (fp_nml != stdout)
11725 longjmp(recvcancel, 1);
11731 /* Argumentless front-end for secure_getc() */
11735 return(secure_getc(globaldin,0));
11738 /* Returns -1 on failure, 0 on success, 1 if file skipped */
11741 Sets ftpcode < 0 on failure if failure reason is not server reply code:
11742 -1: interrupted by user.
11743 -2: error opening or writing output file (reason in errno).
11744 -3: failure to make data connection.
11745 -4: network read error (reason in errno).
11748 struct xx_ftprecv {
11756 sig_t oldintr, oldintp;
11765 static struct xx_ftprecv ftprecv;
11767 static int ftprecvret = 0;
11771 failftprecv(VOID * threadinfo)
11773 failftprecv(threadinfo) VOID * threadinfo;
11774 #endif /* CK_ANSIC */
11777 if (threadinfo) { /* Thread local storage... */
11778 TlsSetValue(TlsIndex,threadinfo);
11779 debug(F100, "docmdfile called with threadinfo block","", 0);
11780 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11790 #endif /* CK_LOGIN */
11793 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
11797 if (ssl_ftp_data_active_flag) {
11798 SSL_shutdown(ssl_ftp_data_con);
11799 SSL_free(ssl_ftp_data_con);
11800 ssl_ftp_data_active_flag = 0;
11801 ssl_ftp_data_con = NULL;
11803 #endif /* CK_SSL */
11805 socket_close(data);
11806 #else /* TCPIPLIB */
11807 #ifdef USE_SHUTDOWN
11808 shutdown(data, 1+1);
11809 #endif /* USE_SHUTDOWN */
11811 #endif /* TCPIPLIB */
11815 if (ftprecv.oldintr)
11816 signal(SIGINT, ftprecv.oldintr);
11821 /* TEST ME IN K95 */
11824 debug(F100,"ftp failftprecv chain to trap()...","",0);
11825 if (ftprecv.oldintr != SIG_IGN)
11826 (*ftprecv.oldintr)(SIGINT);
11827 /* NOTREACHED (I hope!) */
11828 debug(F100,"ftp failftprecv return from trap()...","",0);
11836 doftprecv(VOID * threadinfo)
11838 doftprecv(threadinfo) VOID * threadinfo;
11839 #endif /* CK_ANSIC */
11842 if (threadinfo) { /* Thread local storage... */
11843 TlsSetValue(TlsIndex,threadinfo);
11844 debug(F100, "docmdfile called with threadinfo block","", 0);
11845 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11854 #endif /* CK_LOGIN */
11857 if (!out2screen && !ftprecv.pipename) {
11860 local = ftprecv.local;
11863 if ((!dpyactive || ftp_deb))
11865 "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
11866 signal(SIGINT, ftprecv.oldintr);
11870 ckThreadEnd(threadinfo);
11875 #endif /* COMMENT */
11876 changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
11877 if (initconn()) { /* Initialize the data connection */
11878 signal(SIGINT, ftprecv.oldintr);
11882 ckThreadEnd(threadinfo);
11886 secure_getc(0,1); /* Initialize net input buffers */
11890 ckThreadEnd(threadinfo);
11896 failftprecv2(VOID * threadinfo)
11898 failftprecv2(threadinfo) VOID * threadinfo;
11899 #endif /* CK_ANSIC */
11902 if (threadinfo) { /* Thread local storage... */
11903 TlsSetValue(TlsIndex,threadinfo);
11904 debug(F100, "docmdfile called with threadinfo block","", 0);
11905 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11914 #endif /* CK_LOGIN */
11916 /* Cancel using RFC959 recommended IP,SYNC sequence */
11918 debug(F100,"ftp recvrequest CANCEL","",0);
11920 fpfsecs = gftimer();
11921 #endif /* GFTIMER */
11923 if (ftprecv.oldintp)
11924 signal(SIGPIPE, ftprecv.oldintr);
11925 #endif /* SIGPIPE */
11926 signal(SIGINT, SIG_IGN);
11929 signal(SIGINT, ftprecv.oldintr);
11932 ckThreadEnd(threadinfo);
11936 cancel_remote(ftprecv.din);
11941 if (ssl_ftp_data_active_flag) {
11942 SSL_shutdown(ssl_ftp_data_con);
11943 SSL_free(ssl_ftp_data_con);
11944 ssl_ftp_data_active_flag = 0;
11945 ssl_ftp_data_con = NULL;
11947 #endif /* CK_SSL */
11949 socket_close(data);
11950 #else /* TCPIPLIB */
11951 #ifdef USE_SHUTDOWN
11952 shutdown(data, 1+1);
11953 #endif /* USE_SHUTDOWN */
11955 #endif /* TCPIPLIB */
11961 debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
11963 switch (keep) { /* which is... */
11964 case SET_AUTO: /* AUTO */
11965 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
11968 case SET_OFF: /* DISCARD */
11969 x = 1; /* Delete file, period. */
11971 default: /* KEEP */
11975 x = zdelet(ftprecv.local);
11976 debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
11981 socket_close(ftprecv.din);
11982 #else /* TCPIPLIB */
11983 #ifdef USE_SHUTDOWN
11984 shutdown(ftprecv.din, 1+1);
11985 #endif /* USE_SHUTDOWN */
11986 close(ftprecv.din);
11987 #endif /* TCPIPLIB */
11989 signal(SIGINT, ftprecv.oldintr);
11994 debug(F100,"FTP failftprecv2 chain to trap()...","",0);
11996 debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
11999 if (ftprecv.oldintr != SIG_IGN)
12000 (*ftprecv.oldintr)(SIGINT);
12001 /* NOTREACHED (I hope!) */
12002 debug(F100,"ftp failftprecv2 return from trap()...","",0);
12009 doftprecv2(VOID * threadinfo)
12011 doftprecv2(threadinfo) VOID * threadinfo;
12012 #endif /* CK_ANSIC */
12018 ULONG start = 0L, stop;
12020 static char * rcvbuf = NULL;
12021 static int rcvbufsiz = 0;
12023 char newname[CKMAXPATH+1]; /* For file dialog */
12024 #endif /* CK_URL */
12025 extern int adl_ask;
12029 if (threadinfo) { /* Thread local storage... */
12030 TlsSetValue(TlsIndex,threadinfo);
12031 debug(F100, "docmdfile called with threadinfo block","", 0);
12032 } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12041 #endif /* CK_LOGIN */
12043 if (ftprecv.recover) { /* Initiate recovery */
12044 x = ftpcmd("REST",ckltoa(ftprecv.localsize),-1,-1,ftp_vbm);
12045 debug(F111,"ftp reply","REST",x);
12046 if (x == REPLY_CONTINUE) {
12047 ftprecv.lmode = "ab";
12048 rs_len = ftprecv.localsize;
12050 ftprecv.recover = 0;
12053 /* IMPORTANT: No FTP commands can come between REST and RETR! */
12055 debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12057 /* Send the command and get reply */
12058 debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12059 debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12061 if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12063 signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12064 ftprecvret = -1; /* ftpcode is set by ftpcmd() */
12066 ckThreadEnd(threadinfo);
12070 ftprecv.din = dataconn("r"); /* Good reply, open data connection */
12071 globaldin = ftprecv.din; /* Global copy of file descriptor */
12072 if (ftprecv.din == -1) { /* Check for failure */
12073 ftpcode = -3; /* Code for no data connection */
12076 ckThreadEnd(threadinfo);
12081 /* In K95 GUI put up a file box */
12082 if (haveurl && g_url.pth && adl_ask ) { /* Downloading from a URL */
12085 "\r\nIncoming file from FTP server...\r\n\
12086 Please confirm output file specification or supply an alternative:";
12088 x = uq_file(preface, /* K95 GUI: Put up file box. */
12092 ftprecv.local ? ftprecv.local : ftprecv.remote,
12097 ftprecv.local = newname; /* Substitute user's file name */
12098 if (x == 2) /* And append if user said to */
12099 ftprecv.lmode = "ab";
12102 #endif /* CK_URL */
12103 x = 1; /* Output file open OK? */
12104 if (ftprecv.pipename) { /* Command */
12105 x = zxcmd(ZOFILE,ftprecv.pipename);
12106 debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12107 } else if (!out2screen) { /* File */
12109 xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12110 xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12111 /* Append or New */
12112 xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12113 x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12114 debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12116 if (x < 1) { /* Failure to open output file */
12117 if ((!dpyactive || ftp_deb))
12118 fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12121 ckThreadEnd(threadinfo);
12125 blksize = FTP_BUFSIZ; /* Allocate input buffer */
12127 debug(F101,"ftp recvrequest blksize","",blksize);
12128 debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12130 if (rcvbufsiz < blksize) { /* if necessary */
12135 rcvbuf = (char *)malloc((unsigned)blksize);
12137 debug(F100,"ftp get rcvbuf malloc failed","",0);
12141 #endif /* ENOMEM */
12142 if ((!dpyactive || ftp_deb))
12147 ckThreadEnd(threadinfo);
12151 debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12152 rcvbufsiz = blksize;
12154 debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12156 ffc = 0L; /* Character counter */
12157 cps = oldcps = 0L; /* Thruput */
12158 start = gmstimer(); /* Start time (msecs) */
12160 rftimer(); /* Start time (float) */
12161 #endif /* GFTIMER */
12163 debug(F111,"ftp get type",ftprecv.local,curtype);
12164 debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12166 case FTT_BIN: /* Binary mode */
12167 case FTT_TEN: /* TENEX mode */
12171 c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12173 failftprecv2(threadinfo);
12175 ckThreadEnd(threadinfo);
12181 #ifdef printf /* (What if it isn't?) */
12182 if (out2screen && !ftprecv.pipename) {
12184 for (i = 0; i < c; i++)
12185 printf("%c",rcvbuf[i]);
12187 #endif /* printf */
12193 if (zmchout(rcvbuf[i++]) < 0) {
12203 debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12204 if (c == -1 && errno != EPIPE)
12205 if ((!dpyactive || ftp_deb))
12212 if ((!dpyactive || ftp_deb)) {
12214 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12217 "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12220 "%s: short write\n", ftprecv.local);
12225 case FTT_ASC: /* Text mode */
12226 debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12228 if (ftprecv.xlate) {
12234 #endif /* CK_ANSIC */
12235 debug(F110,"ftp recvrequest (data)","initxlate",0);
12236 initxlate(ftprecv.rcs,ftprecv.fcs); /* (From,To) */
12237 if (ftprecv.pipename) {
12239 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12241 fn = out2screen ? scrnout : putfil;
12242 debug(F110,"ftp recvrequest ASCII",
12243 out2screen ? "scrnout" : "putfil",0);
12246 /* Get byte from net */
12247 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12249 failftprecv2(threadinfo);
12251 ckThreadEnd(threadinfo);
12257 /* Second byte from net */
12258 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12260 failftprecv2(threadinfo);
12262 ckThreadEnd(threadinfo);
12269 /* K95: Check whether we need this */
12270 if (fileorder > 0) /* Little Endian */
12271 bytswap(&c0,&c1); /* swap bytes*/
12272 #endif /* COMMENT */
12275 if ( out2screen && /* we're translating to UCS-2 */
12276 !k95stdout && !inserver) /* for the real screen... */
12283 output.bytes[0] = c1;
12284 output.bytes[1] = c0;
12286 VscrnWrtUCS2StrAtt(VCMD,
12297 if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12298 if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12302 #endif /* NOCSETS */
12304 c = secure_getc(ftprecv.din,0);
12306 failftprecv2(threadinfo);
12308 ckThreadEnd(threadinfo);
12312 if (c < 0 || c == EOF)
12315 /* Record format conversion for Unix */
12316 /* SKIP THIS FOR WINDOWS! */
12319 while (c == '\r') {
12321 if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12324 failftprecv2(threadinfo);
12326 ckThreadEnd(threadinfo);
12330 if (c < 0 || c == EOF)
12342 if (out2screen && !ftprecv.pipename)
12344 printf("%c",(char)c);
12347 #endif /* printf */
12349 if ((d = zmchout(c)) < 0)
12357 if (bare_lfs && (!dpyactive || ftp_deb)) {
12358 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12360 printf("File might not have transferred correctly.\n");
12362 if (ftprecv.din == -1) {
12370 #endif /* NOCSETS */
12372 if (ftprecv.pipename || !out2screen) {
12373 zclose(ZOFILE); /* Close the file */
12374 debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12375 if (ftpcode < 0) { /* If download failed */
12377 switch (keep) { /* which is... */
12378 case SET_AUTO: /* AUTO */
12379 if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12382 case SET_OFF: /* DISCARD */
12383 x = 1; /* Delete file, period. */
12385 default: /* KEEP */
12389 x = zdelet(ftprecv.local);
12390 debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12394 signal(SIGINT, ftprecv.oldintr);
12396 if (ftprecv.oldintp)
12397 signal(SIGPIPE, ftprecv.oldintp);
12398 #endif /* SIGPIPE */
12401 fpfsecs = gftimer();
12402 #endif /* GFTIMER */
12406 socket_close(ftprecv.din);
12407 #else /* TCPIPLIB */
12408 #ifdef USE_SHUTDOWN
12409 shutdown(ftprecv.din, 1+1);
12410 #endif /* USE_SHUTDOWN */
12411 close(ftprecv.din);
12412 #endif /* TCPIPLIB */
12413 ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12414 ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12415 ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12417 ckThreadEnd(threadinfo);
12422 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12424 char *cmd, *local, *remote, *lmode, *pipename;
12425 int printnames, recover, xlate, fcs, rcs;
12428 struct _stat stbuf;
12435 debug(F111,"ftp recvrequest cmd",cmd,recover);
12436 debug(F110,"ftp recvrequest local ",local,0);
12437 debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12438 debug(F110,"ftp recvrequest pipename ",pipename,0);
12439 debug(F101,"ftp recvrequest xlate","",xlate);
12440 debug(F101,"ftp recvrequest fcs","",fcs);
12441 debug(F101,"ftp recvrequest rcs","",rcs);
12445 ftprecv.localsize = 0L;
12447 if (remfile) { /* See remcfm(), remtxt() */
12449 pipename = remdest;
12452 if (remappd) lmode = "ab";
12456 if (!cmd) cmd = ""; /* Core dump prevention */
12457 if (!remote) remote = "";
12458 if (!lmode) lmode = "";
12460 if (pipename) { /* No recovery for pipes. */
12465 if (!local) /* Output to screen? */
12467 out2screen = !strcmp(local,"-");
12469 debug(F101,"ftp recvrequest out2screen","",out2screen);
12472 if ( ftp_xla && out2screen && !k95stdout && !inserver )
12476 if (out2screen) /* No recovery to screen */
12478 if (!ftp_typ) /* No recovery in text mode */
12480 ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12482 if (!ftprecv.is_retr) /* No recovery except for RETRieve */
12486 if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12487 if (recursive && ckstrchr(local,'/')) {
12491 #endif /* COMMENT */
12493 ftprecv.localsize = 0L; /* Local file size */
12494 rs_len = 0L; /* Recovery point */
12496 debug(F101,"ftp recvrequest recover","",recover);
12497 if (recover) { /* Recovering... */
12498 if (stat(local, &stbuf) < 0) { /* Can't stat local file */
12499 debug(F101,"ftp recvrequest recover stat failed","",errno);
12500 recover = 0; /* So cancel recovery */
12501 } else { /* Have local file info */
12502 ftprecv.localsize = stbuf.st_size; /* Get size */
12503 /* Remote file smaller than local */
12504 if (fsize < ftprecv.localsize) {
12505 debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12506 recover = 0; /* Recovery can't work */
12507 } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12508 debug(F111,"ftp recvrequest recover equal size",
12509 remote,ftprecv.localsize);
12514 The problem here is that the original partial file never got its date
12515 set, either because FTP DATES was OFF, or because the partial file was
12516 downloaded by some other program that doesn't set local file dates, or
12517 because Kermit only sets the file's date when the download was complete
12518 and successful. In all these cases, the local file has a later time
12521 if (recover) { /* Remote is bigger */
12522 x = chkmodtime(local,remote,0); /* Check file dates */
12523 debug(F111,"ftp recvrequest chkmodtime",remote,x);
12524 if (x != 1) /* Dates must be equal! */
12525 recover = 0; /* If not, get whole file */
12527 #endif /* COMMENT */
12529 debug(F111,"ftp recvrequest recover",remote,recover);
12533 if (proxy && ftprecv.is_retr)
12534 return(proxtrans(cmd, local ? local : remote, remote));
12535 #endif /* FTP_PROXY */
12537 ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
12542 ftprecv.recover = recover;
12543 ftprecv.xlate = xlate;
12545 ftprecv.local = local;
12546 ftprecv.remote = remote;
12547 ftprecv.lmode = lmode;
12548 ftprecv.pipename = pipename;
12549 ftprecv.oldintp = NULL;
12553 ftprecv.oldintr = signal(SIGINT, cancelrecv);
12554 if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
12556 if (ftprecvret < 0)
12559 if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
12565 * Need to start a listen on the data channel before we send the command,
12566 * otherwise the server's connect may fail.
12570 register char *p, *a;
12571 int result, tmpno = 0;
12575 #ifndef NO_PASSIVE_MODE
12576 int a1,a2,a3,a4,p1,p2;
12579 data = socket(AF_INET, SOCK_STREAM, 0);
12582 perror("ftp: socket");
12585 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
12586 printf("Passive mode refused\n");
12588 return(initconn());
12591 Now we have a string of comma-separated one-byte unsigned integer values,
12592 The first four are the an IP address. The fifth is the MSB of the port
12593 number, the sixth is the LSB. From that we can make a sockaddr_in.
12595 if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
12596 printf("Passive mode address scan failure\n");
12600 if (tcp_http_proxy) {
12602 char * agent = "Kermit 95"; /* Default user agent */
12604 char * agent = "C-Kermit";
12606 register struct hostent *hp = 0;
12607 struct servent *destsp;
12608 char host[512], *p, *q;
12610 #ifdef IPTOS_THROUGHPUT
12612 #endif /* IPTOS_THROUGHPUT */
12613 #endif /* IP_TOS */
12622 ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
12623 ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
12626 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
12627 for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
12631 hisctladdr.sin_addr.s_addr = inet_addr(host);
12632 if (hisctladdr.sin_addr.s_addr != -1) {
12633 debug(F110,"initconn A",host,0);
12634 hisctladdr.sin_family = AF_INET;
12636 debug(F110,"initconn B",host,0);
12637 hp = gethostbyname(host);
12639 hp = ck_copyhostent(hp); /* make safe copy that won't change */
12640 #endif /* HADDRLIST */
12642 fprintf(stderr, "ftp: %s: Unknown host\n", host);
12649 hisctladdr.sin_family = hp->h_addrtype;
12651 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
12652 sizeof(hisctladdr.sin_addr));
12653 #else /* HADDRLIST */
12654 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
12655 sizeof(hisctladdr.sin_addr));
12656 #endif /* HADDRLIST */
12658 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
12659 debug(F101,"initconn socket","",data);
12661 perror("ftp: socket");
12673 destsp = getservbyname(p,"tcp");
12675 hisctladdr.sin_port = destsp->s_port;
12677 hisctladdr.sin_port = htons(atoi(p));
12679 hisctladdr.sin_port = htons(80);
12682 debug(F100,"initconn HADDRLIST","",0);
12685 debug(F100,"initconn no HADDRLIST","",0);
12687 #endif /* HADDRLIST */
12688 (connect(data, (struct sockaddr *)&hisctladdr,
12689 sizeof (hisctladdr)) < 0) {
12690 debug(F101,"initconn connect failed","",errno);
12692 if (hp && hp->h_addr_list[1]) {
12693 int oerrno = errno;
12696 "ftp: connect to address %s: ",
12697 inet_ntoa(hisctladdr.sin_addr)
12702 memcpy((char *)&hisctladdr.sin_addr,
12703 hp->h_addr_list[0],
12704 sizeof(hisctladdr.sin_addr));
12705 fprintf(stdout, "Trying %s...\n",
12706 inet_ntoa(hisctladdr.sin_addr));
12708 socket_close(data);
12709 #else /* TCPIPLIB */
12711 #endif /* TCPIPLIB */
12712 data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
12714 perror("ftp: socket");
12723 #endif /* HADDRLIST */
12724 perror("ftp: connect");
12728 if (http_connect(data,
12729 tcp_http_proxy_agent ?
12730 tcp_http_proxy_agent :
12733 tcp_http_proxy_user,
12734 tcp_http_proxy_pwd,
12739 socket_close(data);
12740 #else /* TCPIPLIB */
12742 #endif /* TCPIPLIB */
12743 perror("ftp: connect");
12748 #endif /* NOHTTP */
12750 data_addr.sin_family = AF_INET;
12751 data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
12752 data_addr.sin_port = htons((p1<<8)|p2);
12755 (struct sockaddr *)&data_addr,
12756 sizeof(data_addr)) < 0
12758 perror("ftp: connect");
12762 debug(F100,"initconn connect ok","",0);
12764 #ifdef IPTOS_THROUGHPUT
12765 on = IPTOS_THROUGHPUT;
12766 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
12767 perror("ftp: setsockopt TOS (ignored)");
12768 #endif /* IPTOS_THROUGHPUT */
12769 #endif /* IP_TOS */
12770 memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
12773 #endif /* NO_PASSIVE_MODE */
12776 memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
12778 data_addr.sin_port = 0; /* let system pick one */
12781 socket_close(data);
12782 #else /* TCPIPLIB */
12783 #ifdef USE_SHUTDOWN
12784 shutdown(data, 1+1);
12785 #endif /* USE_SHUTDOWN */
12787 #endif /* TCPIPLIB */
12789 data = socket(AF_INET, SOCK_STREAM, 0);
12792 perror("ftp: socket");
12798 if (setsockopt(data,
12805 perror("ftp: setsockopt (reuse address)");
12809 if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
12810 perror("ftp: bind");
12813 len = sizeof (data_addr);
12814 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
12815 perror("ftp: getsockname");
12818 if (listen(data, 1) < 0) {
12819 perror("ftp: listen");
12823 a = (char *)&data_addr.sin_addr;
12824 p = (char *)&data_addr.sin_port;
12825 ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
12826 UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
12827 UC(p[0]),",", UC(p[1]));
12828 result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
12829 if (result == REPLY_ERROR && sendport) {
12834 return(result != REPLY_COMPLETE);
12839 #ifdef IPTOS_THROUGHPUT
12840 on = IPTOS_THROUGHPUT;
12841 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
12842 perror("ftp: setsockopt TOS (ignored)");
12848 socket_close(data);
12849 #else /* TCPIPLIB */
12850 #ifdef USE_SHUTDOWN
12851 shutdown(data, 1+1);
12852 #endif /* USE_SHUTDOWN */
12854 #endif /* TCPIPLIB */
12865 if (ssl_ftp_data_con!=NULL) { /* Do SSL */
12866 SSL_free(ssl_ftp_data_con);
12867 ssl_ftp_data_con=NULL;
12869 ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
12871 SSL_set_fd(ssl_ftp_data_con,data);
12872 SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
12874 SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
12876 if (ssl_debug_flag) {
12877 fprintf(stderr,"=>START SSL connect on DATA\n");
12880 if (SSL_connect(ssl_ftp_data_con) <= 0) {
12881 static char errbuf[1024];
12882 ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
12883 ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
12884 fprintf(stderr,"%s\n", errbuf);
12887 socket_close(data);
12888 #else /* TCPIPLIB */
12889 #ifdef USE_SHUTDOWN
12890 shutdown(data, 1+1);
12891 #endif /* USE_SHUTDOWN */
12893 #endif /* TCPIPLIB */
12898 ssl_ftp_data_active_flag=1;
12900 if (!ssl_certsok_flag && !tls_is_krb5(2)) {
12901 char *subject = ssl_get_subject_name(ssl_ftp_data_con);
12904 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
12905 debug(F110,"dataconn","[SSL _- FAILED]",0);
12907 ssl_ftp_data_active_flag = 0;
12909 socket_close(data);
12910 #else /* TCPIPLIB */
12911 #ifdef USE_SHUTDOWN
12912 shutdown(data, 1+1);
12913 #endif /* USE_SHUTDOWN */
12915 #endif /* TCPIPLIB */
12920 if (!out2screen && displa && fdispla) {
12921 ftscreen(SCR_TC,0,0L,"Display canceled");
12922 /* fdispla = XYFD_B; */
12926 "Warning: Server didn't provide a certificate on data connection\n",
12927 "Continue with file transfer? (Y/N)",
12929 debug(F110, "dataconn","[SSL - FAILED]",0);
12930 ssl_ftp_data_active_flag = 0;
12932 socket_close(data);
12933 #else /* TCPIPLIB */
12934 #ifdef USE_SHUTDOWN
12935 shutdown(data, 1+1);
12936 #endif /* USE_SHUTDOWN */
12938 #endif /* TCPIPLIB */
12945 if (!out2screen && displa && fdispla == XYFD_C) {
12946 ftscreen(SCR_TC,0,0L,"Display canceled");
12947 /* fdispla = XYFD_B; */
12950 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
12951 debug(F110,"dataconn","[SSL - FAILED]",0);
12952 ssl_ftp_data_active_flag = 0;
12954 socket_close(data);
12955 #else /* TCPIPLIB */
12956 #ifdef USE_SHUTDOWN
12957 shutdown(data, 1+1);
12958 #endif /* USE_SHUTDOWN */
12960 #endif /* TCPIPLIB */
12967 debug(F110,"dataconn","[SSL - OK]",0);
12969 /* This messes up the full screen file transfer display */
12970 ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
12971 #endif /* COMMENT */
12973 if (ssl_debug_flag) {
12974 fprintf(stderr,"=>DONE SSL connect on DATA\n");
12979 #endif /* CK_SSL */
12982 dataconn(lmode) char *lmode; {
12986 #endif /* IP_TOS */
12988 static u_int fromlen;
12990 static SOCKOPT_T fromlen;
12993 fromlen = sizeof(hisdataaddr);
12995 #ifndef NO_PASSIVE_MODE
12998 ssl_ftp_data_active_flag=0;
12999 if (ssl_ftp_active_flag &&
13000 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13001 return(ssl_dataconn());
13002 #endif /* CK_SSL */
13005 #endif /* NO_PASSIVE_MODE */
13007 s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13009 perror("ftp: accept");
13011 socket_close(data);
13012 #else /* TCPIPLIB */
13013 #ifdef USE_SHUTDOWN
13014 shutdown(data, 1+1);
13015 #endif /* USE_SHUTDOWN */
13017 #endif /* TCPIPLIB */
13023 socket_close(data);
13024 #else /* TCPIPLIB */
13025 #ifdef USE_SHUTDOWN
13026 shutdown(data, 1+1);
13027 #endif /* USE_SHUTDOWN */
13029 #endif /* TCPIPLIB */
13033 #ifdef IPTOS_THROUGHPUT
13034 tos = IPTOS_THROUGHPUT;
13035 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13036 perror("ftp: setsockopt TOS (ignored)");
13037 #endif /* IPTOS_THROUGHPUT */
13038 #endif /* IP_TOS */
13041 ssl_ftp_data_active_flag=0;
13042 if (ssl_ftp_active_flag &&
13043 (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13044 return(ssl_dataconn());
13045 #endif /* CK_SSL */
13051 pscancel(sig) int sig; {
13056 pswitch(flag) int flag; {
13059 static struct comvars {
13061 char name[MAXHOSTNAMELEN];
13062 struct sockaddr_in mctl;
13063 struct sockaddr_in hctl;
13076 char mi[CKMAXPATH];
13077 char mo[CKMAXPATH];
13082 des_cblock session;
13083 des_key_schedule ftp_sched;
13084 #endif /* FTP_KRB4 */
13086 gss_ctx_id_t gcontext;
13087 #endif /* GSSAPI */
13088 } proxstruct, tmpstruct;
13089 struct comvars *ip, *op;
13092 oldintr = signal(SIGINT, pscancel);
13106 ip->connect = connected;
13107 connected = op->connect;
13109 strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13110 ip->name[MAXHOSTNAMELEN - 1] = '\0';
13111 ip->name[strlen(ip->name)] = '\0';
13114 ftp_host = op->name;
13115 ip->hctl = hisctladdr;
13116 hisctladdr = op->hctl;
13117 ip->mctl = myctladdr;
13118 myctladdr = op->mctl;
13125 ip->curtpe = curtype;
13126 curtype = op->curtpe;
13129 ip->sunqe = ftp_usn;
13130 ftp_usn = op->sunqe;
13133 ip->ntflg = ntflag;
13134 ntflag = op->ntflg;
13135 strncpy(ip->nti, ntin, 16);
13136 (ip->nti)[strlen(ip->nti)] = '\0';
13137 strcpy(ntin, op->nti);
13138 strncpy(ip->nto, ntout, 16);
13139 (ip->nto)[strlen(ip->nto)] = '\0';
13140 strcpy(ntout, op->nto);
13141 ip->mapflg = mapflag;
13142 mapflag = op->mapflg;
13143 strncpy(ip->mi, mapin, CKMAXPATH - 1);
13144 (ip->mi)[strlen(ip->mi)] = '\0';
13145 strcpy(mapin, op->mi);
13146 strncpy(ip->mo, mapout, CKMAXPATH - 1);
13147 (ip->mo)[strlen(ip->mo)] = '\0';
13148 strcpy(mapout, op->mo);
13149 ip->authtype = auth_type;
13150 auth_type = op->authtype;
13151 ip->clvl = ftp_cpl;
13152 ftp_cpl = op->clvl;
13153 ip->dlvl = ftp_dpl;
13154 ftp_dpl = op->dlvl;
13160 memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13161 memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13162 memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13163 memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13164 #endif /* FTP_KRB4 */
13166 ip->gcontext = gcontext;
13167 gcontext = op->gcontext;
13168 #endif /* GSSAPI */
13169 signal(SIGINT, oldintr);
13172 debug(F101,"pswitch cancelfile B","",cancelfile);
13173 (*oldintr)(SIGINT);
13178 cancelpt(sig) int sig; {
13184 longjmp(ptcancel, 1);
13191 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13193 int secndflag = 0, prox_type, nfnd;
13197 #endif /* BSDSELECT */
13198 sigtype cancelpt();
13200 if (strcmp(cmd, "RETR"))
13203 cmd2 = unique ? "STOU" : "STOR";
13204 if ((prox_type = type) == 0) {
13205 if (servertype == SYS_UNIX && unix_proxy)
13206 prox_type = FTT_BIN;
13208 prox_type = FTT_ASC;
13210 if (curtype != prox_type)
13211 changetype(prox_type, 1);
13212 if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13213 printf("Proxy server does not support third party transfers.\n");
13218 printf("No primary connection\n");
13223 if (curtype != prox_type)
13224 changetype(prox_type, 1);
13226 if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13231 /* Replace with calls to cc_execute() */
13232 if (setjmp(ptcancel))
13234 oldintr = signal(SIGINT, cancelpt);
13235 if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13236 signal(SIGINT, oldintr);
13243 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13246 getreply(0,-1,-1,ftp_vbm,0);
13248 getreply(0,-1,-1,ftp_vbm,0);
13249 signal(SIGINT, oldintr);
13255 signal(SIGINT, SIG_IGN);
13257 if (strcmp(cmd, "RETR") && !proxy)
13259 else if (!strcmp(cmd, "RETR") && proxy)
13261 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
13262 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13270 signal(SIGINT, oldintr);
13276 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
13277 if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13284 signal(SIGINT, oldintr);
13294 FD_SET(csocket, &mask);
13295 if ((nfnd = empty(&mask, 10)) <= 0) {
13303 #else /* BSDSELECT */
13305 if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13313 #endif /* IBMSELECT */
13314 #endif /* BSDSELECT */
13315 getreply(0,-1,-1,ftp_vbm,0);
13316 getreply(0,-1,-1,ftp_vbm,0);
13323 signal(SIGINT, oldintr);
13325 #endif /* FTP_PROXY */
13327 #ifdef FTP_SECURITY
13331 CONST gss_OID_desc * CONST * mech_type;
13332 char *service_name;
13334 { &gss_mech_krb5, "ftp" },
13335 { &gss_mech_krb5, "host" },
13338 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13339 #endif /* FTP_GSSAPI */
13343 extern int setsafe();
13346 char *service, inst[INST_SZ];
13348 ULONG checksum = (ULONG) getpid();
13349 CHAR out_buf[FTP_BUFSIZ];
13351 #else /* FTP_KRB4 */
13353 CHAR out_buf[FTP_BUFSIZ];
13355 #endif /* FTP_GSSAPI */
13356 #endif /* FTP_KRB4 */
13358 if (ssl_ftp_proxy) /* Do not allow AUTH over SSL proxy */
13362 return(1); /* auth already succeeded */
13364 /* Try each auth type as specified by the end user */
13365 for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13367 if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13368 n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13369 if (n == REPLY_CONTINUE) {
13370 OM_uint32 maj_stat, min_stat;
13371 gss_name_t target_name;
13372 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13373 char stbuf[FTP_BUFSIZ];
13374 int comcode, trial;
13375 struct gss_channel_bindings_struct chan;
13376 char * realm = NULL;
13379 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13380 chan.initiator_address.length = 4;
13381 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13382 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13383 chan.acceptor_address.length = 4;
13384 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13385 chan.application_data.length = 0;
13386 chan.application_data.value = 0;
13389 printf("GSSAPI accepted as authentication type\n");
13391 realm = ck_krb5_realmofhost(ftp_user_host);
13393 ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13394 debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13395 if ( krb5_autoget &&
13396 !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13397 (ck_krb5_is_tgt_valid() > 0)) )
13398 ck_krb5_autoget_TGT(realm);
13401 /* Blob from gss-client */
13402 for (trial = 0; trial < n_gss_trials; trial++) {
13403 /* ftp@hostname first, the host@hostname */
13404 /* the V5 GSSAPI binding canonicalizes this for us... */
13405 ckmakmsg(stbuf,FTP_BUFSIZ,
13406 gss_trials[trial].service_name,
13413 "Authenticating to <%s>...\n", stbuf);
13414 send_tok.value = stbuf;
13415 send_tok.length = strlen(stbuf);
13416 maj_stat = gss_import_name(&min_stat, &send_tok,
13417 gss_nt_service_name,
13420 if (maj_stat != GSS_S_COMPLETE) {
13421 user_gss_error(maj_stat, min_stat, "parsing name");
13422 secure_error("name parsed <%s>\n", stbuf);
13425 token_ptr = GSS_C_NO_BUFFER;
13426 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13430 fprintf(stderr, "calling gss_init_sec_context\n");
13432 gss_init_sec_context(&min_stat,
13433 GSS_C_NO_CREDENTIAL,
13437 gss_trials[trial].mech_type,
13438 GSS_C_MUTUAL_FLAG |
13439 GSS_C_REPLAY_FLAG |
13441 GSS_C_DELEG_FLAG : 0),
13443 /* channel bindings */
13444 (krb5_d_no_addresses ?
13445 GSS_C_NO_CHANNEL_BINDINGS :
13448 NULL, /* ignore mech type */
13450 NULL, /* ignore ret_flags */
13452 ); /* ignore time_rec */
13454 if (maj_stat != GSS_S_COMPLETE &&
13455 maj_stat != GSS_S_CONTINUE_NEEDED) {
13456 if (trial == n_gss_trials-1)
13457 user_gss_error(maj_stat,
13459 "initializing context"
13461 gss_release_name(&min_stat, &target_name);
13462 /* maybe we missed on the service name */
13465 if (send_tok.length != 0) {
13467 reply_parse = "ADAT="; /* for ftpcmd() later */
13470 radix_encode(send_tok.value,
13478 "Base 64 encoding failed: %s\n",
13479 radix_error(kerror)
13481 goto gss_complete_loop;
13483 comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13484 if (comcode != REPLY_COMPLETE
13485 && comcode != REPLY_CONTINUE /* (335) */
13487 if (trial == n_gss_trials-1) {
13488 fprintf(stderr, "GSSAPI ADAT failed\n");
13489 /* force out of loop */
13490 maj_stat = GSS_S_FAILURE;
13493 Backoff to the v1 gssapi is still possible.
13494 Send a new AUTH command. If that fails,
13495 terminate the loop.
13497 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
13498 != REPLY_CONTINUE) {
13500 "GSSAPI ADAT failed, AUTH restart failed\n");
13501 /* force out of loop */
13502 maj_stat = GSS_S_FAILURE;
13506 if (!reply_parse) {
13508 "No authentication data received from server\n");
13509 if (maj_stat == GSS_S_COMPLETE) {
13511 "...but no more was needed\n");
13512 goto gss_complete_loop;
13514 user_gss_error(maj_stat,
13518 goto gss_complete_loop;
13522 kerror = radix_encode(reply_parse,out_buf,i,&len,
13526 "Base 64 decoding failed: %s\n",
13527 radix_error(kerror));
13528 goto gss_complete_loop;
13531 /* everything worked */
13532 token_ptr = &recv_tok;
13533 recv_tok.value = out_buf;
13534 recv_tok.length = len;
13537 /* get out of loop clean */
13539 trial = n_gss_trials-1;
13540 gss_release_buffer(&min_stat, &send_tok);
13541 gss_release_name(&min_stat, &target_name);
13544 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
13547 if (maj_stat == GSS_S_COMPLETE)
13550 if (maj_stat == GSS_S_COMPLETE) {
13551 printf("GSSAPI authentication succeeded\n");
13552 reply_parse = NULL;
13553 auth_type = "GSSAPI";
13556 fprintf(stderr, "GSSAPI authentication failed\n");
13557 reply_parse = NULL;
13561 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
13562 if (ftpcode == 500 || ftpcode == 502)
13566 #endif /* FTP_GSSAPI */
13568 if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
13569 if (srp_ftp_auth(ftp_user_host,NULL,NULL))
13571 else if (ftpcode == 500 || ftpcode == 502)
13574 #endif /* FTP_SRP */
13576 if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
13577 n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
13578 if (n == REPLY_CONTINUE) {
13579 char tgt[4*REALM_SZ+1];
13583 printf("KERBEROS_V4 accepted as authentication type\n");
13584 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
13585 ckstrncpy(ftp_realm,
13586 (char *)ck_krb4_realmofhost(ftp_user_host),
13590 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
13591 rc = ck_krb4_tkt_isvalid(tgt);
13593 if (rc <= 0 && krb4_autoget)
13594 ck_krb4_autoget_TGT(ftp_realm);
13597 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
13598 if (kerror == KDC_PR_UNKNOWN) {
13600 kerror = krb_mk_req(&ftp_tkt,
13608 fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
13609 krb_get_err_text(kerror));
13611 kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
13613 fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
13614 krb_get_err_text(kerror));
13618 rc = des_key_sched(ftp_cred.session, ftp_sched);
13620 printf("?Invalid DES key specified in credentials\r\n");
13621 debug(F110,"ftp_auth",
13622 "invalid DES Key specified in credentials",0);
13623 } else if ( rc == -2 ) {
13624 printf("?Weak DES key specified in credentials\r\n");
13625 debug(F110,"ftp_auth",
13626 "weak DES Key specified in credentials",0);
13627 } else if ( rc != 0 ) {
13628 printf("?DES Key Schedule not set by credentials\r\n");
13629 debug(F110,"ftp_auth",
13630 "DES Key Schedule not set by credentials",0);
13632 reply_parse = "ADAT=";
13634 kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
13637 fprintf(stderr, "Base 64 encoding failed: %s\n",
13638 radix_error(kerror));
13641 if (i > FTP_BUFSIZ - 6)
13642 printf("?ADAT data too long\n");
13643 if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
13645 fprintf(stderr, "Kerberos V4 authentication failed\n");
13648 if (!reply_parse) {
13650 "No authentication data received from server\n");
13653 i = sizeof(out_buf);
13655 radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
13657 fprintf(stderr, "Base 64 decoding failed: %s\n",
13658 radix_error(kerror));
13661 kerror = krb_rd_safe(out_buf, i,
13666 #endif /* KRB524 */
13672 fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
13673 krb_get_err_text(kerror));
13677 /* fetch the (modified) checksum */
13678 memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
13679 if (ntohl(cksum) == checksum + 1) {
13681 printf("Kerberos V4 authentication succeeded\n");
13682 reply_parse = NULL;
13683 auth_type = "KERBEROS_V4";
13687 "Kerberos V4 mutual authentication failed\n");
13689 reply_parse = NULL;
13694 "KERBEROS_V4 rejected as an authentication type\n");
13695 if (ftpcode == 500 || ftpcode == 502)
13699 #endif /* FTP_KRB4 */
13701 if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
13704 ftpcmd("HOST",ftp_user_host,0,0,0);
13707 #endif /* FTPHOST */
13708 n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
13709 if (n != REPLY_COMPLETE)
13710 n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
13711 if (n == REPLY_COMPLETE) {
13713 printf("TLS accepted as authentication type\n");
13717 if (ssl_ftp_active_flag ) {
13722 fprintf(stderr,"TLS authentication failed\n");
13725 socket_close(csocket);
13726 #else /* TCPIPLIB */
13727 #ifdef USE_SHUTDOWN
13728 shutdown(csocket, 1+1);
13729 #endif /* USE_SHUTDOWN */
13731 #endif /* TCPIPLIB */
13733 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
13738 fprintf(stderr,"TLS rejected as an authentication type\n");
13739 if (ftpcode == 500 || ftpcode == 502)
13743 if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
13746 ftpcmd("HOST",ftp_user_host,0,0,0);
13749 #endif /* FTPHOST */
13750 n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
13751 if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
13753 printf("SSL accepted as authentication type\n");
13756 if (ssl_ftp_active_flag) {
13762 fprintf(stderr,"SSL authentication failed\n");
13765 socket_close(csocket);
13766 #else /* TCPIPLIB */
13767 #ifdef USE_SHUTDOWN
13768 shutdown(csocket, 1+1);
13769 #endif /* USE_SHUTDOWN */
13771 #endif /* TCPIPLIB */
13773 if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
13778 fprintf(stderr, "SSL rejected as an authentication type\n");
13779 if (ftpcode == 500 || ftpcode == 502)
13783 #endif /* CK_SSL */
13784 /* Other auth types go here ... */
13788 #endif /* FTP_SECURITY */
13792 setprotbuf(unsigned int size)
13794 setprotbuf(size) unsigned int size;
13795 #endif /* CK_ANSIC */
13802 while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
13808 ucbufsiz = actualbuf - FUDGE_FACTOR;
13809 debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
13810 if (ucbufsiz < 128) {
13811 printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
13812 } else if (ucbufsiz < 0) {
13813 printf("ERROR: ucbuf allocation failure\n");
13816 maxbuf = actualbuf;
13822 setpbsz(unsigned int size)
13824 setpbsz(size) unsigned int size;
13825 #endif /* CK_ANSIC */
13827 if (!setprotbuf(size)) {
13828 perror("?Error while trying to malloc PROT buffer:");
13831 #endif /* FTP_SRP */
13835 reply_parse = "PBSZ=";
13836 ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
13838 ssl_ftp_active_flag ? "0" :
13839 #endif /* CK_SSL */
13840 ckuitoa(actualbuf),NULL,NULL);
13841 if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
13843 printf("?Unable to negotiate PROT buffer size with FTP server\n");
13849 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
13850 maxbuf = actualbuf;
13852 maxbuf = actualbuf;
13853 ucbufsiz = maxbuf - FUDGE_FACTOR;
13854 debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
13855 reply_parse = NULL;
13860 cancel_remote(din) int din; {
13861 CHAR buf[FTP_BUFSIZ];
13865 #endif /* BSDSELECT */
13867 int fds[2], fdcnt = 0;
13868 #endif /* IBMSELECT */
13875 debug(F100,"ftp cancel_remote entry","",0);
13877 if (ssl_ftp_active_flag) {
13879 * Send Telnet IP, Telnet DM but do so inline and within the
13890 count = SSL_write(ssl_ftp_con, buf, 4);
13891 debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
13892 error = SSL_get_error(ssl_ftp_con,count);
13893 debug(F111,"ftp cancel_remote","SSL_get_error()",error);
13895 case SSL_ERROR_NONE:
13897 case SSL_ERROR_WANT_WRITE:
13898 case SSL_ERROR_WANT_READ:
13899 case SSL_ERROR_SYSCALL:
13902 int gle = GetLastError();
13905 case SSL_ERROR_WANT_X509_LOOKUP:
13906 case SSL_ERROR_SSL:
13907 case SSL_ERROR_ZERO_RETURN:
13913 #endif /* CK_SSL */
13916 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
13917 * after urgent byte rather than before as is protocol now.
13923 if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
13925 debug(F101,"ftp cancel_remote send 1","",x);
13927 x = send(csocket,(SENDARG2TYPE)buf,1,0);
13928 debug(F101,"ftp cancel_remote send 2","",x);
13930 x = scommand("ABOR");
13931 debug(F101,"ftp cancel_remote scommand","",x);
13934 FD_SET(csocket, &mask);
13936 FD_SET(din, &mask);
13938 nfnd = empty(&mask, 10);
13939 debug(F101,"ftp cancel_remote empty","",nfnd);
13947 #endif /* FTP_PROXY */
13950 debug(F110,"ftp cancel_remote","D",0);
13951 if (din && FD_ISSET(din, &mask)) {
13952 /* Security: No threat associated with this read. */
13953 /* But you can't simply read the TLS data stream */
13955 if (ssl_ftp_data_active_flag) {
13957 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
13960 #endif /* CK_SSL */
13962 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
13966 debug(F110,"ftp cancel_remote","E",0);
13967 #else /* BSDSELECT */
13975 nfnd = empty(fds, fdcnt, 10);
13976 debug(F101,"ftp cancel_remote empty","",nfnd);
13984 #endif /* FTP_PROXY */
13987 debug(F110,"ftp cancel_remote","D",0);
13988 if (din && select(&din, 1,0,0,1) ) {
13990 if (ssl_ftp_data_active_flag) {
13992 while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
13995 #endif /* CK_SSL */
13997 while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14001 debug(F110,"ftp cancel_remote","E",0);
14002 #else /* IBMSELECT */
14003 Some form of select is required.
14004 #endif /* IBMSELECT */
14005 #endif /* BSDSELECT */
14006 if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14007 debug(F110,"ftp cancel_remote","F",0);
14008 /* 552 needed for NIC style cancel */
14009 getreply(0,-1,-1,ftp_vbm,0);
14010 debug(F110,"ftp cancel_remote","G",0);
14012 debug(F110,"ftp cancel_remote","H",0);
14013 getreply(0,-1,-1,ftp_vbm,0);
14014 debug(F110,"ftp cancel_remote","I",0);
14021 fts_dpl(x) int x; {
14024 || !ck_crypt_is_installed()
14029 printf("?Cannot set protection level to PRIVATE\n");
14032 printf("?Cannot set protection level to SAFE\n");
14040 if (x == FPL_SAF &&
14041 (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14042 printf("Cannot set protection level to safe\n");
14045 #endif /* CK_SSL */
14046 /* Start with a PBSZ of 1 meg */
14047 if (x != FPL_CLR) {
14048 if (setpbsz(DEFAULT_PBSZ) < 0)
14051 y = ftpcmd(x == FPL_CLR ? "PROT C" :
14052 (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14053 if (y == REPLY_COMPLETE) {
14061 fts_cpl(x) int x; {
14064 || !ck_crypt_is_installed()
14069 printf("?Cannot set protection level to PRIVATE\n");
14072 printf("?Cannot set protection level to SAFE\n");
14078 if (x == FPL_CLR) {
14079 y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14080 if (y == REPLY_COMPLETE) {
14092 user_gss_error(maj_stat, min_stat, s)
14093 OM_uint32 maj_stat, min_stat;
14096 /* a lot of work just to report the error */
14097 OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14098 gss_buffer_desc msg;
14101 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14107 if ((gmaj_stat == GSS_S_COMPLETE)||
14108 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14109 fprintf(stderr, "GSSAPI error major: %s\n",
14111 gss_release_buffer(&gmin_stat, &msg);
14113 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14118 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14124 if ((gmaj_stat == GSS_S_COMPLETE)||
14125 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14126 fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14127 gss_release_buffer(&gmin_stat, &msg);
14129 if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14132 fprintf(stderr, "GSSAPI error: %s\n", s);
14134 #endif /* FTP_GSSAPI */
14142 #endif /* HPUX5WINTCP */
14143 #endif /* datageneral */
14144 #endif /* NOMHHOST */
14147 static struct in_addr inaddrx;
14148 #endif /* INADDRX */
14151 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14152 register struct hostent *hp = 0;
14154 #ifdef IPTOS_THROUGHPUT
14156 #endif /* IPTOS_THROUGHPUT */
14157 #endif /* IP_TOS */
14160 static char hostnamebuf[MAXHOSTNAMELEN];
14161 char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14171 if (tcp_http_proxy) {
14172 struct servent *destsp;
14175 ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14176 for (p = tcp_http_proxy, q = hostname;
14177 *p != '\0' && *p != ':';
14188 destsp = getservbyname(p,"tcp");
14190 cport = ntohs(destsp->s_port);
14196 #endif /* NOHTTP */
14198 ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14201 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14202 hisctladdr.sin_addr.s_addr = inet_addr(host);
14203 if (hisctladdr.sin_addr.s_addr != -1) {
14204 debug(F110,"ftp hookup A",hostname,0);
14205 hisctladdr.sin_family = AF_INET;
14206 ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14208 debug(F110,"ftp hookup B",hostname,0);
14209 hp = gethostbyname(hostname);
14211 hp = ck_copyhostent(hp); /* make safe copy that won't change */
14212 #endif /* HADDRLIST */
14214 fprintf(stderr, "ftp: %s: Unknown host\n", host);
14219 return((char *) 0);
14221 hisctladdr.sin_family = hp->h_addrtype;
14223 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14224 sizeof(hisctladdr.sin_addr));
14225 #else /* HADDRLIST */
14226 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14227 sizeof(hisctladdr.sin_addr));
14228 #endif /* HADDRLIST */
14229 ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14231 debug(F110,"ftp hookup C",hostnamebuf,0);
14232 ftp_host = hostnamebuf;
14233 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14234 debug(F101,"ftp hookup socket","",s);
14236 perror("ftp: socket");
14243 hisctladdr.sin_port = htons(cport);
14246 debug(F100,"ftp hookup HADDRLIST","",0);
14249 debug(F100,"ftp hookup no HADDRLIST","",0);
14251 #endif /* HADDRLIST */
14252 (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14253 debug(F101,"ftp hookup connect failed","",errno);
14255 if (hp && hp->h_addr_list[1]) {
14256 int oerrno = errno;
14258 fprintf(stderr, "ftp: connect to address %s: ",
14259 inet_ntoa(hisctladdr.sin_addr));
14261 perror((char *) 0);
14263 memcpy((char *)&hisctladdr.sin_addr,
14264 hp->h_addr_list[0],
14265 sizeof(hisctladdr.sin_addr));
14266 fprintf(stdout, "Trying %s...\n",
14267 inet_ntoa(hisctladdr.sin_addr));
14270 #else /* TCPIPLIB */
14272 #endif /* TCPIPLIB */
14273 s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14275 perror("ftp: socket");
14284 #endif /* HADDRLIST */
14285 perror("ftp: connect");
14289 debug(F100,"ftp hookup connect ok","",0);
14291 len = sizeof (myctladdr);
14293 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14294 debug(F101,"ftp hookup getsockname failed","",errno);
14295 perror("ftp: getsockname");
14299 debug(F100,"ftp hookup getsockname ok","",0);
14302 if (tcp_http_proxy) {
14304 char * agent = "Kermit 95"; /* Default user agent */
14306 char * agent = "C-Kermit";
14309 if (http_connect(s,agent,NULL,
14310 tcp_http_proxy_user,
14311 tcp_http_proxy_pwd,
14318 #else /* TCPIPLIB */
14320 #endif /* TCPIPLIB */
14322 while (foo == NULL && tcp_http_proxy != NULL ) {
14324 if (tcp_http_proxy_errno == 401 ||
14325 tcp_http_proxy_errno == 407 ) {
14326 char uid[UIDBUFLEN];
14328 struct txtbox tb[2];
14332 tb[0].t_len = UIDBUFLEN;
14333 tb[0].t_lbl = "Proxy Userid: ";
14334 tb[0].t_dflt = NULL;
14338 tb[1].t_lbl = "Proxy Passphrase: ";
14339 tb[1].t_dflt = NULL;
14342 ok = uq_mtxt("Proxy Server Authentication Required\n",
14345 if (ok && uid[0]) {
14346 char * proxy_user, * proxy_pwd;
14348 proxy_user = tcp_http_proxy_user;
14349 proxy_pwd = tcp_http_proxy_pwd;
14351 tcp_http_proxy_user = uid;
14352 tcp_http_proxy_pwd = pwd;
14354 foo = ftp_hookup(host, port, 0);
14356 debug(F110,"ftp_hookup()",foo,0);
14357 memset(pwd,0,PWDSIZ);
14358 tcp_http_proxy_user = proxy_user;
14359 tcp_http_proxy_pwd = proxy_pwd;
14367 perror("ftp: connect");
14371 ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14373 #endif /* NOHTTP */
14380 * If the connection is over an SSL proxy then the
14381 * auth_type will be NULL. However, I'm not sure
14382 * whether we should protect the data channel in
14383 * that case or not.
14386 debug(F100,"ftp hookup use_tls","",0);
14388 debug(F100,"ftp hookup ssl_auth failed","",0);
14396 #endif /* CK_SSL */
14399 #ifdef IPTOS_LOWDELAY
14400 tos = IPTOS_LOWDELAY;
14401 if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14402 perror("ftp: setsockopt TOS (ignored)");
14406 printf("Connected to %s.\n", host);
14408 /* Read greeting from server */
14409 if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14410 debug(F100,"ftp hookup bad reply","",0);
14412 socket_close(csocket);
14413 #else /* TCPIPLIB */
14415 #endif /* TCPIPLIB */
14419 #ifdef SO_OOBINLINE
14423 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14425 perror("ftp: setsockopt");
14426 debug(F101,"ftp hookup setsockopt failed","",errno);
14430 debug(F100,"ftp hookup setsockopt ok","",0);
14433 #endif /* SO_OOBINLINE */
14441 debug(F100,"ftp hookup bad","",0);
14444 #else /* TCPIPLIB */
14446 #endif /* TCPIPLIB */
14458 /* The purpose of the initial REST 0 is not clear, but other FTP */
14459 /* clients do it. In any case, failure of this command is not a */
14460 /* reliable indication that the server does not support Restart. */
14464 n = ftpcmd("REST 0",NULL,0,0,0);
14465 if (n == REPLY_COMPLETE)
14469 printf("WARNING: Unable to restore file pointer.\n");
14470 #endif /* COMMENT */
14472 n = ftpcmd("SYST",NULL,0,0,0); /* Get server system type */
14473 if (n == REPLY_COMPLETE) {
14474 register char *cp, c = NUL;
14475 cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14477 cp = ckstrchr(ftp_reply_str+4,'\r');
14481 c = *cp; /* Save this char */
14482 *cp = '\0'; /* Replace it with NUL */
14485 printf("Remote system type is %s.\n",ftp_reply_str+4);
14486 ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
14487 if (cp) /* Put back saved char */
14490 alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
14492 if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
14493 else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
14494 else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
14495 else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
14496 else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
14497 else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
14498 else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
14502 if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
14503 #endif /* FTP_PROXY */
14505 if (ftp_cmdlin && xfermode == XMODE_M)
14506 ftp_typ = binary; /* Type given on command line */
14507 else /* Otherwise set it automatically */
14508 ftp_typ = alike ? FTT_BIN : FTT_ASC;
14509 changetype(ftp_typ,0); /* Change to this type */
14510 g_ftp_typ = ftp_typ; /* Make it the global type */
14512 printf("Default transfer mode is %s\n",
14513 ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
14515 for (i = 0; i < 16; i++) /* Init server FEATure table */
14518 n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
14520 if (n != REPLY_COMPLETE)
14521 printf("WARNING: Server does not accept MODE S(TREAM)\n");
14522 #endif /* COMMENT */
14523 n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
14525 if (n != REPLY_COMPLETE)
14526 printf("WARNING: Server does not accept STRU F(ILE)\n");
14527 #endif /* COMMENT */
14529 n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
14530 if (n == REPLY_COMPLETE) {
14531 debug(F101,"ftp_init FEAT","",sfttab[0]);
14532 if (deblog || ftp_deb) {
14534 for (i = 1; i < 16 && i < nfeattab; i++) {
14535 debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
14537 printf(" Server %s %s\n",
14538 sfttab[i] ? "supports" : "does not support",
14542 /* Deal with disabled MLST opts here if necessary */
14543 /* But why would it be? */
14551 ftp_login(host) char * host; { /* (also called from ckuusy.c) */
14552 static char ftppass[PASSBUFSIZ]="";
14553 char tmp[PASSBUFSIZ];
14554 char *user = NULL, *pass = NULL, *acct = NULL;
14556 extern char uidbuf[];
14557 extern char pwbuf[];
14558 extern int pwflg, pwcrypt;
14560 debug(F111,"ftp_login",ftp_logname,ftp_log);
14562 if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
14564 if (!ckstrcmp(ftp_logname,"ftp",-1,0))
14568 if (auth_type && !strcmp(auth_type, "SRP")) {
14573 #endif /* FTP_SRP */
14575 user = "anonymous";
14576 if (ftp_tmp) { /* They gave a password */
14578 } else if (ftp_apw) { /* SET FTP ANONYMOUS-PASSWORD */
14580 } else { /* Supply user@host */
14581 ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
14584 debug(F110,"ftp anonymous",pass,0);
14586 #ifdef USE_RUSERPASS
14587 if (ruserpass(host, &user, &pass, &acct) < 0) {
14591 #endif /* USE_RUSERPASS */
14593 user = ftp_logname;
14595 } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
14599 } else if (pwbuf[0] && pwflg) {
14600 ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
14603 ck_encrypt((char *)ftppass);
14609 while (user == NULL) {
14610 char *myname, prompt[PROMPTSIZ];
14615 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
14616 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
14618 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
14621 ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
14622 DEFAULT_UQ_TIMEOUT);
14623 if (!ok || *tmp == '\0')
14626 user = brstrip(tmp);
14629 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
14630 if (n == REPLY_COMPLETE) {
14631 /* determine if we need to send a dummy password */
14632 if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
14633 ftpcmd("PASS dummy",NULL,0,0,1);
14634 } else if (n == REPLY_CONTINUE) {
14635 #ifdef CK_ENCRYPTION
14637 #endif /* CK_ENCRYPTION */
14639 if (pass == NULL) {
14642 ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
14643 DEFAULT_UQ_TIMEOUT);
14645 pass = brstrip(ftppass);
14648 #ifdef CK_ENCRYPTION
14649 oldftp_cpl = ftp_cpl;
14651 #endif /* CK_ENCRYPTION */
14652 n = ftpcmd("PASS",pass,-1,-1,1);
14653 if (!anonymous && pass) {
14655 while (*p++) *(p-1) = NUL;
14656 makestr(&ftp_tmp,NULL);
14658 #ifdef CK_ENCRYPTION
14659 /* level may have changed */
14660 if (ftp_cpl == FPL_PRV)
14661 ftp_cpl = oldftp_cpl;
14662 #endif /* CK_ENCRYPTION */
14664 if (n == REPLY_CONTINUE) {
14666 if (acct == NULL) {
14667 static char ftpacct[80];
14670 ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
14671 DEFAULT_UQ_TIMEOUT);
14673 acct = brstrip(ftpacct);
14675 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
14677 if (n != REPLY_COMPLETE) {
14678 fprintf(stderr, "FTP login failed.\n");
14680 doexit(BAD_EXIT,-1);
14683 if (!aflag && acct != NULL) {
14684 ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
14686 makestr(&ftp_logname,user);
14689 /* Unprefixed file management commands go to server */
14690 if (autolocus && !ftp_cmdlin) {
14696 if (anonymous && !quiet) {
14697 printf(" Logged in as anonymous (%s)\n",pass);
14698 memset(pass, 0, strlen(pass));
14701 if (doftpcwd(ftp_rdir,-1) < 1)
14702 doexit(BAD_EXIT,-1);
14708 #endif /* FTP_PROXY */
14720 FD_SET(csocket, &mask);
14721 if ((nfnd = empty(&mask,0)) < 0) {
14727 getreply(0,-1,-1,ftp_vbm,0);
14730 #else /* BSDSELECT */
14734 if ((nfnd = empty(&csocket,1,0)) < 0) {
14740 getreply(0,-1,-1,ftp_vbm,0);
14743 #endif /* IBMSELECT */
14744 #endif /* BSDSELECT */
14745 rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
14752 ftp_rename(from, to) char * from, * to; {
14753 int lcs = -1, rcs = -1;
14757 if (lcs < 0) lcs = fcharset;
14759 if (rcs < 0) rcs = ftp_csr;
14761 #endif /* NOCSETS */
14762 if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
14763 return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
14765 return(0); /* Failure */
14769 ftp_umask(mask) char * mask; {
14771 rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
14776 ftp_user(user,pass,acct) char * user, * pass, * acct; {
14777 int n = 0, aflag = 0;
14780 if (!auth_type && ftp_aut) {
14782 if (ck_srp_is_installed()) {
14783 if (srp_ftp_auth( NULL, user, pass)) {
14784 makestr(&pass,srp_pass);
14787 #endif /* FTP_SRP */
14789 n = ftpcmd("USER",user,-1,-1,ftp_vbm);
14790 if (n == REPLY_COMPLETE)
14791 n = ftpcmd("PASS dummy",NULL,0,0,1);
14792 else if (n == REPLY_CONTINUE) {
14793 #ifdef CK_ENCRYPTION
14795 #endif /* CK_ENCRYPTION */
14796 if (pass == NULL || !pass[0]) {
14800 ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
14801 DEFAULT_UQ_TIMEOUT);
14803 pass = brstrip(pwd);
14806 #ifdef CK_ENCRYPTION
14807 if ((oldftp_cpl = ftp_cpl) == PROT_S)
14809 #endif /* CK_ENCRYPTION */
14810 n = ftpcmd("PASS",pass,-1,-1,1);
14811 memset(pass, 0, strlen(pass));
14812 #ifdef CK_ENCRYPTION
14813 /* level may have changed */
14814 if (ftp_cpl == PROT_P)
14815 ftp_cpl = oldftp_cpl;
14816 #endif /* CK_ENCRYPTION */
14818 if (n == REPLY_CONTINUE) {
14819 if (acct == NULL || !acct[0]) {
14823 ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
14824 DEFAULT_UQ_TIMEOUT);
14828 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
14831 if (n != REPLY_COMPLETE) {
14832 printf("Login failed.\n");
14835 if (!aflag && acct != NULL && acct[0]) {
14836 n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
14838 if (n == REPLY_COMPLETE) {
14839 makestr(&ftp_logname,user);
14851 return(auth_type ? auth_type : "NULL");
14864 return("confidential");
14880 return("confidential");
14887 /* remote_files() */
14889 Returns next remote filename on success;
14890 NULL on error or no more files with global rfrc set to:
14892 -2: Server error response to NLST, e.g. file not found
14896 #define FTPNAMBUFLEN CKMAXPATH+1024
14898 /* Check: ckmaxfiles CKMAXOPEN */
14900 #define MLSDEPTH 128 /* Stack of open temp files */
14901 static int mlsdepth = 0; /* Temp file stack depth */
14902 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
14903 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
14906 mlsreset() { /* Reset MGET temp-file stack */
14908 for (i = 0; i <= mlsdepth; i++) {
14909 if (tmpfilptr[i]) {
14910 fclose(tmpfilptr[i]);
14911 tmpfilptr[i] = NULL;
14912 if (tmpfilnam[i]) {
14914 unlink(tmpfilnam[i]);
14916 free(tmpfilnam[i]);
14925 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
14926 #else /* CK_ANSIC */
14927 remote_files(new_query, arg, pattern, proxy_switch)
14929 CHAR * arg; /* That we send to the server */
14930 CHAR * pattern; /* That we use locally */
14932 #endif /* CK_ANSIC */
14933 /* remote_files */ {
14934 static CHAR buf[FTPNAMBUFLEN];
14935 CHAR *cp, *whicharg;
14936 char * cdto = NULL;
14938 int i, x, forced = 0;
14939 int lcs = 0, rcs = 0, xlate = 0;
14941 debug(F101,"ftp remote_files new_query","",new_query);
14942 debug(F110,"ftp remote_files arg",arg,0);
14943 debug(F110,"ftp remote_files pattern",pattern,0);
14946 if (pattern) /* Treat empty pattern same as NULL */
14949 if (arg) /* Ditto for arg */
14956 if (tmpfilptr[mlsdepth]) {
14957 fclose(tmpfilptr[mlsdepth]);
14958 tmpfilptr[mlsdepth] = NULL;
14960 if (!ftp_deb && !deblog)
14961 unlink(tmpfilnam[mlsdepth]);
14965 if (tmpfilptr[mlsdepth] == NULL) {
14966 extern char * tempdir;
14968 debug(F110,"ftp remote_files tempdir",tempdir,0);
14974 p = getenv("K95TMP");
14976 p = getenv("K2TMP");
14980 p = getenv("CK_TMP");
14982 p = getenv("TMPDIR");
14983 if (!p) p = getenv("TEMP");
14984 if (!p) p = getenv("TMP");
14987 int len = strlen(p);
14988 if (p[len-1] != '/'
14990 && p[len-1] != '\\'
14993 static char foo[CKMAXPATH];
14994 ckstrncpy(foo,p,CKMAXPATH);
14995 ckstrncat(foo,"/",CKMAXPATH);
14999 #else /* OS2ORUNIX */
15001 #endif /* OS2ORUNIX */
15002 #ifdef UNIX /* Systems that have a standard */
15003 p = "/tmp/"; /* temporary directory... */
15009 #endif /* datageneral */
15012 debug(F110,"ftp remote_files p",p,0);
15014 /* Get temp file */
15016 if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15017 ckmakmsg((char *)tmpfilnam[mlsdepth],
15018 CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15020 printf("?Malloc failure: remote_files()\n");
15026 char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15028 ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15033 x = mkstemp((char *)tmpfilnam[mlsdepth]);
15034 if (x > -1) close(x); /* We just want the name. */
15036 mktemp((char *)tmpfilnam[mlsdepth]);
15037 #endif /* MKSTEMP */
15038 /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15039 #endif /* MKTEMP */
15042 debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15043 tmpfilnam[mlsdepth],mlsdepth);
15046 if (proxy_switch) {
15049 #endif /* FTP_PROXY */
15051 debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15052 debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15053 debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15056 xlate = ftp_xla; /* SET FTP CHARACTER-SET-TRANSLATION */
15057 if (xlate) { /* ON? */
15058 lcs = ftp_csl; /* Local charset */
15059 if (lcs < 0) lcs = fcharset;
15060 if (lcs < 0) xlate = 0;
15062 if (xlate) { /* Still ON? */
15063 rcs = ftp_csx; /* Remote (Server) charset */
15064 if (rcs < 0) rcs = ftp_csr;
15065 if (rcs < 0) xlate = 0;
15067 #endif /* NOCSETS */
15069 forced = mgetforced; /* MGET method forced? */
15070 if (!forced || !mgetmethod) /* Not forced... */
15071 mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15075 User's Command: Result:
15076 mget /nlst NLST (NULL)
15077 mget /nlst foo NLST foo
15078 mget /nlst *.txt NLST *.txt
15079 mget /nlst /match:*.txt NLST (NULL)
15080 mget /nlst /match:*.txt foo NLST foo
15081 mget /mlsd MLSD (NULL)
15082 mget /mlsd foo MLSD foo
15083 mget /mlsd *.txt MLSD (NULL)
15084 mget /mlsd /match:*.txt MLSD (NULL)
15085 mget /mlsd /match:*.txt foo MLSD foo
15089 if (pattern) { /* Don't simplify this! */
15091 } else if (mgetmethod == SND_MLS) {
15093 whicharg = iswild((char *)arg) ? NULL : arg;
15099 debug(F110,"ftp remote_files mgetmethod",
15100 mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15101 debug(F110,"ftp remote_files whicharg",whicharg,0);
15103 x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15104 (char *)tmpfilnam[mlsdepth],
15114 if (x < 0) { /* Chosen method wasn't accepted */
15116 if (ftpcode > 500 && ftpcode < 505 && !quiet)
15117 printf("?%s: Not supported by server\n",
15118 mgetmethod == SND_MLS ? "MLSD" : "NLST"
15120 rfrc = -2; /* Fail */
15123 /* Not forced - if MLSD failed, try NLST */
15124 if (mgetmethod == SND_MLS) { /* Server lied about MLST */
15125 sfttab[SFT_MLST] = 0; /* So disable it */
15126 mlstok = 0; /* and */
15127 mgetmethod = SND_NLS; /* try NLST */
15135 if (proxy_switch) {
15138 #endif /* FTP_PROXY */
15139 tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15141 if (tmpfilptr[mlsdepth]) {
15142 if (!ftp_deb && !deblog)
15143 unlink(tmpfilnam[mlsdepth]);
15147 if (!tmpfilptr[mlsdepth]) {
15148 debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15149 if ((!dpyactive || ftp_deb))
15150 printf("?Can't find list of remote files, oops\n");
15155 printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15158 buf[FTPNAMBUFLEN-1] = NUL;
15159 buf[FTPNAMBUFLEN-2] = NUL;
15161 /* We have to redo all this because the first time was only for */
15162 /* for getting the file list, now it's for getting each file */
15164 if (arg && mgetmethod == SND_MLS) { /* MLSD */
15165 if (!pattern && iswild((char *)arg)) {
15166 pattern = arg; /* Wild arg is really a pattern */
15170 arg = NULL; /* and not an arg */
15172 if (new_query) { /* Initial query? */
15173 cdto = (char *)arg; /* (nonwild) arg given? */
15177 if (cdto) /* If so, then CD to it */
15183 if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15184 fclose(tmpfilptr[mlsdepth]);
15185 tmpfilptr[mlsdepth] = NULL;
15188 if (!ftp_deb && !deblog)
15189 unlink(tmpfilnam[mlsdepth]);
15191 if (ftp_deb && !deblog) {
15192 printf("(Temporary file %s NOT deleted)\n",
15193 (char *)tmpfilnam[mlsdepth]);
15195 if (mlsdepth <= 0) { /* EOF at depth 0 */
15196 rfrc = -3; /* means we're done */
15199 printf("POPPING(%d)...\n",mlsdepth-1);
15200 if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15203 zchdir(".."); /* <-- Not portable */
15206 if (buf[FTPNAMBUFLEN-1]) {
15207 printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15210 debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15213 /* debug(F110,"ftp remote_files buf 1",buf,0); */
15214 if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15216 if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15218 debug(F110,"ftp remote_files buf",buf,0);
15222 printf("[%s]\n",(char *)buf);
15224 havesize = -1L; /* Initialize file facts... */
15226 makestr(&havemdtm,NULL);
15229 if (mgetmethod == SND_NLS) { /* NLST... */
15231 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15234 } else { /* MLSD... */
15235 p = parsefacts((char *)buf);
15236 switch (havetype) {
15237 case FTYP_FILE: /* File: Get it if it matches */
15239 if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15243 case FTYP_CDIR: /* Current directory */
15244 case FTYP_PDIR: /* Parent directory */
15245 goto again; /* Skip */
15246 case FTYP_DIR: /* (Sub)Directory */
15247 if (!recursive) /* If not /RECURSIVE */
15248 goto again; /* Skip */
15249 if (mlsdepth < MLSDEPTH) {
15252 printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15253 if (doftpcwd(p,0) > 0) {
15255 if (!ckstrchr(p,'/')) {
15256 /* zmkdir() needs dirsep */
15257 if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15258 strcpy(p2,p); /* SAFE */
15259 strcat(p2,"/"); /* SAFE */
15267 #endif /* NOMKDIR */
15270 p = (char *)remote_files(1,arg,pattern,0);
15273 printf("?mkdir failed: [%s] Depth=%d\n",
15282 printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15287 printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15298 debug(F101,"remote_files havesize","",havesize);
15299 debug(F101,"remote_files havetype","",havetype);
15300 debug(F110,"remote_files havemdtm",havemdtm,0);
15301 debug(F110,"remote_files name",p,0);
15307 /* N O T P O R T A B L E !!! */
15309 #if (SIZEOF_SHORT == 4)
15310 typedef unsigned short ftp_uint32;
15311 typedef short ftp_int32;
15313 #if (SIZEOF_INT == 4)
15314 typedef unsigned int ftp_uint32;
15315 typedef int ftp_int32;
15317 #if (SIZEOF_LONG == 4)
15318 typedef ULONG ftp_uint32;
15319 typedef long ftp_int32;
15324 /* Perhaps use these in general, certainly use them for GSSAPI */
15326 #ifndef looping_write
15327 #define ftp_int32 int
15328 #define ftp_uint32 unsigned int
15330 looping_write(fd, buf, len)
15332 register CONST char *buf;
15336 register int wrlen = len;
15338 cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15340 if (errno == EINTR)
15347 } while (wrlen > 0);
15351 #ifndef looping_read
15353 looping_read(fd, buf, len)
15355 register char *buf;
15361 cc = recv(fd, (char *)buf, len,0);
15363 if (errno == EINTR)
15365 return(cc); /* errno is already set */
15366 } else if (cc == 0) {
15376 #endif /* looping_read */
15382 secure_putbyte(fd, c) int fd; CHAR c; {
15386 if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15388 if (!ftpissecure())
15389 ret = send(fd, (SENDARG2TYPE)ucbuf,
15390 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15392 ret = secure_putbuf(fd,
15394 (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15400 #endif /* COMMENT */
15404 * -1 on error (errno set)
15405 * -2 on security error
15408 secure_flush(fd) int fd; {
15414 if (!ftpissecure()) {
15415 rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15419 rc = secure_putbuf(fd, ucbuf, nout);
15424 rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15427 if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15430 ftscreen(SCR_PT,'D',spackets,NULL);
15435 #ifdef COMMENT /* (not used) */
15439 * -2 on security error
15443 secure_putc(char c, int fd)
15445 secure_putc(c, fd) char c; int fd;
15446 #endif /* CK_ANSIC */
15447 /* secure_putc */ {
15448 return(secure_putbyte(fd, (CHAR) c));
15450 #endif /* COMMENT */
15454 * -1 on error (errno set)
15455 * -2 on security error
15459 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15461 secure_write(fd, buf, nbyte)
15464 unsigned int nbyte;
15465 #endif /* CK_ANSIC */
15469 if (!ftpissecure()) {
15471 if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15475 return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15477 int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
15480 while (bsent < nbyte) {
15481 int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
15482 (ucbuflen - nout) : (nbyte - bsent));
15485 debug(F101,"secure_write ucbuflen","",ucbuflen);
15486 debug(F101,"secure_write ucbufsiz","",ucbufsiz);
15487 debug(F101,"secure_write bsent","",bsent);
15488 debug(F101,"secure_write b2cp","",b2cp);
15491 memcpy(&ucbuf[nout],&buf[bsent],b2cp);
15495 if (nout == ucbuflen) {
15497 ret = secure_putbuf(fd, ucbuf, ucbuflen);
15508 * -1 on error (errno set)
15509 * -2 on security error
15513 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
15515 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
15516 #endif /* CK_ANSIC */
15518 static char *outbuf = NULL; /* output ciphertext */
15519 #ifdef FTP_SECURITY
15520 static unsigned int bufsize = 0; /* size of outbuf */
15521 #endif /* FTP_SECURITY */
15522 ftp_int32 length = 0;
15523 ftp_uint32 net_len = 0;
15525 /* Other auth types go here ... */
15527 if (ssl_ftp_data_active_flag) {
15530 /* there is no need to send an empty buffer when using SSL/TLS */
15534 count = SSL_write(ssl_ftp_data_con, buf, nbyte);
15535 error = SSL_get_error(ssl_ftp_data_con,count);
15537 case SSL_ERROR_NONE:
15539 case SSL_ERROR_WANT_WRITE:
15540 case SSL_ERROR_WANT_READ:
15541 case SSL_ERROR_SYSCALL:
15544 int gle = GetLastError();
15547 debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
15550 case SSL_ERROR_WANT_X509_LOOKUP:
15551 case SSL_ERROR_SSL:
15552 case SSL_ERROR_ZERO_RETURN:
15554 SSL_shutdown(ssl_ftp_data_con);
15555 SSL_free(ssl_ftp_data_con);
15556 ssl_ftp_data_active_flag = 0;
15557 ssl_ftp_data_con = NULL;
15559 socket_close(data);
15560 #else /* TCPIPLIB */
15561 #ifdef USE_SHUTDOWN
15562 shutdown(data, 1+1);
15563 #endif /* USE_SHUTDOWN */
15565 #endif /* TCPIPLIB */
15572 #endif /* CK_SSL */
15575 if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
15576 if (bufsize < nbyte + FUDGE_FACTOR) {
15578 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
15579 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
15580 bufsize = nbyte + FUDGE_FACTOR;
15583 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
15588 srp_encode(ftp_dpl == FPL_PRV,
15594 secure_error ("srp_encode failed");
15598 #endif /* FTP_SRP */
15600 if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
15601 struct sockaddr_in myaddr, hisaddr;
15603 len = sizeof(myaddr);
15604 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
15605 secure_error("secure_putbuf: getsockname failed");
15608 len = sizeof(hisaddr);
15609 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
15610 secure_error("secure_putbuf: getpeername failed");
15613 if (bufsize < nbyte + FUDGE_FACTOR) {
15615 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
15616 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
15617 bufsize = nbyte + FUDGE_FACTOR;
15620 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
15624 if (ftp_dpl == FPL_PRV) {
15625 length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
15631 #endif /* KRB524 */
15636 length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
15641 #endif /* KRB524 */
15646 if (length == -1) {
15647 secure_error("krb_mk_%s failed for KERBEROS_V4",
15648 ftp_dpl == FPL_PRV ? "priv" : "safe");
15652 #endif /* FTP_KRB4 */
15654 if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
15655 gss_buffer_desc in_buf, out_buf;
15656 OM_uint32 maj_stat, min_stat;
15659 in_buf.value = buf;
15660 in_buf.length = nbyte;
15661 maj_stat = gss_seal(&min_stat, gcontext,
15662 (ftp_dpl == FPL_PRV), /* confidential */
15668 if (maj_stat != GSS_S_COMPLETE) {
15669 /* generally need to deal */
15670 /* ie. should loop, but for now just fail */
15671 user_gss_error(maj_stat, min_stat,
15672 ftp_dpl == FPL_PRV?
15673 "GSSAPI seal failed":
15674 "GSSAPI sign failed");
15677 if (bufsize < out_buf.length) {
15679 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
15680 (outbuf = malloc((unsigned) out_buf.length))) {
15681 bufsize = out_buf.length;
15684 secure_error("%s (in malloc of PROT buffer)",
15689 memcpy(outbuf, out_buf.value, length=out_buf.length);
15690 gss_release_buffer(&min_stat, &out_buf);
15692 #endif /* FTP_GSSAPI */
15693 net_len = htonl((ULONG) length);
15694 if (looping_write(fd, (char *)&net_len, 4) == -1)
15696 if (looping_write(fd, outbuf, length) != length)
15701 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
15704 secure_getbyte(fd,fc) int fd,fc; {
15705 /* number of chars in ucbuf, pointer into ucbuf */
15706 static unsigned int nin = 0, bufp = 0;
15719 if (ssl_ftp_data_active_flag) {
15721 count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
15722 error = SSL_get_error(ssl_ftp_data_con,count);
15724 case SSL_ERROR_NONE:
15725 nin = bufp = count;
15728 if (fdispla != XYFD_B) {
15730 ftscreen(SCR_PT,'D',rpackets,NULL);
15733 case SSL_ERROR_WANT_WRITE:
15734 case SSL_ERROR_WANT_READ:
15735 case SSL_ERROR_SYSCALL:
15738 int gle = GetLastError();
15741 case SSL_ERROR_WANT_X509_LOOKUP:
15742 case SSL_ERROR_SSL:
15743 case SSL_ERROR_ZERO_RETURN:
15745 nin = bufp = count = 0;
15746 SSL_shutdown(ssl_ftp_data_con);
15747 SSL_free(ssl_ftp_data_con);
15748 ssl_ftp_data_active_flag = 0;
15749 ssl_ftp_data_con = NULL;
15751 socket_close(data);
15752 #else /* TCPIPLIB */
15753 #ifdef USE_SHUTDOWN
15754 shutdown(data, 1+1);
15755 #endif /* USE_SHUTDOWN */
15757 #endif /* TCPIPLIB */
15763 #endif /* CK_SSL */
15765 kerror = looping_read(fd, (char *)&length, sizeof(length));
15766 if (kerror != sizeof(length)) {
15767 secure_error("Couldn't read PROT buffer length: %d/%s",
15769 kerror == -1 ? ck_errstr()
15774 debug(F101,"secure_getbyte length","",length);
15775 debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
15777 length = (ULONG) ntohl(length);
15778 if (length > maxbuf) {
15779 secure_error("Length (%d) of PROT buffer > PBSZ=%u",
15785 if ((kerror = looping_read(fd, ucbuf, length)) != length) {
15786 secure_error("Couldn't read %u byte PROT buffer: %s",
15788 kerror == -1 ? ck_errstr() : "premature EOF"
15793 /* Other auth types go here ... */
15795 if (strcmp(auth_type, "SRP") == 0) {
15796 if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
15802 secure_error ("srp_encode failed" );
15806 #endif /* FTP_SRP */
15808 if (strcmp(auth_type, "KERBEROS_V4") == 0) {
15809 struct sockaddr_in myaddr, hisaddr;
15811 len = sizeof(myaddr);
15812 if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
15813 secure_error("secure_putbuf: getsockname failed");
15816 len = sizeof(hisaddr);
15817 if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
15818 secure_error("secure_putbuf: getpeername failed");
15822 kerror = krb_rd_priv(ucbuf, length, ftp_sched,
15827 #endif /* KRB524 */
15828 &hisaddr, &myaddr, &ftp_msg_data);
15830 kerror = krb_rd_safe(ucbuf, length,
15835 #endif /* KRB524 */
15836 &hisaddr, &myaddr, &ftp_msg_data);
15839 secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
15840 ftp_dpl == FPL_PRV ? "priv" : "safe",
15841 krb_get_err_text(kerror));
15844 memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
15845 nin = bufp = ftp_msg_data.app_length;
15847 #endif /* FTP_KRB4 */
15849 if (strcmp(auth_type, "GSSAPI") == 0) {
15850 gss_buffer_desc xmit_buf, msg_buf;
15851 OM_uint32 maj_stat, min_stat;
15854 xmit_buf.value = ucbuf;
15855 xmit_buf.length = length;
15856 conf_state = (ftp_dpl == FPL_PRV);
15857 /* decrypt/verify the message */
15858 maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
15859 &msg_buf, &conf_state, NULL);
15860 if (maj_stat != GSS_S_COMPLETE) {
15861 user_gss_error(maj_stat, min_stat,
15862 (ftp_dpl == FPL_PRV)?
15863 "failed unsealing ENC message":
15864 "failed unsealing MIC message");
15867 memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
15868 gss_release_buffer(&min_stat, &msg_buf);
15870 #endif /* FTP_GSSAPI */
15871 /* Other auth types go here ... */
15873 /* Update file transfer display */
15876 if (fdispla != XYFD_B) {
15878 ftscreen(SCR_PT,'D',rpackets,NULL);
15885 return(ucbuf[bufp - nin--]);
15888 /* secure_getc(fd,fc)
15890 * fd = file descriptor for connection.
15891 * fc = 0 to get a character, fc != 0 to initialize buffer pointers.
15893 * c>=0 on success (character value)
15895 * -2 on security error
15898 secure_getc(fd,fc) int fd,fc; { /* file descriptor, function code */
15899 if (!ftpissecure()) {
15900 static unsigned int nin = 0, bufp = 0;
15909 nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
15911 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
15912 debug(F101,"secure_getc returns EOF","",EOF);
15916 debug(F101,"ftp secure_getc recv","",nin);
15917 hexdump("ftp secure_getc recv",ucbuf,16);
15920 if (fdispla != XYFD_B) {
15922 ftscreen(SCR_PT,'D',rpackets,NULL);
15925 return(ucbuf[bufp - nin--]);
15927 return(secure_getbyte(fd,fc));
15931 * n>0 on success (n == # of bytes read)
15933 * -1 on error (errno set), only for FPL_CLR
15934 * -2 on security error
15937 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
15941 debug(F101,"secure_read bytes requested","",nbyte);
15944 for (i = 0; nbyte > 0; nbyte--) {
15945 c = secure_getc(fd,0);
15947 case -9: /* Canceled from keyboard */
15948 debug(F101,"ftp secure_read interrupted","",c);
15951 debug(F101,"ftp secure_read error","",c);
15954 debug(F101,"ftp secure_read EOF","",c);
15965 #ifdef USE_RUSERPASS
15968 * Copyright (c) 1985 Regents of the University of California.
15969 * All rights reserved.
15971 * Redistribution and use in source and binary forms, with or without
15972 * modification, are permitted provided that the following conditions
15974 * 1. Redistributions of source code must retain the above copyright
15975 * notice, this list of conditions and the following disclaimer.
15976 * 2. Redistributions in binary form must reproduce the above copyright
15977 * notice, this list of conditions and the following disclaimer in the
15978 * documentation and/or other materials provided with the distribution.
15979 * 3. All advertising materials mentioning features or use of this software
15980 * must display the following acknowledgement:
15981 * This product includes software developed by the University of
15982 * California, Berkeley and its contributors.
15983 * 4. Neither the name of the University nor the names of its contributors
15984 * may be used to endorse or promote products derived from this software
15985 * without specific prior written permission.
15987 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15988 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15989 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15990 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
15991 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15992 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
15993 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15994 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
15995 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
15996 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16001 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16002 #endif /* not lint */
16004 #ifndef MAXHOSTNAMELEN
16005 #define MAXHOSTNAMELEN 64
16009 static FILE * cfile;
16019 static char tokval[100];
16021 static struct toktab {
16025 "default", DEFAULT,
16027 "password", PASSWD,
16029 "account", ACCOUNT,
16043 while ((c = getc(cfile)) != EOF &&
16044 (c == '\n' || c == '\t' || c == ' ' || c == ','))
16050 while ((c = getc(cfile)) != EOF && c != '"') {
16057 while ((c = getc(cfile)) != EOF
16058 && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16065 if (tokval[0] == 0)
16067 for (t = toktab; t->tokstr; t++)
16068 if (!strcmp(t->tokstr, tokval))
16073 ruserpass(host, aname, apass, aacct)
16074 char *host, **aname, **apass, **aacct;
16076 char *hdir, buf[FTP_BUFSIZ], *tmp;
16077 char myname[MAXHOSTNAMELEN], *mydomain;
16078 int t, i, c, usedefault = 0;
16085 hdir = getenv("HOME");
16088 ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16089 cfile = fopen(buf, "r");
16090 if (cfile == NULL) {
16091 if (errno != ENOENT)
16095 if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16097 if ((mydomain = ckstrchr(myname, '.')) == NULL)
16101 while ((t = token())) switch(t) {
16112 * Allow match either for user's input host name
16113 * or official hostname. Also allow match of
16114 * incompletely-specified host in local domain.
16116 if (ckstrcmp(host, tokval,-1,1) == 0)
16118 if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16120 if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16121 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16122 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16123 tokval[tmp - ftp_host] == '\0')
16125 if ((tmp = ckstrchr(host, '.')) != NULL &&
16126 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16127 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16128 tokval[tmp - host] == '\0')
16134 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16139 *aname = malloc((unsigned) strlen(tokval) + 1);
16140 strcpy(*aname, tokval); /* safe */
16142 if (strcmp(*aname, tokval))
16147 if (strcmp(*aname, "anonymous") &&
16148 fstat(fileno(cfile), &stb) >= 0 &&
16149 (stb.st_mode & 077) != 0) {
16150 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16151 fprintf(stderr, "Remove password or correct mode.\n");
16154 if (token() && *apass == 0) {
16155 *apass = malloc((unsigned) strlen(tokval) + 1);
16156 strcpy(*apass, tokval); /* safe */
16160 if (fstat(fileno(cfile), &stb) >= 0
16161 && (stb.st_mode & 077) != 0) {
16162 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16163 fprintf(stderr, "Remove account or correct mode.\n");
16166 if (token() && *aacct == 0) {
16167 *aacct = malloc((unsigned) strlen(tokval) + 1);
16168 strcpy(*aacct, tokval); /* safe */
16173 fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16187 #endif /* USE_RUSERPASS */
16189 static char *radixN =
16190 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16192 static char pad = '=';
16195 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16196 CHAR inbuf[], outbuf[];
16197 int inlen, *outlen, decode;
16204 for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16205 if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16213 outbuf[j++] |= D>>4;
16214 outbuf[j] = (D&15)<<4;
16217 outbuf[j++] |= D>>2;
16218 outbuf[j] = (D&3)<<6;
16228 case 2: if (D&15) return(3);
16229 if (strcmp((char *)&inbuf[i], "==")) return(2);
16231 case 3: if (D&3) return(3);
16232 if (strcmp((char *)&inbuf[i], "=")) return(2);
16236 for (i = 0, j = 0; i < inlen; i++) {
16239 outbuf[j++] = radixN[inbuf[i]>>2];
16240 c = (inbuf[i]&3)<<4;
16243 outbuf[j++] = radixN[c|inbuf[i]>>4];
16244 c = (inbuf[i]&15)<<2;
16247 outbuf[j++] = radixN[c|inbuf[i]>>6];
16248 outbuf[j++] = radixN[inbuf[i]&63];
16254 if (i%3) outbuf[j++] = radixN[c];
16256 case 1: outbuf[j++] = pad;
16257 case 2: outbuf[j++] = pad;
16259 outbuf[*outlen = j] = '\0';
16265 radix_error(e) int e;
16268 case 0: return("Success");
16269 case 1: return("Bad character in encoding");
16270 case 2: return("Encoding not properly padded");
16271 case 3: return("Decoded # of bits not a multiple of 8");
16272 case 4: return("Output buffer too small");
16273 default: return("Unknown error");
16276 /* END_RUSERPASS */
16279 /*---------------------------------------------------------------------------+
16281 | Package: srpftp |
16282 | Author: Eugene Jhong |
16284 +---------------------------------------------------------------------------*/
16287 * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
16288 * All Rights Reserved.
16290 * Permission is hereby granted, free of charge, to any person obtaining
16291 * a copy of this software and associated documentation files (the
16292 * "Software"), to deal in the Software without restriction, including
16293 * without limitation the rights to use, copy, modify, merge, publish,
16294 * distribute, sublicense, and/or sell copies of the Software, and to
16295 * permit persons to whom the Software is furnished to do so, subject to
16296 * the following conditions:
16298 * The above copyright notice and this permission notice shall be
16299 * included in all copies or substantial portions of the Software.
16301 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16302 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16303 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16305 * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16306 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16307 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16308 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16309 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16311 * In addition, the following conditions apply:
16313 * 1. Any software that incorporates the SRP authentication technology
16314 * must display the following acknowlegment:
16315 * "This product uses the 'Secure Remote Password' cryptographic
16316 * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16318 * 2. Any software that incorporates all or part of the SRP distribution
16319 * itself must also display the following acknowledgment:
16320 * "This product includes software developed by Tom Wu and Eugene
16321 * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16323 * 3. Redistributions in source or binary form must retain an intact copy
16324 * of this copyright notice and list of conditions.
16327 #define SRP_PROT_VERSION 1
16329 #ifdef CK_ENCRYPTION
16330 #define SRP_DEFAULT_CIPHER CIPHER_ID_CAST5_CBC
16332 #define SRP_DEFAULT_CIPHER CIPHER_ID_NONE
16333 #endif /* CK_ENCRYPTION */
16335 #define SRP_DEFAULT_HASH HASH_ID_SHA
16337 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16338 CHAR srp_pref_hash = HASH_ID_SHA;
16340 static struct t_client *tc = NULL;
16341 static CHAR *skey = NULL;
16342 static krypto_context *incrypt = NULL;
16343 static krypto_context *outcrypt = NULL;
16345 typedef unsigned int srp_uint32;
16347 /*--------------------------------------------------------------+
16348 | srp_selcipher: select cipher |
16349 +--------------------------------------------------------------*/
16351 srp_selcipher (cname) char *cname; {
16354 if (!(cd = cipher_getdescbyname (cname))) {
16356 CHAR *list = cipher_getlist ();
16358 fprintf (stderr, "ftp: supported ciphers:\n\n");
16359 for (i = 0; i < strlen (list); i++)
16360 fprintf (stderr, " %s\n", (cipher_getdescbyid(list[i]))->name);
16361 fprintf (stderr, "\n");
16364 srp_pref_cipher = cd->id;
16368 /*--------------------------------------------------------------+
16369 | srp_selhash: select hash |
16370 +--------------------------------------------------------------*/
16372 srp_selhash (hname) char *hname; {
16375 if (!(hd = hash_getdescbyname (hname))) {
16377 CHAR *list = hash_getlist ();
16379 fprintf (stderr, "ftp: supported hash functions:\n\n");
16380 for (i = 0; i < strlen (list); i++)
16381 fprintf (stderr, " %s\n", (hash_getdescbyid(list[i]))->name);
16382 fprintf (stderr, "\n");
16385 srp_pref_hash = hd->id;
16389 /*--------------------------------------------------------------+
16390 | srp_userpass: get username and password |
16391 +--------------------------------------------------------------*/
16393 srp_userpass (host) char *host; {
16394 char tmp[BUFSIZ], prompt[PROMPTSIZ];
16398 #ifdef USE_RUSERPASS
16399 ruserpass (host, &user, &srp_pass, &srp_acct);
16400 #endif /* USE_RUSERPASS */
16402 while (user == NULL) {
16407 if (!myname) myname = "";
16409 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16410 NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16412 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16414 ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16415 DEFAULT_UQ_TIMEOUT);
16416 if (!ok || *tmp == '\0')
16419 user = brstrip(tmp);
16421 ckstrncpy (srp_user, user,BUFSIZ);
16425 /*--------------------------------------------------------------+
16426 | srp_reset: reset srp information |
16427 +--------------------------------------------------------------*/
16430 if (tc) { t_clientclose (tc); tc = NULL; }
16431 if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16432 if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16436 /*--------------------------------------------------------------+
16437 | srp_ftp_auth: perform srp authentication |
16438 +--------------------------------------------------------------*/
16440 srp_ftp_auth(host, user, pass)
16450 CHAR buf[FTP_BUFSIZ];
16451 CHAR tmp[FTP_BUFSIZ];
16453 int n, e, clen, blen, len, i;
16457 srp_pass = srp_acct = 0;
16459 n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
16460 if (n != REPLY_CONTINUE) {
16462 fprintf(stderr, "SRP rejected as an authentication type\n");
16464 } else { /* Send protocol version */
16466 memset (vers, 0, 4);
16467 vers[3] = SRP_PROT_VERSION;
16469 printf ("SRP accepted as authentication type.\n");
16470 bp = tmp; blen = 0;
16471 srp_put (vers, &bp, 4, &blen);
16473 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16475 reply_parse = "ADAT=";
16476 n = ftpcmd("ADAT",buf,-1,-1,0);
16478 if (n == REPLY_CONTINUE) { /* Get protocol version */
16483 if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
16485 if (srp_get (&bp, &cp, &blen, &clen) != 4)
16488 if (host) { /* Get username/password if needed */
16489 srp_userpass (host);
16491 ckstrncpy (srp_user, user, BUFSIZ);
16494 bp = tmp; blen = 0; /* Send username */
16495 srp_put (srp_user, &bp, strlen (srp_user), &blen);
16497 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16499 reply_parse = "ADAT=";
16500 n = ftpcmd("ADAT",buf,-1,-1,0);
16502 if (n == REPLY_CONTINUE) { /* Get N, g and s */
16507 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
16509 if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
16511 if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
16513 if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
16515 if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
16516 fprintf (stderr, "Unable to open SRP client structure.\n");
16519 wp = t_clientgenexp (tc); /* Send wp */
16520 bp = tmp; blen = 0;
16521 srp_put (wp->data, &bp, wp->len, &blen);
16523 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16525 reply_parse = "ADAT=";
16526 n = ftpcmd("ADAT",buf,-1,-1,0);
16528 if (n == REPLY_CONTINUE) { /* Get yp */
16533 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
16535 if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
16538 static char ftppass[PASSBUFSIZ];
16541 ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
16542 DEFAULT_UQ_TIMEOUT);
16544 srp_pass = brstrip(ftppass);
16546 t_clientpasswd (tc, srp_pass);
16547 memset (srp_pass, 0, strlen (srp_pass));
16548 skey = t_clientgetkey (tc, &yp); /* Send response */
16549 bp = tmp; blen = 0;
16550 srp_put (t_clientresponse (tc), &bp, 20, &blen);
16552 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16554 reply_parse = "ADAT=";
16555 n = ftpcmd("ADAT",buf,-1,-1,0);
16557 if (n == REPLY_CONTINUE) { /* Get response */
16562 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
16564 if (srp_get (&bp, &cp, &blen, &clen) != 20)
16566 if (t_clientverify (tc, cp)) {
16567 fprintf (stderr, "WARNING: bad response to client challenge.\n");
16570 bp = tmp; blen = 0; /* Send nothing */
16571 srp_put ("\0", &bp, 1, &blen);
16573 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16575 reply_parse = "ADAT=";
16576 n = ftpcmd("ADAT",buf,-1,-1,0);
16578 if (n == REPLY_CONTINUE) { /* Get cipher & hash lists, seqnum */
16583 int clist_len, hlist_len;
16588 if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
16590 if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
16592 if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
16594 if (srp_get (&bp, &cp, &blen, &clen) != 4)
16596 memcpy (seqnum, cp, 4);
16597 if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
16598 cid = srp_pref_cipher;
16599 if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
16600 cid = SRP_DEFAULT_CIPHER;
16602 CHAR *loclist = cipher_getlist ();
16603 for (i = 0; i < strlen (loclist); i++)
16604 if (cipher_supported (clist, loclist[i])) {
16610 fprintf (stderr, "Unable to agree on cipher.\n");
16615 if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
16616 hid = srp_pref_hash;
16618 if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
16619 hid = SRP_DEFAULT_HASH;
16622 CHAR *loclist = hash_getlist ();
16623 for (i = 0; i < strlen (loclist); i++)
16624 if (hash_supported (hlist, loclist[i])) {
16630 fprintf (stderr, "Unable to agree on hash.\n");
16635 if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
16639 /* Generate random number for outkey and outseqnum */
16641 t_random (seqnum, 4);
16643 /* Send cid, hid, outkey, outseqnum */
16645 bp = tmp; blen = 0;
16646 srp_put (&cid, &bp, 1, &blen);
16647 srp_put (&hid, &bp, 1, &blen);
16648 srp_put (seqnum, &bp, 4, &blen);
16650 if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
16652 reply_parse = "ADAT=";
16653 n = ftpcmd("ADAT",buf,-1,-1,0);
16657 if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
16661 t_clientclose (tc);
16664 if (n != REPLY_COMPLETE)
16670 printf ("SRP authentication succeeded.\n");
16671 printf ("Using cipher %s and hash function %s.\n",
16672 (cipher_getdescbyid(cid))->name,
16673 (hash_getdescbyid(hid))->name
16676 reply_parse = NULL;
16681 fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
16685 fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
16689 fprintf (stderr, "Unable to unmarshal authentication data.\n");
16693 fprintf (stderr, "SRP authentication failed, trying regular login.\n");
16694 reply_parse = NULL;
16698 /*--------------------------------------------------------------+
16699 | srp_put: put item to send buffer |
16700 +--------------------------------------------------------------*/
16702 srp_put (in, out, inlen, outlen)
16708 srp_uint32 net_len;
16710 net_len = htonl (inlen);
16711 memcpy (*out, &net_len, 4);
16713 *out += 4; *outlen += 4;
16715 memcpy (*out, in, inlen);
16717 *out += inlen; *outlen += inlen;
16721 /*--------------------------------------------------------------+
16722 | srp_get: get item from receive buffer |
16723 +--------------------------------------------------------------*/
16725 srp_get (in, out, inlen, outlen)
16731 srp_uint32 net_len;
16733 if (*inlen < 4) return -1;
16735 memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
16736 *outlen = ntohl (net_len);
16738 if (*inlen < *outlen) return -1;
16740 *out = *in; *inlen -= *outlen; *in += *outlen;
16745 /*--------------------------------------------------------------+
16746 | srp_encode: encode control message |
16747 +--------------------------------------------------------------*/
16749 srp_encode (private, in, out, len)
16756 return krypto_msg_priv (outcrypt, in, out, len);
16758 return krypto_msg_safe (outcrypt, in, out, len);
16761 /*--------------------------------------------------------------+
16762 | srp_decode: decode control message |
16763 +--------------------------------------------------------------*/
16765 srp_decode (private, in, out, len)
16772 return krypto_msg_priv (incrypt, in, out, len);
16774 return krypto_msg_safe (incrypt, in, out, len);
16777 #endif /* FTP_SRP */
16783 The following code is from the Unix FTP client. Be sure to
16784 make sure that the functionality is not lost. Especially
16785 the Proxy stuff even though we have not yet implemented it.
16788 /* Send multiple files */
16791 ftp_mput(argc, argv) int argc; char **argv; {
16798 if (argc < 2 && !another(&argc, &argv, "local-files")) {
16799 printf("usage: %s local-files\n", argv[0]);
16805 oldintr = signal(SIGINT, mcancel);
16807 /* Replace with calls to cc_execute() */
16811 char *cp, *tp2, tmpbuf[CKMAXPATH];
16813 while ((cp = remglob(argv,0)) != NULL) {
16818 if (mflag && confirm(argv[0], cp)) {
16821 while (*tp && !islower(*tp)) {
16827 while ((*tp2 = *tp) != 0) {
16828 if (isupper(*tp2)) {
16829 *tp2 = 'a' + *tp2 - 'A';
16843 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
16844 if (!mflag && fromatty) {
16845 ointer = interactive;
16847 if (confirm("Continue with","mput")) {
16850 interactive = ointer;
16854 signal(SIGINT, oldintr);
16858 #endif /* FTP_PROXY */
16859 for (i = 1; i < argc; i++) {
16860 register char **cpp, **gargs;
16862 if (mflag && confirm(argv[0], argv[i])) {
16864 sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
16865 if (!mflag && fromatty) {
16866 ointer = interactive;
16868 if (confirm("Continue with","mput")) {
16871 interactive = ointer;
16876 gargs = ftpglob(argv[i]);
16877 if (globerr != NULL) {
16878 printf("%s\n", globerr);
16881 free((char *)gargs);
16885 for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
16886 if (mflag && confirm(argv[0], *cpp)) {
16888 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
16889 if (!mflag && fromatty) {
16890 ointer = interactive;
16892 if (confirm("Continue with","mput")) {
16895 interactive = ointer;
16899 if (gargs != NULL) {
16901 free((char *)gargs);
16904 signal(SIGINT, oldintr);
16908 /* Get multiple files */
16911 ftp_mget(argc, argv) int argc; char **argv; {
16915 char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
16918 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
16919 printf("usage: %s remote-files\n", argv[0]);
16925 oldintr = signal(SIGINT,mcancel);
16926 /* Replace with calls to cc_execute() */
16928 while ((cp = remglob(argv,proxy)) != NULL) {
16933 if (mflag && confirm(argv[0], cp)) {
16936 while (*tp && !islower(*tp)) {
16942 while ((*tp2 = *tp) != 0) {
16943 if (isupper(*tp2)) {
16944 *tp2 = 'a' + *tp2 - 'A';
16952 rc = (recvrequest("RETR", tp, cp, "wb",
16953 tp != cp || !interactive) == 0,0,NULL,0,0,0);
16954 if (!mflag && fromatty) {
16955 ointer = interactive;
16957 if (confirm("Continue with","mget")) {
16960 interactive = ointer;
16964 signal(SIGINT,oldintr);
16969 /* Delete multiple files */
16972 mdelete(argc, argv) int argc; char **argv; {
16978 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
16979 printf("usage: %s remote-files\n", argv[0]);
16985 oldintr = signal(SIGINT, mcancel);
16986 /* Replace with calls to cc_execute() */
16988 while ((cp = remglob(argv,0)) != NULL) {
16993 if (mflag && confirm(argv[0], cp)) {
16994 rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
16995 if (!mflag && fromatty) {
16996 ointer = interactive;
16998 if (confirm("Continue with", "mdelete")) {
17001 interactive = ointer;
17005 signal(SIGINT, oldintr);
17010 /* Get a directory listing of multiple remote files */
17013 mls(argc, argv) int argc; char **argv; {
17016 char *cmd, mode[1], *dest;
17020 if (argc < 2 && !another(&argc, &argv, "remote-files"))
17022 if (argc < 3 && !another(&argc, &argv, "local-file")) {
17024 printf("usage: %s remote-files local-file\n", argv[0]);
17028 dest = argv[argc - 1];
17029 argv[argc - 1] = NULL;
17030 if (strcmp(dest, "-") && *dest != '|')
17031 if (!globulize(&dest) ||
17032 !confirm("output to local-file:", dest)) {
17036 cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17039 oldintr = signal(SIGINT, mcancel);
17040 /* Replace with calls to cc_execute() */
17042 for (i = 1; mflag && i < argc-1; ++i) {
17043 *mode = (i == 1) ? 'w' : 'a';
17044 rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17045 if (!mflag && fromatty) {
17046 ointer = interactive;
17048 if (confirm("Continue with", argv[0])) {
17051 interactive = ointer;
17054 signal(SIGINT, oldintr);
17060 remglob(argv,doswitch) char *argv[]; int doswitch; {
17062 static char buf[CKMAXPATH];
17063 static FILE *ftemp = NULL;
17064 static char **args;
17073 (void) fclose(ftemp);
17082 if ((cp = *++args) == NULL)
17086 if (ftemp == NULL) {
17087 (void) strcpy(temp, _PATH_TMP);
17090 (void) mktemp(temp);
17091 #endif /* MKSTEMP */
17092 #endif /* MKTEMP */
17094 oldhash = hash, hash = 0;
17099 #endif /* FTP_PROXY */
17100 for (mode = "wb"; *++argv != NULL; mode = "ab")
17101 recvrequest ("NLST", temp, *argv, mode, 0);
17106 #endif /* FTP_PROXY */
17108 ftemp = fopen(temp, "r");
17110 if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17111 printf("Can't find list of remote files, oops\n");
17115 if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17116 fclose(ftemp), ftemp = NULL;
17119 if ((cp = ckstrchr(buf,'\n')) != NULL)
17123 #endif /* NOT_USED */
17124 #endif /* TCPSOCKET (top of file) */
17125 #endif /* SYSFTP (top of file) */
17126 #endif /* NOFTP (top of file) */