1 #define FTP_TIMEOUT
2 
3 /*  C K C F T P  --  FTP Client for C-Kermit  */
4 
5 char *ckftpv = "FTP Client, 9.0.264, 24 Dec 2015";
6 
7 /*
8   Authors:
9     Jeffrey E Altman <jaltman@secure-endpoints.com>
10       Secure Endpoints Inc., New York City
11     Frank da Cruz <fdc@columbia.edu>,
12       The Kermit Project, Columbia University.
13 
14   Copyright (C) 2000, 2015,
15     Trustees of Columbia University in the City of New York.
16     All rights reserved.  See the C-Kermit COPYING.TXT file or the
17     copyright text in the ckcmai.c module for disclaimer and permissions.
18 
19   Portions of conditionally included code Copyright Regents of the
20     University of California and The Stanford SRP Authentication Project;
21     see notices below.
22 */
23 
24 /*
25   Pending...
26 
27   . Implement recursive NLST downloads by trying to CD to each filename.
28     If it works, it's a directory; if not, it's a file -- GET it.  But
29     that won't work with servers like wu-ftpd that don't send directory
30     names.  Recursion with MLSD is done.
31 
32   . Make syslog entries for session?  Files?
33 
34   . Messages are printed to stdout and stderr in random fashion.  We should
35     either print everything to stdout, or else be systematic about when
36     to use stderr.
37 
38   . Implement mail (MAIL, MLFL, MSOM, etc) if any servers support it.
39 
40   . Adapt to VMS.  Big job because of its record-oriented file system.
41     RMS programmer required.  There are probably also some VMS TCP/IP
42     product-specific wrinkles, e.g. attribute preservation in VMS-to-VMS
43     transfers using special options for Multinet or other FTP servers
44     (find out about STRU VMS).
45 */
46 
47 /*
48   Quick FTP command reference:
49 
50   RFC765 (1980) and earlier:
51     MODE  S(tream), B(lock), C(ompressed)
52     STRU  F(ILE), R(ECORD), P(AGE)
53     TYPE  A(SCII) <format>,  E(BCDIC) <format>, I(MAGE), L(OCAL) <bytesize>
54     PORT  - Port
55     PASV  - Passive mode
56     USER  - User
57     PASS  - Password
58     ACCT  - Account
59     CWD   - Change Working Directory
60     REIN  - Logout but not disconnect
61     QUIT  - Bye
62     RETR  - Retreive
63     STOR  - Store
64     APPE  - Append
65     ALLO  - Allocate
66     REST  - Restart
67     RNFR  - Rename from
68     RNTO  - Rename to
69     ABOR  - Cancel
70     DELE  - Delete
71     LIST  - Directory
72     NLST  - Name List
73     SITE  - Site parameters or commands
74     STAT  - Status
75     HELP  - Help
76     NOOP  - Noop
77 
78   RFC959 (1985):
79     CDUP  - Change to Parent Directory
80     SMNT  - Structure Mount
81     STOU  - Store Unique
82     RMD   - Remove Directory
83     MKD   - Make Directory
84     PWD   - Print Directory
85     SYST  - System
86 
87   RFC2389 (1998):
88     FEAT  - List Features (done)
89     OPTS  - Send options (done)
90 
91   RFC2640 (1999):
92     LANG  - Specify language for messages (not done)
93 
94   Pending (Internet Drafts):
95     SIZE  - File size (done)
96     MDTM  - File modification date-time (done)
97     MLST  - File name and attribute list (single file) (not done)
98     MLSD  - File list with attributes (multiple files) (done)
99     MAIL, MLFL, MSOM - mail delivery (not done)
100 
101   Alphabetical syntax list:
102     ABOR <CRLF>
103     ACCT <SP> <account-information> <CRLF>
104     ALLO <SP> <decimal-integer> [<SP> R <SP> <decimal-integer>] <CRLF>
105     APPE <SP> <pathname> <CRLF>
106     CDUP <CRLF>
107     CWD  <SP> <pathname> <CRLF>
108     DELE <SP> <pathname> <CRLF>
109     FEAT <CRLF>
110     HELP [<SP> <string>] <CRLF>
111     LANG [<SP> <language-tag> ] <CRLF>
112     LIST [<SP> <pathname>] <CRLF>
113     MKD  <SP> <pathname> <CRLF>
114     MLSD [<SP> <pathname>] <CRLF>
115     MLST [<SP> <pathname>] <CRLF>
116     MODE <SP> <mode-code> <CRLF>
117     NLST [<SP> <pathname-or-wildcard>] <CRLF>
118     NOOP <CRLF>
119     OPTS <SP> <commandname> [ <SP> <command-options> ] <CRLF>
120     PASS <SP> <password> <CRLF>
121     PASV <CRLF>
122     PORT <SP> <host-port> <CRLF>
123     PWD  <CRLF>
124     QUIT <CRLF>
125     REIN <CRLF>
126     REST <SP> <marker> <CRLF>
127     RETR <SP> <pathname> <CRLF>
128     RMD  <SP> <pathname> <CRLF>
129     RNFR <SP> <pathname> <CRLF>
130     RNTO <SP> <pathname> <CRLF>
131     SITE <SP> <string> <CRLF>
132     SIZE <SP> <pathname> <CRLF>
133     SMNT <SP> <pathname> <CRLF>
134     STAT [<SP> <pathname>] <CRLF>
135     STOR <SP> <pathname> <CRLF>
136     STOU <CRLF>
137     STRU <SP> <structure-code> <CRLF>
138     SYST <CRLF>
139     TYPE <SP> <type-code> <CRLF>
140     USER <SP> <username> <CRLF>
141 */
142 #include "ckcsym.h"                     /* Standard includes */
143 #include "ckcdeb.h"
144 
145 #ifndef NOFTP                           /* NOFTP  = no FTP */
146 #ifndef SYSFTP                          /* SYSFTP = use external ftp client */
147 #ifdef TCPSOCKET                        /* Build only if TCP/IP included */
148 #define CKCFTP_C
149 
150 /* Note: much of the following duplicates what was done in ckcdeb.h */
151 /* but let's not mess with it unless it causes trouble. */
152 
153 #ifdef CK_ANSIC
154 #include <stdarg.h>
155 #else /* CK_ANSIC */
156 #include <varargs.h>
157 #endif /* CK_ANSIC */
158 #include <signal.h>
159 #ifdef OS2
160 #ifdef OS2ONLY
161 #include <os2.h>
162 #endif /* OS2ONLY */
163 #include "ckowin.h"
164 #include "ckocon.h"
165 #endif /* OS2 */
166 #ifndef ZILOG
167 #ifdef NT
168 #include <setjmpex.h>
169 #ifdef NTSIG
170 extern int TlsIndex;
171 #endif /* NTSIG */
172 #else /* NT */
173 #include <setjmp.h>
174 #endif /* NT */
175 #else
176 #include <setret.h>
177 #endif /* ZILOG */
178 #include "ckcsig.h"
179 #ifdef VMS
180 /* 2010-03-09 SMS.  VAX C needs help to find "sys".  It's easier not to try. */
181 #include <stat.h>
182 #else /* def VMS */
183 #include <sys/stat.h>
184 #endif /* def VMS [else] */
185 #include <ctype.h>
186 
187 #ifndef HPUXPRE65
188 #include <errno.h>			/* Error number symbols */
189 #else
190 #ifndef ERRNO_INCLUDED
191 #include <errno.h>			/* Error number symbols */
192 #endif	/* ERRNO_INCLUDED */
193 #endif	/* HPUXPRE65 */
194 
195 #ifndef NOTIMEH
196 #include <time.h>
197 #endif /* NOTIMEH */
198 #ifndef EPIPE
199 #define EPIPE 32                        /* Broken pipe error */
200 #endif /* EPIPE */
201 
202 /* Kermit includes */
203 
204 #include "ckcasc.h"
205 #include "ckcker.h"
206 #include "ckucmd.h"
207 #include "ckuusr.h"
208 #include "ckcnet.h"                     /* Includes ckctel.h */
209 #include "ckctel.h"                     /* (then why include it again?) */
210 #include "ckcxla.h"
211 
212 #ifdef CK_SSL
213 #include "ckuath.h"			/* SMS 2007/02/15 */
214 #endif /* def CK_SSL */
215 
216 /*
217   How to get the struct timeval definition so we can call select().  The
218   xxTIMEH symbols are defined in ckcdeb.h, overridden in various makefile
219   targets.  The problem is: maybe we have already included some header file
220   that defined struct timeval, and maybe we didn't.  If we did, we don't want
221   to include another header file that defines it again or the compilation will
222   fail.  If we didn't, we have to include the header file where it's defined.
223   But in some cases even that won't work because of strict POSIX constraints
224   or somesuch, or because this introduces other conflicts (e.g. struct tm
225   multiply defined), in which case we have to define it ourselves, but this
226   can work only if we didn't already encounter a definition.
227 */
228 #ifndef DCLTIMEVAL
229 #ifdef SV68R3V6
230 #define DCLTIMEVAL
231 #else
232 #ifdef SCO234
233 #define DCLTIMEVAL
234 #endif /* SCO234 */
235 #endif /* SV68R3V6 */
236 #endif /* DCLTIMEVAL */
237 
238 #ifdef DCLTIMEVAL
239 /* Also maybe in some places the elements must be unsigned... */
240 struct timeval {
241     long tv_sec;
242     long tv_usec;
243 };
244 #ifdef COMMENT
245 /* Currently we don't use this... */
246 struct timezone {
247     int tz_minuteswest;
248     int tz_dsttime;
249 };
250 #endif /* COMMENT */
251 #else  /* !DCLTIMEVAL */
252 #ifndef NOSYSTIMEH
253 #ifdef SYSTIMEH
254 #include <sys/time.h>
255 #endif /* SYSTIMEH */
256 #endif /* NOSYSTIMEH */
257 #ifndef NOSYSTIMEBH
258 #ifdef SYSTIMEBH
259 #include <sys/timeb.h>
260 #endif /* SYSTIMEBH */
261 #endif /* NOSYSTIMEBH */
262 #endif /* DCLTIMEVAL */
263 
264 /* 2010-03-09 SMS.  VAX C needs help to find "sys".  It's easier not to try. */
265 #ifdef VMS
266 #include <types.h>
267 #else /* def VMS */
268 #include <sys/types.h>
269 #endif /* def VMS [else] */
270 #include <stdio.h>
271 #include <string.h>
272 #ifdef HAVE_STDLIB_H
273 #include <stdlib.h>
274 #endif /* HAVE_STDLIB_H */
275 
276 #ifndef NOSETTIME
277 #ifdef COMMENT
278 /* This section moved to ckcdeb.h */
279 #ifdef POSIX
280 #define UTIMEH
281 #else
282 #ifdef HPUX9
283 #define UTIMEH
284 #else
285 #ifdef OS2
286 #define SYSUTIMEH
287 #endif /* OS2 */
288 #endif /* HPUX9 */
289 #endif /* POSIX */
290 #endif /* COMMENT */
291 
292 #ifdef VMS				/* SMS 2007/02/15 */
293 #include "ckvrtl.h"			/* for utime() */
294 #else  /* def VMS */
295 #ifdef SYSUTIMEH
296 #include <sys/utime.h>
297 #else
298 #ifdef UTIMEH
299 #include <utime.h>
300 #define SYSUTIMEH
301 #endif /* UTIMEH */
302 #endif /* SYSUTIMEH */
303 #endif /* def VMS */
304 #endif /* NOSETTIME */
305 
306 #ifndef SCO_OSR504
307 #ifdef SELECT_H
308 #include <sys/select.h>
309 #endif /* SELECT_H */
310 #endif /* SCO_OSR504 */
311 
312 #ifndef INADDR_NONE			/* 2010-03-29 */
313 #define INADDR_NONE -1
314 #endif	/* INADDR_NONE */
315 
316 /* select() dialects... */
317 
318 #ifdef UNIX
319 #define BSDSELECT                       /* BSD select() syntax/semantics */
320 #ifndef FD_SETSIZE
321 #define FD_SETSIZE 128
322 #endif	/* FD_SETSIZE */
323 #ifdef HPUX6				/* For HP-UX 6.5 circa 1989 */
324 typedef long fd_mask;
325 #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
326 #ifndef howmany
327 #define howmany(x, y)   (((x)+((y)-1))/(y))
328 #endif	/* howmany */
329 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
330 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
331 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
332 #define FD_COPY(f, t)   bcopy(f, t, sizeof(*(f)))
333 #define FD_ZERO(p)      bzero(p, sizeof(*(p)))
334 #endif	/* HPUX6 */
335 
336 #else
337 #ifdef OS2                              /* OS/2 or Win32 */
338 #ifdef NT
339 #define BSDSELECT
340 #else /* NT */
341 #define IBMSELECT
342 #endif /* NT */
343 #endif /* OS2 */
344 #endif /* UNIX */
345 
346 #ifdef VMS
347 #define BSDSELECT			/* SMS 2007/02/15 */
348 #endif /* def VMS */
349 
350 /* Other select() peculiarities */
351 
352 #ifdef HPUX
353 #ifndef HPUX10                          /* HP-UX 9.xx and earlier */
354 #ifndef HPUX1100
355 /* The three interior args to select() are (int *) rather than (fd_set *) */
356 #ifndef INTSELECT
357 #define INTSELECT
358 #endif /* INTSELECT */
359 #endif /* HPUX1100 */
360 #endif /* HPUX10 */
361 #endif /* HPUX */
362 
363 #ifdef CK_SOCKS                         /* SOCKS Internet relay package */
364 #ifdef CK_SOCKS5                        /* SOCKS 5 */
365 #define accept  SOCKSaccept
366 #define bind    SOCKSbind
367 #define connect SOCKSconnect
368 #define getsockname SOCKSgetsockname
369 #define listen SOCKSlisten
370 #else  /* Not SOCKS 5 */
371 #define accept  Raccept
372 #define bind    Rbind
373 #define connect Rconnect
374 #define getsockname Rgetsockname
375 #define listen Rlisten
376 #endif /* CK_SOCKS5 */
377 #endif /* CK_SOCKS */
378 
379 #ifndef NOHTTP
380 extern char * tcp_http_proxy;           /* Name[:port] of http proxy server */
381 extern int    tcp_http_proxy_errno;
382 extern char * tcp_http_proxy_user;
383 extern char * tcp_http_proxy_pwd;
384 extern char * tcp_http_proxy_agent;
385 #define HTTPCPYL 1024
386 static char proxyhost[HTTPCPYL];
387 #endif /* NOHTTP */
388 int ssl_ftp_proxy = 0;                  /* FTP over SSL/TLS Proxy Server */
389 
390 /* Feature selection */
391 
392 #ifndef USE_SHUTDOWN
393 /*
394   We don't use shutdown() because (a) we always call it just before close()
395   so it's redundant and unnecessary, and (b) it introduces a long pause on
396   some platforms like SV/68 R3.
397 */
398 /* #define USE_SHUTDOWN */
399 #endif /* USE_SHUTDOWN */
400 
401 #ifndef NORESEND
402 #ifndef NORESTART                       /* Restart / recover */
403 #ifndef FTP_RESTART
404 #define FTP_RESTART
405 #endif /* FTP_RESTART */
406 #endif /* NORESTART */
407 #endif /* NORESEND */
408 
409 #ifndef NOUPDATE                        /* Update mode */
410 #ifndef DOUPDATE
411 #define DOUPDATE
412 #endif /* DOUPDATE */
413 #endif /* NOUPDATE */
414 
415 #ifndef UNICODE                         /* Unicode required */
416 #ifndef NOCSETS                         /* for charset translation */
417 #define NOCSETS
418 #endif /* NOCSETS */
419 #endif /* UNICODE */
420 
421 #ifndef OS2
422 #ifndef HAVE_MSECS                      /* Millisecond timer */
423 #ifdef UNIX
424 #ifdef GFTIMER
425 #define HAVE_MSECS
426 #endif /* GFTIMER */
427 #endif /* UNIX */
428 #endif /* HAVE_MSECS */
429 #endif /* OS2 */
430 
431 #ifdef PIPESEND                         /* PUT from pipe */
432 #ifndef PUTPIPE
433 #define PUTPIPE
434 #endif /* PUTPIPE */
435 #endif /* PIPESEND */
436 
437 #ifndef NOSPL                           /* PUT from array */
438 #ifndef PUTARRAY
439 #define PUTARRAY
440 #endif /* PUTARRAY */
441 #endif /* NOSPL */
442 
443 /* Security... */
444 
445 #ifdef CK_SRP
446 #define FTP_SRP
447 #endif /* CK_SRP */
448 
449 #ifdef CK_KERBEROS
450 #ifdef KRB4
451 /*
452   There is a conflict between the Key Schedule formats used internally
453   within the standalone MIT KRB4 library and that used by Eric Young
454   in OpenSSL and his standalone DES library.  Therefore, KRB4 FTP AUTH
455   cannot be supported when either of those two packages are used.
456 */
457 #ifdef KRB524
458 #define FTP_KRB4
459 #else /* KRB524 */
460 #ifndef CK_SSL
461 #ifndef LIBDES
462 #define FTP_KRB4
463 #endif /* LIBDES */
464 #endif /* CK_SSL */
465 #endif /* KRB524 */
466 #endif /* KRB4 */
467 #ifdef KRB5
468 #ifndef HEIMDAL
469 #ifndef NOFTP_GSSAPI			/* 299 */
470 #define FTP_GSSAPI
471 #endif	/* NOFTP_GSSAPI */
472 #endif /* HEIMDAL */
473 #endif /* KRB5 */
474 #endif /* CK_KERBEROS */
475 
476 /* FTP_SECURITY is defined if any of the above is selected */
477 #ifndef FTP_SECURITY
478 #ifdef FTP_GSSAPI
479 #define FTP_SECURITY
480 #else
481 #ifdef FTP_KRB4
482 #define FTP_SECURITY
483 #else
484 #ifdef FTP_SRP
485 #define FTP_SECURITY
486 #else
487 #ifdef CK_SSL
488 #define FTP_SECURITY
489 #endif /* CK_SSL */
490 #endif /* FTP_SRP */
491 #endif /* FTP_KRB4 */
492 #endif /* FTP_GSSAPI */
493 #endif /* FTP_SECURITY */
494 
495 #ifdef CK_DES
496 #ifdef CK_SSL
497 #ifndef LIBDES
498 #define LIBDES
499 #endif /* LIBDES */
500 #endif /* CK_SSL */
501 #endif /* CK_DES */
502 
503 #ifdef CRYPT_DLL
504 #ifndef LIBDES
505 #define LIBDES
506 #endif /* LIBDES */
507 #endif /* CRYPT_DLL */
508 
509 #ifdef FTP_KRB4
510 #define des_cblock Block
511 #define des_key_schedule Schedule
512 #ifdef KRB524
513 #ifdef NT
514 #define _WINDOWS
515 #endif /* NT */
516 #include "kerberosIV/krb.h"
517 #else /* KRB524 */
518 #ifdef SOLARIS
519 #ifndef sun
520 /* For some reason lost in history the Makefile Solaris targets have -Usun */
521 #define sun
522 #endif /* sun */
523 #endif /* SOLARIS */
524 #include "krb.h"
525 #define krb_get_err_text_entry krb_get_err_text
526 #endif /* KRB524 */
527 #endif /* FTP_KRB4 */
528 
529 #ifdef CK_SSL
530 #ifdef FTP_KRB4
531 #ifndef HEADER_DES_H
532 #define HEADER_DES_H
533 #endif /* HEADER_DES_H */
534 #endif /* FTP_KRB4 */
535 #include "ck_ssl.h"
536 #endif /* CK_SSL */
537 
538 #ifdef FTP_SRP
539 #ifdef HAVE_PWD_H
540 #include "pwd.h"
541 #endif /* HAVE_PWD_H */
542 #include "t_pwd.h"
543 #include "t_client.h"
544 #include "krypto.h"
545 #endif /* FTP_SRP */
546 
547 #ifdef FTP_GSSAPI
548 #include <gssapi/gssapi.h>
549 /*
550   Need to include the krb5 file, because we're doing manual fallback
551   from the v2 mech to the v1 mech.  Once there's real negotiation,
552   we can be generic again.
553 */
554 #include <gssapi/gssapi_generic.h>
555 #include <gssapi/gssapi_krb5.h>
556 static gss_ctx_id_t gcontext;
557 
558 #ifdef MACOSX
559 /** exported constants defined in gssapi_krb5{,_nx}.h **/
560 
561 /* these are bogus, but will compile */
562 
563 /*
564  * The OID of the draft krb5 mechanism, assigned by IETF, is:
565  *      iso(1) org(3) dod(5) internet(1) security(5)
566  *      kerberosv5(2) = 1.3.5.1.5.2
567  * The OID of the krb5_name type is:
568  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
569  *      krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
570  * The OID of the krb5_principal type is:
571  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
572  *      krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
573  * The OID of the proposed standard krb5 mechanism is:
574  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
575  *      krb5(2) = 1.2.840.113554.1.2.2
576  * The OID of the proposed standard krb5 v2 mechanism is:
577  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
578  *      krb5v2(3) = 1.2.840.113554.1.2.3
579  *
580  */
581 
582 /*
583  * Encoding rules: The first two values are encoded in one byte as 40
584  * * value1 + value2.  Subsequent values are encoded base 128, most
585  * significant digit first, with the high bit (\200) set on all octets
586  * except the last in each value's encoding.
587  */
588 
589 static CONST gss_OID_desc
590 ck_krb5_gss_oid_array[] = {
591    /* this is the official, rfc-specified OID */
592    {9, "\052\206\110\206\367\022\001\002\002"},
593    /* this is the unofficial, wrong OID */
594    {5, "\053\005\001\005\002"},
595    /* this is the v2 assigned OID */
596    {9, "\052\206\110\206\367\022\001\002\003"},
597    /* these two are name type OID's */
598    {10, "\052\206\110\206\367\022\001\002\002\001"},
599    {10, "\052\206\110\206\367\022\001\002\002\002"},
600    { 0, 0 }
601 };
602 
603 static
604 CONST gss_OID_desc * CONST gss_mech_krb5_v2 = ck_krb5_gss_oid_array+2;
605 
606 #ifdef MACOSX103
607 static
608 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
609 #endif /* MACOSX103 */
610 
611 #ifndef MACOSX
612 static
613 CONST gss_OID_desc * CONST gss_mech_krb5 = ck_krb5_gss_oid_array+0;
614 static
615 CONST gss_OID_desc * CONST gss_mech_krb5_old = ck_krb5_gss_oid_array+1;
616 static
617 CONST gss_OID_desc * CONST gss_nt_krb5_name = ck_krb5_gss_oid_array+3;
618 static
619 CONST gss_OID_desc * CONST gss_nt_krb5_principal = ck_krb5_gss_oid_array+4;
620 #endif	/* MACOSX */
621 
622 /*
623  * See krb5/gssapi_krb5.c for a description of the algorithm for
624  * encoding an object identifier.
625  */
626 
627 /*
628  * The OID of user_name is:
629  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
630  *      generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
631  * machine_uid_name:
632  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
633  *      generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
634  * string_uid_name:
635  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
636  *      generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
637  * service_name:
638  *      iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
639  *      generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
640  * exported_name:
641  *      1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes),
642  *          4(gss-api-exported-name)
643  * host_based_service_name (v2):
644  *      iso (1) org (3), dod (6), internet (1), security (5), nametypes(6),
645  *      gss-host-based-services(2)
646  */
647 
648 static gss_OID_desc ck_oids[] = {
649    {10, "\052\206\110\206\367\022\001\002\001\001"},
650    {10, "\052\206\110\206\367\022\001\002\001\002"},
651    {10, "\052\206\110\206\367\022\001\002\001\003"},
652    {10, "\052\206\110\206\367\022\001\002\001\004"},
653    { 6, "\053\006\001\005\006\004"},
654    { 6, "\053\006\001\005\006\002"},
655 };
656 
657 static gss_OID ck_gss_nt_user_name = ck_oids+0;
658 static gss_OID ck_gss_nt_machine_uid_name = ck_oids+1;
659 static gss_OID ck_gss_nt_string_uid_name = ck_oids+2;
660 static gss_OID ck_gss_nt_service_name = ck_oids+3;
661 static gss_OID ck_gss_nt_exported_name = ck_oids+4;
662 static gss_OID ck_gss_nt_service_name_v2 = ck_oids+5;
663 #endif /* MACOSX */
664 #endif /* FTP_GSSAPI */
665 
666 #ifdef OS2
667 #ifdef FTP_SRP
668 #define MAP_KRYPTO
669 #ifdef SRPDLL
670 #define MAP_SRP
671 #endif /* SRPDLL */
672 #endif /* FTP_SRP */
673 #ifdef FTP_KRB4
674 #define MAP_KRB4
675 #ifdef CK_ENCRYPTION
676 #define MAP_DES
677 #endif /* CK_ENCRYPTION */
678 #endif /* FTP_KRB4 */
679 #ifdef FTP_GSSAPI
680 #define MAP_GSSAPI
681 #define GSS_OIDS
682 #endif /* FTP_GSSAPI */
683 #include "ckoath.h"
684 
685 extern int k95stdout, wherex[], wherey[];
686 extern unsigned char colorcmd;
687 #endif /* OS2 */
688 
689 #ifdef FTP_KRB4
690 static char ftp_realm[REALM_SZ + 1];
691 static KTEXT_ST ftp_tkt;
692 #ifdef OS2
693 static LEASH_CREDENTIALS ftp_cred;
694 #else /* OS2 */
695 static CREDENTIALS ftp_cred;
696 #endif /* OS2 */
697 static MSG_DAT ftp_msg_data;
698 static des_key_schedule ftp_sched;
699 static int foo[4] = {99,99,99,99};
700 #endif /* FTP_KRB4 */
701 
702 /* getreply() function codes */
703 
704 #define GRF_AUTH 1			/* Reply to AUTH command */
705 #define GRF_FEAT 2			/* Reply to FEAT command */
706 
707 /* Operational definitions */
708 
709 #define DEF_VBM 0                       /* Default verbose mode */
710 /* #define SETVBM */                    /* (see getreply) */
711 
712 #define URL_ONEFILE                     /* GET, not MGET, for FTP URL */
713 
714 #define FTP_BUFSIZ 10240                /* Max size for FTP cmds & replies */
715 #define SRVNAMLEN 32                    /* Max length for server type name */
716 #define PWDSIZ 256
717 #define PASSBUFSIZ 256
718 #define PROMPTSIZ 256
719 
720 #ifndef MGETMAX                         /* Max operands for MGET command */
721 #define MGETMAX 1000
722 #endif /* MGETMAX */
723 
724 #ifdef FTP_SRP
725 #define FUDGE_FACTOR 100
726 #endif /* FTP_SRP */
727 
728 /*
729   Amount of growth from cleartext to ciphertext.  krb_mk_priv adds this
730   number bytes.  Must be defined for each auth type.
731   GSSAPI appears to add 52 bytes, but I'm not sure it is a constant--hartmans
732   3DES requires 56 bytes.  Lets use 96 just to be sure.
733 */
734 #ifdef FTP_GSSAPI
735 #ifndef FUDGE_FACTOR
736 #define FUDGE_FACTOR 96
737 #endif /* FUDGE_FACTOR */
738 #endif /* FTP_GSSAPI */
739 
740 #ifdef FTP_KRB4
741 #ifndef FUDGE_FACTOR
742 #define FUDGE_FACTOR 32
743 #endif /* FUDGE_FACTOR */
744 #endif /* FTP_KRB4 */
745 
746 #ifndef FUDGE_FACTOR                    /* In case no auth types define it */
747 #define FUDGE_FACTOR 0
748 #endif /* FUDGE_FACTOR */
749 
750 #ifndef MAXHOSTNAMELEN
751 #define MAXHOSTNAMELEN 64
752 #endif /* MAXHOSTNAMELEN */
753 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
754 
755 /* Fascist compiler toadying */
756 
757 #ifndef SENDARG2TYPE
758 #ifdef COMMENT                          /* Might be needed here and there */
759 #define SENDARG2TYPE const char *
760 #else
761 #define SENDARG2TYPE char *
762 #endif /* COMMENT */
763 #endif /* SENDARG2TYPE */
764 
765 /* Common text messages */
766 
767 static char *nocx = "?No FTP control connection\n";
768 
769 static char *fncnam[] = {
770   "rename", "overwrite", "backup", "append", "discard", "ask", "update",
771   "dates-differ", ""
772 };
773 
774 /* Macro definitions */
775 
776 /* Used to speed up text-mode PUTs */
777 #define zzout(fd,c) \
778 ((fd<0)?(-1):((nout>=ucbufsiz)?(zzsend(fd,c)):(ucbuf[nout++]=c)))
779 
780 #define CHECKCONN() if(!connected){printf(nocx);return(-9);}
781 
782 /* Externals */
783 
784 #ifdef CK_URL
785 extern struct urldata g_url;
786 #endif /* CK_URL */
787 
788 #ifdef DYNAMIC
789 extern char *zinbuffer, *zoutbuffer;    /* Regular Kermit file i/o */
790 #else
791 extern char zinbuffer[], zoutbuffer[];
792 #endif /* DYNAMIC */
793 extern char *zinptr, *zoutptr;
794 extern int zincnt, zoutcnt, zobufsize, fncact;
795 
796 #ifdef CK_TMPDIR
797 extern int f_tmpdir;                    /* Directory changed temporarily */
798 extern char savdir[];                   /* For saving current directory */
799 extern char * dldir;
800 #endif /* CK_TMPDIR */
801 
802 extern char * rfspec, * sfspec, * srfspec, * rrfspec; /* For WHERE command */
803 
804 extern xx_strp xxstring;
805 extern struct keytab onoff[], txtbin[], rpathtab[];
806 extern int nrpathtab, xfiletype, patterns, gnferror, moving, what, pktnum;
807 extern int success, nfils, sndsrc, quiet, nopush, recursive, inserver, binary;
808 extern int filepeek, nscanfile, fsecs, xferstat, xfermode, lastxfer, tsecs;
809 extern int backgrd, spackets, rpackets, spktl, rpktl, xaskmore, cmd_rows;
810 extern int nolinks, msgflg, keep;
811 extern CK_OFF_T fsize, ffc, tfc, sendstart, sndsmaller, sndlarger, rs_len;
812 extern long filcnt, xfsecs, tfcps, cps, oldcps;
813 
814 #ifdef FTP_TIMEOUT
815 int ftp_timed_out = 0;
816 long ftp_timeout = 0;
817 #endif	/* FTP_TIMEOUT */
818 
819 #ifdef GFTIMER
820 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
821 #else
822 extern long xfsecs;
823 #endif /* GFTIMER */
824 
825 extern char filnam[], * filefile, myhost[];
826 extern char * snd_move, * rcv_move, * snd_rename, * rcv_rename;
827 extern int g_skipbup, skipbup, sendmode;
828 extern int g_displa, fdispla, displa;
829 
830 #ifdef LOCUS
831 extern int locus, autolocus;
832 #endif /* LOCUS */
833 
834 #ifndef NOCSETS
835 extern int nfilc, dcset7, dcset8, fileorder;
836 extern struct csinfo fcsinfo[];
837 extern struct keytab fcstab[];
838 extern int fcharset;
839 #endif /* NOCSETS */
840 
841 extern char sndbefore[], sndafter[], *sndexcept[]; /* Selection criteria */
842 extern char sndnbefore[], sndnafter[], *rcvexcept[];
843 extern CHAR feol;
844 
845 extern char * remdest;
846 extern int remfile, remappd, rempipe;
847 
848 #ifndef NOSPL
849 extern int cmd_quoting;
850 #ifdef PUTARRAY
851 extern int sndxlo, sndxhi, sndxin;
852 extern char sndxnam[];
853 extern char **a_ptr[];                  /* Array pointers */
854 extern int a_dim[];                     /* Array dimensions */
855 #endif /* PUTARRAY */
856 #endif /* NOSPL */
857 
858 #ifndef NOMSEND                         /* MPUT and ADD SEND-LIST lists */
859 extern char *msfiles[];
860 extern int filesinlist;
861 extern struct filelist * filehead;
862 extern struct filelist * filetail;
863 extern struct filelist * filenext;
864 extern int addlist;
865 extern char fspec[];                    /* Most recent filespec */
866 extern int fspeclen;                    /* Length of fspec[] buffer */
867 #endif /* NOMSEND */
868 
869 extern int pipesend;
870 #ifdef PIPESEND
871 extern char * sndfilter, * rcvfilter;
872 #endif /* PIPESEND */
873 
874 #ifdef CKROOT
875 extern int ckrooterr;
876 #endif /* CKROOT */
877 
878 #ifdef KRB4
879 extern int krb4_autoget;
880 _PROTOTYP(char * ck_krb4_realmofhost,(char *));
881 #endif /* KRB4 */
882 
883 #ifdef KRB5
884 extern int krb5_autoget;
885 extern int krb5_d_no_addresses;
886 _PROTOTYP(char * ck_krb5_realmofhost,(char *));
887 #endif /* KRB5 */
888 
889 #ifdef DCMDBUF
890 extern char *atmbuf;                    /* Atom buffer (malloc'd) */
891 extern char *cmdbuf;                    /* Command buffer (malloc'd) */
892 extern char *line;                      /* Big string buffer #1 */
893 extern char *tmpbuf;                    /* Big string buffer #2 */
894 #else
895 extern char atmbuf[];                   /* The same, but static */
896 extern char cmdbuf[];
897 extern char line[];
898 extern char tmpbuf[];
899 #endif /* DCMDBUF */
900 
901 extern char * cmarg, * cmarg2, ** cmlist; /* For setting up file lists */
902 
903 /* Public variables declared here */
904 
905 #ifdef NOXFER
906 int ftpget  =  1;                       /* GET/PUT/REMOTE orientation FTP */
907 #else
908 int ftpget  =  2;                       /* GET/PUT/REMOTE orientation AUTO */
909 #endif /* NOXFER */
910 int ftpcode = -1;                       /* Last FTP response code */
911 int ftp_cmdlin = 0;                     /* FTP invoked from command line */
912 int ftp_fai = 0;                        /* FTP failure count */
913 int ftp_deb = 0;                        /* FTP debugging */
914 int ftp_dis = -1;			/* FTP display style */
915 int ftp_log = 1;                        /* FTP Auto-login */
916 int sav_log = -1;
917 int ftp_action = 0;                     /* FTP action from command line */
918 int ftp_dates = 1;                      /* Set file dates from server */
919 int ftp_xfermode = XMODE_A;		/* FTP-specific transfer mode */
920 
921 char ftp_reply_str[FTP_BUFSIZ] = "";    /* Last line of previous reply */
922 char ftp_srvtyp[SRVNAMLEN] = { NUL, NUL }; /* Server's system type */
923 char ftp_user_host[MAX_DNS_NAMELEN]= ""; /* FTP hostname specified by user */
924 char * ftp_host = NULL;                 /* FTP hostname */
925 char * ftp_logname = NULL;              /* FTP username */
926 char * ftp_rdir = NULL;                 /* Remote directory from cmdline */
927 char * ftp_apw = NULL;			/* Anonymous password */
928 
929 /* Definitions and typedefs needed for prototypes */
930 
931 #define sig_t my_sig_t
932 #define sigtype SIGTYP
933 typedef sigtype (*sig_t)();
934 
935 /* Static global variables */
936 
937 static char ftpsndbuf[FTP_BUFSIZ+64];
938 
939 static char * fts_sto = NULL;
940 
941 static int ftpsndret = 0;
942 static struct _ftpsnd {
943     sig_t oldintr, oldintp;
944     int            reply;
945     int            incs,
946                    outcs;
947     char *         cmd, * local, * remote;
948     int            bytes;
949     int            restart;
950     int            xlate;
951     char *         lmode;
952 } ftpsnd;
953 
954 /*
955   This is just a first stab -- these strings should match how the
956   corresponding FTP servers identify themselves.
957 */
958 #ifdef UNIX
959 static char * myostype = "UNIX";
960 #else
961 #ifdef VMS
962 /* not yet... */
963 static char * myostype = "VMS";
964 #else
965 #ifdef OS2
966 #ifdef NT
967 static char * myostype = "WIN32";
968 #else
969 static char * myostype = "OS/2";
970 #endif /* NT */
971 #else
972 static char * myostype = "UNSUPPORTED";
973 #endif /* OS2  */
974 #endif /* VMS */
975 #endif /* UNIX */
976 
977 static int noinit = 0;                  /* Don't send REST, STRU, MODE */
978 static int alike = 0;                   /* Client/server like platforms */
979 static int local = 1;                   /* Shadows Kermit global 'local' */
980 static int dout = -1;                   /* Data connection file descriptor */
981 static int dpyactive = 0;               /* Data transfer is active */
982 static int globaldin = -1;              /* Data connection f.d. */
983 static int out2screen = 0;              /* GET output is to screen */
984 static int forcetype = 0;               /* Force text or binary mode */
985 static int cancelfile = 0;              /* File canceled */
986 static int cancelgroup = 0;             /* Group canceled */
987 static int anonymous = 0;               /* Logging in as anonymous */
988 static int loggedin = 0;                /* Logged in (or not) */
989 static int puterror = 0;                /* What to do on PUT error */
990 static int geterror = 0;                /* What to do on GET error */
991 static int rfrc = 0;                    /* remote_files() return code */
992 static int okrestart = 0;               /* Server understands REST */
993 static int printlines = 0;              /* getreply()should print data lines */
994 static int haveurl = 0;                 /* Invoked by command-line FTP URL */
995 static int mdtmok = 1;			/* Server supports MDTM */
996 static int sizeok = 1;
997 static int featok = 1;
998 static int mlstok = 1;
999 static int stouarg = 1;
1000 static int typesent = 0;
1001 static int havesigint = 0;
1002 static long havetype =  0;
1003 static CK_OFF_T havesize = (CK_OFF_T)-1;
1004 static char * havemdtm = NULL;
1005 static int mgetmethod = 0;		/* NLST or MLSD */
1006 static int mgetforced = 0;
1007 
1008 static int i, /* j, k, */ x, y, z;      /* Volatile temporaries */
1009 static int c0, c1;                      /* Temp variables for characters */
1010 
1011 static char putpath[CKMAXPATH+1] = { NUL, NUL };
1012 static char asnambuf[CKMAXPATH+1] = { NUL, NUL };
1013 
1014 #define RFNBUFSIZ 4096			/* Remote filename buffer size */
1015 
1016 static unsigned int maxbuf = 0, actualbuf = 0;
1017 static CHAR *ucbuf = NULL;
1018 static int ucbufsiz = 0;
1019 static unsigned int nout = 0;           /* Number of chars in ucbuf */
1020 
1021 static jmp_buf recvcancel;
1022 static jmp_buf sendcancel;
1023 static jmp_buf ptcancel;
1024 static jmp_buf jcancel;
1025 static int ptabflg = 0;
1026 
1027 /* Protection level symbols */
1028 
1029 #define FPL_CLR 1                       /* Clear */
1030 #define FPL_SAF 2                       /* Safe */
1031 #define FPL_PRV 3                       /* Private */
1032 #define FPL_CON 4                       /* Confidential */
1033 
1034 /* Symbols for file types returned by MLST/MLSD */
1035 
1036 #define FTYP_FILE 1			/* Regular file */
1037 #define FTYP_DIR  2			/* Directory */
1038 #define FTYP_CDIR 3			/* Current directory */
1039 #define FTYP_PDIR 4			/* Parent directory */
1040 
1041 /* File type symbols keyed to the file-type symbols from ckcker.h */
1042 
1043 #define FTT_ASC XYFT_T                  /* ASCII (text) */
1044 #define FTT_BIN XYFT_B                  /* Binary (image) */
1045 #define FTT_TEN XYFT_X                  /* TENEX (TOPS-20) */
1046 
1047 /* Server feature table - sfttab[0] > 0 means server supports FEAT and OPTS */
1048 
1049 static int sfttab[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
1050 
1051 #define SFT_AUTH  1			/* FTP server feature codes */
1052 #define SFT_LANG  2
1053 #define SFT_MDTM  3
1054 #define SFT_MLST  4
1055 #define SFT_PBSZ  5
1056 #define SFT_PROT  6
1057 #define SFT_REST  7
1058 #define SFT_SIZE  8
1059 #define SFT_TVFS  9
1060 #define SFT_UTF8 10
1061 
1062 #define CNV_AUTO  2			/* FTP filename conversion */
1063 #define CNV_CNV   1
1064 #define CNV_LIT   0
1065 
1066 /* SET FTP values */
1067 
1068 static int                              /* SET FTP values... */
1069   ftp_aut = 1,                          /* Auto-authentication */
1070 #ifdef FTP_SECURITY
1071   ftp_cry = 1,                          /* Auto-encryption */
1072   ftp_cfw = 0,                          /* Credential forwarding */
1073 #endif /* FTP_SECURITY */
1074   ftp_cpl = FPL_CLR,                    /* Command protection level */
1075   ftp_dpl = FPL_CLR,                    /* Data protection level */
1076 #ifdef FTP_PROXY
1077   ftp_prx = 0,                          /* Use proxy */
1078 #endif /* FTP_PROXY */
1079   sav_psv = -1,                         /* For saving passive mode */
1080   ftp_psv = 1,                          /* Passive mode */
1081   ftp_spc = 1,                          /* Send port commands */
1082   ftp_typ = FTT_ASC,                    /* Type */
1083   get_auto = 1,                         /* Automatic type switching for GET */
1084   tenex = 0,                            /* Type is Tenex */
1085   ftp_usn = 0,                          /* Unique server names */
1086   ftp_prm = 0,                          /* Permissions */
1087   ftp_cnv = CNV_AUTO,			/* Filename conversion (2 = auto) */
1088   ftp_vbm = DEF_VBM,                    /* Verbose mode */
1089   ftp_vbx = DEF_VBM,                    /* Sticky version of same */
1090   ftp_err = 0,                          /* Error action */
1091   ftp_fnc = -1;                         /* Filename collision action */
1092 
1093 #ifdef CK_SSL
1094 static int ftp_bug_use_ssl_v2 = 0;      /* use SSLv2 for AUTH SSL */
1095 static int ftp_bug_use_ssl_v3 = 0;	/* use SSLv3 for AUTH SSL */
1096 #endif /* CK_SSL */
1097 
1098 static int
1099 #ifdef NOCSETS
1100   ftp_csr = -1,                         /* Remote (server) character set */
1101 #else
1102   ftp_csr = FC_UTF8,
1103 #endif /* NOCSETS */
1104   ftp_xla = 0;                          /* Character-set translation on/off */
1105 int
1106   ftp_csx = -1,                         /* Remote charset currently in use */
1107   ftp_csl = -1;                         /* Local charset currently in use */
1108 
1109 static int g_ftp_typ = FTT_ASC;         /* For saving and restoring ftp_typ */
1110 
1111 char * ftp_nml = NULL;                  /* /NAMELIST */
1112 char * ftp_tmp = NULL;                  /* Temporary string */
1113 static char * ftp_acc = NULL;           /* Account string */
1114 static char * auth_type = NULL;         /* Authentication type */
1115 static char * srv_renam = NULL;         /* Server-rename string */
1116 FILE * fp_nml = NULL;                   /* Namelist file pointer */
1117 
1118 static int csocket = -1;                /* Control socket */
1119 static int connected = 0;               /* Connected to FTP server */
1120 /* static unsigned short ftp_port = 0; */ /* FTP port */
1121 /* static int ftp_port = 0; */		/* SMS 2007/02/15 */
1122 static int ftp_port = 0;		/* fdc 2007/08/30 */
1123 #ifdef FTPHOST
1124 static int hostcmd = 0;                 /* Has HOST command been sent */
1125 #endif /* FTPHOST */
1126 static int form, mode, stru, bytesize, curtype = FTT_ASC;
1127 static char bytename[8];
1128 
1129 /* For parsing replies to FTP server command */
1130 static char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
1131 
1132 #ifdef FTP_PROXY
1133 static int proxy, unix_proxy
1134 #endif /* FTP_PROXY */
1135 
1136 static char pasv[64];                   /* Passive-mode port */
1137 static int passivemode = 0;
1138 static int sendport = 0;
1139 static int servertype = 0;              /* FTP server's OS type */
1140 
1141 static int testing = 0;
1142 static char ftpcmdbuf[FTP_BUFSIZ];
1143 
1144 /* Macro definitions */
1145 
1146 #define UC(b) ckitoa(((int)b)&0xff)
1147 #define nz(x) ((x) == 0 ? 1 : (x))
1148 
1149 /* Command tables and definitions */
1150 
1151 #define FTP_ACC  1                      /* FTP command keyword codes */
1152 #define FTP_APP  2
1153 #define FTP_CWD  3
1154 #define FTP_CHM  4
1155 #define FTP_CLS  5
1156 #define FTP_DEL  6
1157 #define FTP_DIR  7
1158 #define FTP_GET  8
1159 #define FTP_IDL  9
1160 #define FTP_MDE 10
1161 #define FTP_MDI 11
1162 #define FTP_MGE 12
1163 #define FTP_MKD 13
1164 #define FTP_MOD 14
1165 #define FTP_MPU 15
1166 #define FTP_OPN 16
1167 #define FTP_PUT 17
1168 #define FTP_PWD 18
1169 #define FTP_RGE 19
1170 #define FTP_REN 20
1171 #define FTP_RES 21
1172 #define FTP_HLP 22
1173 #define FTP_RMD 23
1174 #define FTP_STA 24
1175 #define FTP_SIT 25
1176 #define FTP_SIZ 26
1177 #define FTP_SYS 27
1178 #define FTP_UMA 28
1179 #define FTP_GUP 29
1180 #define FTP_USR 30
1181 #define FTP_QUO 31
1182 #define FTP_TYP 32
1183 #define FTP_FEA 33
1184 #define FTP_OPT 34
1185 #define FTP_CHK 35
1186 #define FTP_VDI 36
1187 #define FTP_ENA 37
1188 #define FTP_DIS 38
1189 #define FTP_REP 39
1190 
1191 struct keytab gprtab[] = {              /* GET-PUT-REMOTE keywords */
1192     { "auto",    2, 0 },
1193     { "ftp",     1, 0 },
1194     { "kermit",  0, 0  }
1195 };
1196 
1197 static struct keytab qorp[] = {         /* QUIT or PROCEED keywords */
1198     { "proceed", 0, 0 },                /* 0 = proceed */
1199     { "quit",    1, 0 }                 /* 1 = quit */
1200 };
1201 
1202 static struct keytab ftpcmdtab[] = {    /* FTP command table */
1203     { "account",   FTP_ACC, 0 },
1204     { "append",    FTP_APP, 0 },
1205     { "bye",       FTP_CLS, 0 },
1206     { "cd",        FTP_CWD, 0 },
1207     { "cdup",      FTP_GUP, 0 },
1208     { "check",     FTP_CHK, 0 },
1209     { "chmod",     FTP_CHM, 0 },
1210     { "close",     FTP_CLS, 0 },
1211     { "cwd",       FTP_CWD, CM_INV },
1212     { "delete",    FTP_MDE, 0 },
1213     { "directory", FTP_DIR, 0 },
1214     { "disable",   FTP_DIS, 0 },
1215     { "enable",    FTP_ENA, 0 },
1216     { "features",  FTP_FEA, 0 },
1217     { "get",       FTP_GET, 0 },
1218     { "help",      FTP_HLP, 0 },
1219     { "idle",      FTP_IDL, 0 },
1220     { "login",     FTP_USR, CM_INV },
1221     { "mdelete",   FTP_MDE, CM_INV },
1222     { "mget",      FTP_MGE, 0 },
1223     { "mkdir",     FTP_MKD, 0 },
1224     { "modtime",   FTP_MOD, 0 },
1225     { "mput",      FTP_MPU, 0 },
1226     { "open",      FTP_OPN, 0 },
1227     { "opt",       FTP_OPT, CM_INV|CM_ABR },
1228     { "opts",      FTP_OPT, CM_INV },
1229     { "options",   FTP_OPT, 0 },
1230     { "put",       FTP_PUT, 0 },
1231     { "pwd",       FTP_PWD, 0 },
1232     { "quit",      FTP_CLS, CM_INV },
1233     { "quote",     FTP_QUO, 0 },
1234     { "reget",     FTP_RGE, 0 },
1235     { "rename",    FTP_REN, 0 },
1236     { "reput",     FTP_REP, 0 },
1237     { "resend",    FTP_REP, CM_INV },
1238     { "reset",     FTP_RES, 0 },
1239     { "rmdir",     FTP_RMD, 0 },
1240     { "send",      FTP_PUT, CM_INV },
1241     { "site",      FTP_SIT, 0 },
1242     { "size",      FTP_SIZ, 0 },
1243     { "status",    FTP_STA, 0 },
1244     { "system",    FTP_SYS, 0 },
1245     { "type",      FTP_TYP, 0 },
1246     { "umask",     FTP_UMA, 0 },
1247     { "up",        FTP_GUP, CM_INV },
1248     { "user",      FTP_USR, 0 },
1249     { "vdirectory",FTP_VDI, 0 },
1250     { "", 0, 0 }
1251 };
1252 static int nftpcmd = (sizeof(ftpcmdtab) / sizeof(struct keytab)) - 1;
1253 
1254 #define OPN_ANO 1			/* FTP OPEN switch codes */
1255 #define OPN_PSW 2
1256 #define OPN_USR 3
1257 #define OPN_ACC 4
1258 #define OPN_ACT 5
1259 #define OPN_PSV 6
1260 #define OPN_TLS 7
1261 #define OPN_NIN 8
1262 #define OPN_NOL 9
1263 
1264 #ifdef FTP_SECURITY
1265 #ifdef CK_SSL
1266 #define USETLSTAB
1267 static struct keytab tlstab[] = {       /* FTP SSL/TLS switches */
1268     { "/ssl",       OPN_TLS, 0    },
1269     { "/tls",       OPN_TLS, 0    },
1270     { "", 0, 0 }
1271 };
1272 static int ntlstab = (sizeof(tlstab) / sizeof(struct keytab)) - 1;
1273 #endif /* CK_SSL */
1274 #endif /* FTP_SECURITY */
1275 
1276 static struct keytab ftpswitab[] = {    /* FTP command switches */
1277     { "/account",   OPN_ACC, CM_ARG },
1278     { "/active",    OPN_ACT, 0      },
1279     { "/anonymous", OPN_ANO, 0      },
1280     { "/noinit",    OPN_NIN, 0      },
1281     { "/nologin",   OPN_NOL, 0      },
1282     { "/passive",   OPN_PSV, 0      },
1283     { "/password",  OPN_PSW, CM_ARG },
1284     { "/user",      OPN_USR, CM_ARG },
1285     { "", 0, 0 }
1286 };
1287 static int nftpswi = (sizeof(ftpswitab) / sizeof(struct keytab)) - 1;
1288 
1289 /* FTP { ENABLE, DISABLE } items */
1290 
1291 #define ENA_FEAT 1
1292 #define ENA_MDTM 2
1293 #define ENA_MLST 3
1294 #define ENA_SIZE 4
1295 #define ENA_AUTH 5
1296 
1297 static struct keytab ftpenatab[] = {
1298     { "AUTH",  ENA_AUTH, 0 },
1299     { "FEAT",  ENA_FEAT, 0 },
1300     { "MDTM",  ENA_MDTM, 0 },
1301     { "ML",    ENA_MLST, CM_INV|CM_ABR },
1302     { "MLS",   ENA_MLST, CM_INV|CM_ABR },
1303     { "MLSD",  ENA_MLST, CM_INV },
1304     { "MLST",  ENA_MLST, 0 },
1305     { "SIZE",  ENA_SIZE, 0 },
1306     { "", 0, 0 }
1307 };
1308 static int nftpena = (sizeof(ftpenatab) / sizeof(struct keytab)) - 1;
1309 
1310 /* SET FTP command keyword indices */
1311 
1312 #define FTS_AUT  1                      /* Autoauthentication */
1313 #define FTS_CRY  2                      /* Encryption */
1314 #define FTS_LOG  3                      /* Autologin */
1315 #define FTS_CPL  4                      /* Command protection level */
1316 #define FTS_CFW  5                      /* Credentials forwarding */
1317 #define FTS_DPL  6                      /* Data protection level */
1318 #define FTS_DBG  7                      /* Debugging */
1319 #define FTS_PSV  8                      /* Passive mode */
1320 #define FTS_SPC  9                      /* Send port commands */
1321 #define FTS_TYP 10                      /* (file) Type */
1322 #define FTS_USN 11                      /* Unique server names (for files) */
1323 #define FTS_VBM 12                      /* Verbose mode */
1324 #define FTS_ATP 13                      /* Authentication type */
1325 #define FTS_CNV 14                      /* Filename conversion */
1326 #define FTS_TST 15                      /* Test (progress) messages */
1327 #define FTS_PRM 16                      /* (file) Permissions */
1328 #define FTS_XLA 17                      /* Charset translation */
1329 #define FTS_CSR 18                      /* Server charset */
1330 #define FTS_ERR 19                      /* Error action */
1331 #define FTS_FNC 20                      /* Collision */
1332 #define FTS_SRP 21                      /* SRP options */
1333 #define FTS_GFT 22                      /* GET automatic file-type switching */
1334 #define FTS_DAT 23                      /* Set file dates */
1335 #define FTS_STO 24			/* Server time offset */
1336 #define FTS_APW 25			/* Anonymous password */
1337 #define FTS_DIS 26			/* File-transfer display style */
1338 #define FTS_BUG 27                      /* Bug(s) */
1339 #define FTS_TMO 28			/* Timeout */
1340 
1341 /* FTP BUGS */
1342 
1343 #define FTB_SV2  1                      /* use SSLv2 */
1344 #define FTB_SV3  2                      /* use SSLv3 */
1345 
1346 static struct keytab ftpbugtab[] = {
1347     { "use-ssl-v2",     FTB_SV2,        0 },
1348     { "use-ssl-v3",	FTB_SV3,	0 }
1349 
1350 };
1351 static int nftpbug = (sizeof(ftpbugtab) / sizeof(struct keytab));
1352 
1353 /* FTP PUT options (mutually exclusive, not a bitmask) */
1354 
1355 #define PUT_UPD 1                       /* Update */
1356 #define PUT_RES 2                       /* Restart */
1357 #define PUT_SIM 4                       /* Simulation */
1358 #define PUT_DIF 8			/* Dates Differ */
1359 
1360 static struct keytab ftpcolxtab[] = { /* SET FTP COLLISION options */
1361 #ifndef MAC
1362     { "append",    XYFX_A, 0 },         /* append to old file */
1363 #endif /* MAC */
1364 #ifdef COMMENT
1365     { "ask",       XYFX_Q, 0 },         /* ask what to do (not implemented) */
1366 #endif
1367     { "backup",    XYFX_B, 0 },         /* rename old file */
1368 #ifndef MAC
1369     { "dates-differ", XYFX_M, 0 },	/* accept if dates differ */
1370     { "discard",   XYFX_D, 0 },         /* don't accept new file */
1371     { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
1372 #endif /* MAC */
1373     { "overwrite", XYFX_X, 0 },         /* overwrite the old file */
1374     { "rename",    XYFX_R, 0 },         /* rename the incoming file */
1375 #ifndef MAC                             /* This crashes Mac Kermit. */
1376     { "update",    XYFX_U, 0 },         /* replace if newer */
1377 #endif /* MAC */
1378     { "", 0, 0 }
1379 };
1380 static int nftpcolx = (sizeof(ftpcolxtab) / sizeof(struct keytab)) - 1;
1381 
1382 
1383 #ifdef FTP_SECURITY
1384 /* FTP authentication options */
1385 
1386 #define FTA_AUTO 0                      /* Auto */
1387 #define FTA_SRP  1                      /* SRP */
1388 #define FTA_GK5  2                      /* Kerberos 5 */
1389 #define FTA_K4   3                      /* Kerberos 4 */
1390 #define FTA_SSL  4                      /* SSL */
1391 #define FTA_TLS  5                      /* TLS */
1392 
1393 /* FTP authentication types */
1394 
1395 #define FTPATYPS 8
1396 static int ftp_auth_type[FTPATYPS] = {
1397 #ifdef FTP_GSSAPI
1398     FTA_GK5,                            /* GSSAPI Kerberos 5 */
1399 #endif /* FTP_GK5 */
1400 #ifdef FTP_SRP
1401     FTA_SRP,                            /* SRP */
1402 #endif /* FTP_SRP */
1403 #ifdef FTP_KRB4
1404     FTA_K4,                             /* Kerberos 4 */
1405 #endif /* FTP_KRB4 */
1406 #ifdef CK_SSL
1407     FTA_TLS,                            /* TLS */
1408     FTA_SSL,                            /* SSL */
1409 #endif /* CK_SSL */
1410     0
1411 };
1412 
1413 static struct keytab ftpauth[] = {      /* SET FTP AUTHTYPE cmd table */
1414     { "automatic", FTA_AUTO,  CM_INV },
1415 #ifdef FTP_GSSAPI
1416     { "gssapi-krb5", FTA_GK5, 0 },
1417 #endif /* FTP_GSSAPI */
1418 #ifdef FTP_KRB4
1419     { "k4",       FTA_K4,     CM_INV },
1420 #endif /* FTP_KRB4 */
1421 #ifdef FTP_GSSAPI
1422     { "k5",        FTA_GK5,   CM_INV },
1423 #endif /* FTP_GSSAPI */
1424 #ifdef FTP_KRB4
1425     { "kerberos4", FTA_K4,    0 },
1426 #endif /* FTP_KRB4 */
1427 #ifdef FTP_GSSAPI
1428     { "kerberos5", FTA_GK5,   CM_INV },
1429 #endif /* FTP_GSSAPI */
1430 #ifdef FTP_KRB4
1431     { "kerberos_iv",FTA_K4,   CM_INV },
1432 #endif /* FTP_KRB4 */
1433 #ifdef FTP_GSSAPI
1434     { "kerberos_v", FTA_GK5,  CM_INV },
1435 #endif /* FTP_GSSAPI */
1436 #ifdef FTP_KRB4
1437     { "krb4",     FTA_K4,     CM_INV },
1438 #endif /* FTP_KRB4 */
1439 #ifdef FTP_GSSAPI
1440     { "krb5",     FTA_GK5,    CM_INV },
1441 #endif /* FTP_GSSAPI */
1442 #ifdef FTP_SRP
1443     { "srp",      FTA_SRP,     0 },
1444 #endif /* FTP_SRP */
1445 #ifdef CK_SSL
1446     { "ssl",      FTA_SSL,     0 },
1447     { "tls",      FTA_TLS,     0 },
1448 #endif /* CK_SSL */
1449     { "", 0, 0 }
1450 };
1451 static int nftpauth = (sizeof(ftpauth) / sizeof(struct keytab)) - 1;
1452 
1453 #ifdef FTP_SRP
1454 #define SRP_CIPHER 1
1455 #define SRP_HASH   2
1456 static struct keytab ftpsrp[] = {      /* SET FTP SRP command table */
1457     { "cipher",   SRP_CIPHER,     0 },
1458     { "hash",     SRP_HASH,       0 },
1459     { "", 0, 0 }
1460 };
1461 static int nftpsrp = (sizeof(ftpsrp) / sizeof(struct keytab)) - 1;
1462 #endif /* FTP_SRP */
1463 #endif /* FTP_SECURITY */
1464 
1465 static struct keytab ftpset[] = {       /* SET FTP commmand table */
1466     { "anonymous-password",       FTS_APW, 0 },
1467 #ifdef FTP_SECURITY
1468     { "authtype",                 FTS_ATP, 0 },
1469     { "autoauthentication",       FTS_AUT, 0 },
1470     { "autoencryption",           FTS_CRY, 0 },
1471 #endif /* FTP_SECURITY */
1472     { "autologin",                FTS_LOG, 0 },
1473     { "bug",                      FTS_BUG, 0 },
1474 #ifndef NOCSETS
1475     { "character-set-translation",FTS_XLA, 0 },
1476 #endif /* NOCSETS */
1477     { "collision",                FTS_FNC, 0 },
1478 #ifdef FTP_SECURITY
1479     { "command-protection-level", FTS_CPL, 0 },
1480     { "cpl",                      FTS_CPL, CM_INV },
1481     { "credential-forwarding",    FTS_CFW, 0 },
1482     { "da",                       FTS_DAT, CM_INV|CM_ABR },
1483     { "data-protection-level",    FTS_DPL, 0 },
1484 #endif /* FTP_SECURITY */
1485     { "dates",                    FTS_DAT, 0 },
1486     { "debug",                    FTS_DBG, 0 },
1487     { "display",                  FTS_DIS, 0 },
1488 #ifdef FTP_SECURITY
1489     { "dpl",                      FTS_DPL, CM_INV },
1490 #endif /* FTP_SECURITY */
1491     { "error-action",             FTS_ERR, 0 },
1492     { "filenames",                FTS_CNV, 0 },
1493     { "get-filetype-switching",   FTS_GFT, 0 },
1494     { "passive-mode",             FTS_PSV, 0 },
1495     { "pasv",                     FTS_PSV, CM_INV },
1496     { "permissions",              FTS_PRM, 0 },
1497     { "progress-messages",        FTS_TST, 0 },
1498     { "send-port-commands",       FTS_SPC, 0 },
1499 #ifndef NOCSETS
1500     { "server-character-set",     FTS_CSR, 0 },
1501 #endif /* NOCSETS */
1502     { "server-time-offset",       FTS_STO, 0 },
1503 #ifdef FTP_SRP
1504     { "srp",                      FTS_SRP, 0 },
1505 #else
1506     { "srp",                      FTS_SRP, CM_INV },
1507 #endif /* FTP_SRP */
1508 #ifdef FTP_TIMEOUT
1509     { "timeout",                  FTS_TMO, 0 },
1510 #endif	/* FTP_TIMEOUT */
1511     { "type",                     FTS_TYP, 0 },
1512     { "unique-server-names",      FTS_USN, 0 },
1513     { "verbose-mode",             FTS_VBM, 0 },
1514     { "", 0, 0 }
1515 };
1516 static int nftpset = (sizeof(ftpset) / sizeof(struct keytab)) - 1;
1517 
1518 /*
1519   GET and PUT switches are approximately the same as Kermit GET and SEND,
1520   and use the same SND_xxx definitions, but hijack a couple for FTP use.
1521   Don't just make up new ones, since the number of SND_xxx options must be
1522   known in advance for the switch-parsing arrays.
1523 */
1524 #define SND_USN SND_PRO                 /* /UNIQUE instead of /PROTOCOL */
1525 #define SND_PRM SND_PIP                 /* /PERMISSIONS instead of /PIPES */
1526 #define SND_TEN SND_CAL                 /* /TENEX instead of /CALIBRATE */
1527 
1528 static struct keytab putswi[] = {       /* FTP PUT switch table */
1529     { "/after",                SND_AFT, CM_ARG },
1530 #ifdef PUTARRAY
1531     { "/array",                SND_ARR, CM_ARG },
1532 #endif /* PUTARRAY */
1533     { "/as",                   SND_ASN, CM_ARG|CM_INV|CM_ABR },
1534     { "/as-name",              SND_ASN, CM_ARG },
1535     { "/ascii",                SND_TXT, CM_INV },
1536     { "/b",                    SND_BIN, CM_INV|CM_ABR },
1537     { "/before",               SND_BEF, CM_ARG },
1538     { "/binary",               SND_BIN, 0 },
1539 #ifdef PUTPIPE
1540     { "/command",              SND_CMD, CM_PSH },
1541 #endif /* PUTPIPE */
1542 #ifdef COMMENT
1543 /* This works but it's dangerous */
1544 #ifdef DOUPDATE
1545     { "/dates-differ",         SND_DIF, CM_INV },
1546 #endif /* DOUPDATE */
1547 #endif /* COMMENT */
1548     { "/delete",               SND_DEL, 0 },
1549 #ifdef UNIXOROSK
1550     { "/dotfiles",             SND_DOT, 0 },
1551 #endif /* UNIXOROSK */
1552     { "/error-action",         SND_ERR, CM_ARG },
1553     { "/except",               SND_EXC, CM_ARG },
1554     { "/filenames",            SND_NAM, CM_ARG },
1555 #ifdef PIPESEND
1556 #ifndef NOSPL
1557     { "/filter",               SND_FLT, CM_ARG|CM_PSH },
1558 #endif /* NOSPL */
1559 #endif /* PIPESEND */
1560 #ifdef CKSYMLINK
1561     { "/followlinks",          SND_LNK, 0 },
1562 #endif /* CKSYMLINK */
1563 #ifdef VMS
1564     { "/image",                SND_IMG, 0 },
1565 #else
1566     { "/image",                SND_BIN, CM_INV },
1567 #endif /* VMS */
1568     { "/larger-than",          SND_LAR, CM_ARG },
1569     { "/listfile",             SND_FIL, CM_ARG },
1570 #ifndef NOCSETS
1571     { "/local-character-set",  SND_CSL, CM_ARG },
1572 #endif /* NOCSETS */
1573 #ifdef CK_TMPDIR
1574     { "/move-to",              SND_MOV, CM_ARG },
1575 #endif /* CK_TMPDIR */
1576     { "/nobackupfiles",        SND_NOB, 0 },
1577 #ifdef UNIXOROSK
1578     { "/nodotfiles",           SND_NOD, 0 },
1579 #endif /* UNIXOROSK */
1580 #ifdef CKSYMLINK
1581     { "/nofollowlinks",        SND_NLK, 0 },
1582 #endif /* CKSYMLINK */
1583 
1584     { "/not-after",            SND_NAF, CM_ARG },
1585     { "/not-before",           SND_NBE, CM_ARG },
1586 #ifdef UNIX
1587     { "/permissions",          SND_PRM, CM_ARG },
1588 #else
1589     { "/permissions",          SND_PRM, CM_ARG|CM_INV },
1590 #endif /* UNIX */
1591     { "/quiet",                SND_SHH, 0 },
1592 #ifdef FTP_RESTART
1593     { "/recover",              SND_RES, 0 },
1594 #endif /* FTP_RESTART */
1595 #ifdef RECURSIVE
1596     { "/recursive",            SND_REC, 0 },
1597 #endif /* RECURSIVE */
1598     { "/rename-to",            SND_REN, CM_ARG },
1599 #ifdef FTP_RESTART
1600     { "/restart",              SND_RES, CM_INV },
1601 #endif /* FTP_RESTART */
1602 #ifndef NOCSETS
1603     { "/server-character-set", SND_CSR, CM_ARG },
1604 #endif /* NOCSETS */
1605     { "/server-rename-to",     SND_SRN, CM_ARG },
1606     { "/simulate",             SND_SIM, 0 },
1607     { "/since",                SND_AFT, CM_INV|CM_ARG },
1608     { "/smaller-than",         SND_SMA, CM_ARG },
1609 #ifdef COMMENT
1610     { "/starting-at",          SND_STA, CM_ARG },
1611 #endif /* COMMENT */
1612 #ifdef RECURSIVE
1613     { "/subdirectories",       SND_REC, CM_INV },
1614 #endif /* RECURSIVE */
1615     { "/tenex",                SND_TEN, 0 },
1616     { "/text",                 SND_TXT, 0 },
1617 #ifndef NOCSETS
1618     { "/transparent",          SND_XPA, 0 },
1619 #endif /* NOCSETS */
1620     { "/type",                 SND_TYP, CM_ARG },
1621 #ifdef DOUPDATE
1622     { "/update",               SND_UPD, 0 },
1623 #endif /* DOUPDATE */
1624     { "/unique-server-names",  SND_USN, 0 },
1625     { "", 0, 0 }
1626 };
1627 static int nputswi = (sizeof(putswi) / sizeof(struct keytab)) - 1;
1628 
1629 static struct keytab getswi[] = {       /* FTP [M]GET switch table */
1630     { "/after",                SND_AFT, CM_INV },
1631     { "/as",                   SND_ASN, CM_ARG|CM_INV|CM_ABR },
1632     { "/as-name",              SND_ASN, CM_ARG },
1633     { "/ascii",                SND_TXT, CM_INV },
1634     { "/before",               SND_BEF, CM_INV },
1635     { "/binary",               SND_BIN, 0 },
1636     { "/collision",            SND_COL, CM_ARG },
1637 #ifdef PUTPIPE
1638     { "/command",              SND_CMD, CM_PSH },
1639 #endif /* PUTPIPE */
1640     { "/delete",               SND_DEL, 0 },
1641     { "/error-action",         SND_ERR, CM_ARG },
1642     { "/except",               SND_EXC, CM_ARG },
1643     { "/filenames",            SND_NAM, CM_ARG },
1644 #ifdef PIPESEND
1645 #ifndef NOSPL
1646     { "/filter",               SND_FLT, CM_ARG|CM_PSH },
1647 #endif /* NOSPL */
1648 #endif /* PIPESEND */
1649 #ifdef VMS
1650     { "/image",                SND_IMG, 0 },
1651 #else
1652     { "/image",                SND_BIN, CM_INV },
1653 #endif /* VMS */
1654     { "/larger-than",          SND_LAR, CM_ARG },
1655     { "/listfile",             SND_FIL, CM_ARG },
1656 #ifndef NOCSETS
1657     { "/local-character-set",  SND_CSL, CM_ARG },
1658 #endif /* NOCSETS */
1659     { "/match",                SND_PAT, CM_ARG },
1660     { "/ml",                   SND_MLS, CM_INV|CM_ABR },
1661     { "/mls",                  SND_MLS, CM_INV|CM_ABR },
1662     { "/mlsd",                 SND_MLS, 0 },
1663     { "/mlst",                 SND_MLS, CM_INV },
1664 #ifdef CK_TMPDIR
1665     { "/move-to",              SND_MOV, CM_ARG },
1666 #endif /* CK_TMPDIR */
1667     { "/namelist",             SND_NML, CM_ARG },
1668     { "/nlst",                 SND_NLS, 0 },
1669     { "/nobackupfiles",        SND_NOB, 0 },
1670     { "/nodotfiles",           SND_NOD, 0 },
1671 #ifdef DOUPDATE
1672     { "/dates-differ",         SND_DIF, CM_INV },
1673 #endif /* DOUPDATE */
1674     { "/not-after",            SND_NAF, CM_INV },
1675     { "/not-before",           SND_NBE, CM_INV },
1676     { "/permissions",          SND_PRM, CM_INV },
1677     { "/quiet",                SND_SHH, 0 },
1678 #ifdef FTP_RESTART
1679     { "/recover",              SND_RES, 0 },
1680 #endif /* FTP_RESTART */
1681 #ifdef RECURSIVE
1682     { "/recursive",            SND_REC, 0 },
1683 #endif /* RECURSIVE */
1684     { "/rename-to",            SND_REN, CM_ARG },
1685 #ifdef FTP_RESTART
1686     { "/restart",              SND_RES, CM_INV },
1687 #endif /* FTP_RESTART */
1688 #ifndef NOCSETS
1689     { "/server-character-set", SND_CSR, CM_ARG },
1690 #endif /* NOCSETS */
1691     { "/server-rename-to",     SND_SRN, CM_ARG },
1692     { "/smaller-than",         SND_SMA, CM_ARG },
1693 #ifdef RECURSIVE
1694     { "/subdirectories",       SND_REC, CM_INV },
1695 #endif /* RECURSIVE */
1696     { "/text",                 SND_TXT, 0 },
1697     { "/tenex",                SND_TEN, 0 },
1698 #ifndef NOCSETS
1699     { "/transparent",          SND_XPA, 0 },
1700 #endif /* NOCSETS */
1701     { "/to-screen",            SND_MAI, 0 },
1702 #ifdef DOUPDATE
1703     { "/update",               SND_UPD, CM_INV },
1704 #endif /* DOUPDATE */
1705     { "", 0, 0 }
1706 };
1707 static int ngetswi = (sizeof(getswi) / sizeof(struct keytab)) - 1;
1708 
1709 static struct keytab delswi[] = {       /* FTP [M]DELETE switch table */
1710     { "/error-action",         SND_ERR, CM_ARG },
1711     { "/except",               SND_EXC, CM_ARG },
1712     { "/filenames",            SND_NAM, CM_ARG },
1713     { "/larger-than",          SND_LAR, CM_ARG },
1714     { "/nobackupfiles",        SND_NOB, 0 },
1715 #ifdef UNIXOROSK
1716     { "/nodotfiles",           SND_NOD, 0 },
1717 #endif /* UNIXOROSK */
1718     { "/quiet",                SND_SHH, 0 },
1719 #ifdef RECURSIVE
1720     { "/recursive",            SND_REC, 0 },
1721 #endif /* RECURSIVE */
1722     { "/smaller-than",         SND_SMA, CM_ARG },
1723 #ifdef RECURSIVE
1724     { "/subdirectories",       SND_REC, CM_INV },
1725 #endif /* RECURSIVE */
1726     { "", 0, 0 }
1727 };
1728 static int ndelswi = (sizeof(delswi) / sizeof(struct keytab)) - 1;
1729 
1730 static struct keytab fntab[] = {        /* Filename conversion keyword table */
1731     { "automatic",    2, CNV_AUTO },
1732     { "converted",    1, CNV_CNV  },
1733     { "literal",      0, CNV_LIT  }
1734 };
1735 static int nfntab = (sizeof(fntab) / sizeof(struct keytab));
1736 
1737 static struct keytab ftptyp[] = {       /* SET FTP TYPE table */
1738     { "ascii",        FTT_ASC, 0 },
1739     { "binary",       FTT_BIN, 0 },
1740     { "tenex",        FTT_TEN, 0 },
1741     { "text",         FTT_ASC, CM_INV },
1742     { "", 0, 0 }
1743 };
1744 static int nftptyp = (sizeof(ftptyp) / sizeof(struct keytab)) - 1;
1745 
1746 #ifdef FTP_SECURITY
1747 static struct keytab ftppro[] = {       /* SET FTP PROTECTION-LEVEL table */
1748     { "clear",        FPL_CLR, 0 },
1749     { "confidential", FPL_CON, 0 },
1750     { "private",      FPL_PRV, 0 },
1751     { "safe",         FPL_SAF, 0 },
1752     { "", 0, 0 }
1753 };
1754 static int nftppro = (sizeof(ftppro) / sizeof(struct keytab)) - 1;
1755 #endif /* FTP_SECURITY */
1756 
1757 /* Definitions for FTP from RFC765. */
1758 
1759 /* Reply codes */
1760 
1761 #define REPLY_PRELIM    1               /* Positive preliminary */
1762 #define REPLY_COMPLETE  2               /* Positive completion */
1763 #define REPLY_CONTINUE  3               /* Positive intermediate */
1764 #define REPLY_TRANSIENT 4               /* Transient negative completion */
1765 #define REPLY_ERROR     5               /* Permanent negative completion */
1766 #define REPLY_SECURE    6               /* Security encoded message */
1767 
1768 /* Form codes and names */
1769 
1770 #define FORM_N 1                        /* Non-print */
1771 #define FORM_T 2                        /* Telnet format effectors */
1772 #define FORM_C 3                        /* Carriage control (ASA) */
1773 
1774 /* Structure codes and names */
1775 
1776 #define STRU_F 1                        /* File (no record structure) */
1777 #define STRU_R 2                        /* Record structure */
1778 #define STRU_P 3                        /* Page structure */
1779 
1780 /* Mode types and names */
1781 
1782 #define MODE_S 1                        /* Stream */
1783 #define MODE_B 2                        /* Block */
1784 #define MODE_C 3                        /* Compressed */
1785 
1786 /* Protection levels and names */
1787 
1788 #define PROT_C 1                        /* Clear */
1789 #define PROT_S 2                        /* Safe */
1790 #define PROT_P 3                        /* Private */
1791 #define PROT_E 4                        /* Confidential */
1792 
1793 #ifdef COMMENT                          /* Not used */
1794 #ifdef FTP_NAMES
1795 char *strunames[]  =  {"0", "File",     "Record", "Page" };
1796 char *formnames[]  =  {"0", "Nonprint", "Telnet", "Carriage-control" };
1797 char *modenames[]  =  {"0", "Stream",   "Block",  "Compressed" };
1798 char *levelnames[] =  {"0", "Clear",    "Safe",   "Private",  "Confidential" };
1799 #endif /* FTP_NAMES */
1800 
1801 /* Record Tokens */
1802 
1803 #define REC_ESC '\377'                  /* Record-mode Escape */
1804 #define REC_EOR '\001'                  /* Record-mode End-of-Record */
1805 #define REC_EOF '\002'                  /* Record-mode End-of-File */
1806 
1807 /* Block Header */
1808 
1809 #define BLK_EOR           0x80          /* Block is End-of-Record */
1810 #define BLK_EOF           0x40          /* Block is End-of-File */
1811 #define BLK_REPLY_ERRORS  0x20          /* Block might have errors */
1812 #define BLK_RESTART       0x10          /* Block is Restart Marker */
1813 #define BLK_BYTECOUNT 2                 /* Bytes in this block */
1814 #endif /* COMMENT */
1815 
1816 #define RADIX_ENCODE 0                  /* radix_encode() function codes */
1817 #define RADIX_DECODE 1
1818 
1819 /*
1820   The default setpbsz() value in the Unix FTP client is 1<<20 (1MB).  This
1821   results in a serious performance degradation due to the increased number
1822   of page faults and the inability to overlap encrypt/decrypt, file i/o, and
1823   network i/o.  So instead we set the value to 1<<13 (8K), about half the size
1824   of the typical TCP window.  Maybe we should add a command to allow the value
1825   to be changed.
1826 */
1827 #define DEFAULT_PBSZ 1<<13
1828 
1829 /* Prototypes */
1830 
1831 _PROTOTYP(int remtxt, (char **) );
1832 _PROTOTYP(char * gskreason, (int) );
1833 _PROTOTYP(static int ftpclose,(void));
1834 _PROTOTYP(static int zzsend, (int, CHAR));
1835 _PROTOTYP(static int getreply,(int,int,int,int,int));
1836 _PROTOTYP(static int radix_encode,(CHAR[], CHAR[], int, int *, int));
1837 _PROTOTYP(static int setpbsz,(unsigned int));
1838 _PROTOTYP(static int recvrequest,(char *,char *,char *,char *,
1839   int,int,char *,int,int,int));
1840 _PROTOTYP(static int ftpcmd,(char *,char *,int,int,int));
1841 _PROTOTYP(static int fts_cpl,(int));
1842 _PROTOTYP(static int fts_dpl,(int));
1843 #ifdef FTP_SECURITY
1844 _PROTOTYP(static int ftp_auth, (void));
1845 #endif /* FTP_SECURITY */
1846 _PROTOTYP(static int ftp_user, (char *, char *, char *));
1847 _PROTOTYP(static int ftp_login, (char *));
1848 _PROTOTYP(static int ftp_reset, (void));
1849 _PROTOTYP(static int ftp_rename, (char *, char *));
1850 _PROTOTYP(static int ftp_umask, (char *));
1851 _PROTOTYP(static int secure_flush, (int));
1852 #ifdef COMMENT
1853 _PROTOTYP(static int secure_putc, (char, int));
1854 #endif /* COMMENT */
1855 _PROTOTYP(static int secure_write, (int, CHAR *, unsigned int));
1856 _PROTOTYP(static int scommand, (char *));
1857 _PROTOTYP(static int secure_putbuf, (int, CHAR *, unsigned int));
1858 _PROTOTYP(static int secure_getc, (int, int));
1859 _PROTOTYP(static int secure_getbyte, (int, int));
1860 _PROTOTYP(static int secure_read, (int, char *, int));
1861 _PROTOTYP(static int initconn, (void));
1862 _PROTOTYP(static int dataconn, (char *));
1863 _PROTOTYP(static int setprotbuf,(unsigned int));
1864 _PROTOTYP(static int sendrequest, (char *, char *, char *, int,int,int,int));
1865 
1866 _PROTOTYP(static char * radix_error,(int));
1867 _PROTOTYP(static char * ftp_hookup,(char *, int, int));
1868 _PROTOTYP(static CHAR * remote_files, (int, CHAR *, CHAR *, int));
1869 
1870 _PROTOTYP(static VOID mlsreset, (void));
1871 _PROTOTYP(static VOID secure_error, (char *fmt, ...));
1872 _PROTOTYP(static VOID lostpeer, (void));
1873 _PROTOTYP(static VOID cancel_remote, (int));
1874 _PROTOTYP(static VOID changetype, (int, int));
1875 
1876 _PROTOTYP(static sigtype cmdcancel, (int));
1877 
1878 #ifdef FTP_SRP
1879 _PROTOTYP(static int srp_reset, ());
1880 _PROTOTYP(static int srp_ftp_auth, (char *,char *,char *));
1881 _PROTOTYP(static int srp_put, (CHAR *, CHAR **, int, int *));
1882 _PROTOTYP(static int srp_get, (CHAR **, CHAR **, int *, int *));
1883 _PROTOTYP(static int srp_encode, (int, CHAR *, CHAR *, unsigned int));
1884 _PROTOTYP(static int srp_decode, (int, CHAR *, CHAR *, unsigned int));
1885 _PROTOTYP(static int srp_selcipher, (char *));
1886 _PROTOTYP(static int srp_selhash, (char *));
1887 #endif /* FTP_SRP */
1888 
1889 #ifdef FTP_GSSAPI
1890 _PROTOTYP(static void user_gss_error,(OM_uint32, OM_uint32,char *));
1891 #endif /* FTP_GSSAPI */
1892 
1893 /*  D O F T P A R G  --  Do an FTP command-line argument.  */
1894 
1895 #ifdef FTP_SECURITY
1896 #ifndef NOICP
1897 #define FT_NOGSS   1
1898 #define FT_NOK4    2
1899 #define FT_NOSRP   3
1900 #define FT_NOSSL   4
1901 #define FT_NOTLS   5
1902 #define FT_CERTFI  6
1903 #define FT_OKCERT  7
1904 #define FT_DEBUG   8
1905 #define FT_KEY     9
1906 #define FT_SECURE 10
1907 #define FT_VERIFY 11
1908 
1909 static struct keytab ftpztab[] = {
1910     { "!gss",    FT_NOGSS,  0 },
1911     { "!krb4",   FT_NOK4,   0 },
1912     { "!srp",    FT_NOSRP,  0 },
1913     { "!ssl",    FT_NOSSL,  0 },
1914     { "!tls",    FT_NOTLS,  0 },
1915     { "cert",    FT_CERTFI, CM_ARG },
1916     { "certsok", FT_OKCERT, 0 },
1917     { "debug",   FT_DEBUG,  0 },
1918     { "key",     FT_KEY,    CM_ARG },
1919     { "nogss",   FT_NOGSS,  0 },
1920     { "nokrb4",  FT_NOK4,   0 },
1921     { "nosrp",   FT_NOSRP,  0 },
1922     { "nossl",   FT_NOSSL,  0 },
1923     { "notls",   FT_NOTLS,  0 },
1924 #ifdef COMMENT
1925     { "secure",  FT_SECURE, 0 },
1926 #endif /* COMMENT */
1927     { "verify",  FT_VERIFY, CM_ARG },
1928     { "", 0, 0 }
1929 };
1930 static int nftpztab = sizeof(ftpztab) / sizeof(struct keytab) - 1;
1931 
1932 /*
1933   The following cipher and hash tables should be replaced with
1934   dynamicly created versions based upon the linked library.
1935 */
1936 #define SRP_BLOWFISH_ECB    1
1937 #define SRP_BLOWFISH_CBC    2
1938 #define SRP_BLOWFISH_CFB64  3
1939 #define SRP_BLOWFISH_OFB64  4
1940 #define SRP_CAST5_ECB       5
1941 #define SRP_CAST5_CBC       6
1942 #define SRP_CAST5_CFB64     7
1943 #define SRP_CAST5_OFB64     8
1944 #define SRP_DES_ECB         9
1945 #define SRP_DES_CBC        10
1946 #define SRP_DES_CFB64      11
1947 #define SRP_DES_OFB64      12
1948 #define SRP_DES3_ECB       13
1949 #define SRP_DES3_CBC       14
1950 #define SRP_DES3_CFB64     15
1951 #define SRP_DES3_OFB64     16
1952 
1953 static struct keytab ciphertab[] = {
1954     { "blowfish_ecb",   SRP_BLOWFISH_ECB,   0 },
1955     { "blowfish_cbc",   SRP_BLOWFISH_CBC,   0 },
1956     { "blowfish_cfb64", SRP_BLOWFISH_CFB64, 0 },
1957     { "blowfish_ofb64", SRP_BLOWFISH_OFB64, 0 },
1958     { "cast5_ecb",      SRP_CAST5_ECB,      0 },
1959     { "cast5_cbc",      SRP_CAST5_CBC,      0 },
1960     { "cast5_cfb64",    SRP_CAST5_CFB64,    0 },
1961     { "cast5_ofb64",    SRP_CAST5_OFB64,    0 },
1962     { "des_ecb",        SRP_DES_ECB,        0 },
1963     { "des_cbc",        SRP_DES_CBC,        0 },
1964     { "des_cfb64",      SRP_DES_CFB64,      0 },
1965     { "des_ofb64",      SRP_DES_OFB64,      0 },
1966     { "des3_ecb",       SRP_DES3_ECB,       0 },
1967     { "des3_cbc",       SRP_DES3_CBC,       0 },
1968     { "des3_cfb64",     SRP_DES3_CFB64,     0 },
1969     { "des3_ofb64",     SRP_DES3_OFB64,     0 },
1970     { "none",           0, 0 },
1971     { "", 0, 0 }
1972 };
1973 static int nciphertab = sizeof(ciphertab) / sizeof(struct keytab) - 1;
1974 
1975 #define SRP_MD5  1
1976 #define SRP_SHA  2
1977 static struct keytab hashtab[] = {
1978     { "md5",              SRP_MD5,        0 },
1979     { "none",             0,              0 },
1980     { "sha",              SRP_SHA,        0 },
1981     { "", 0, 0 }
1982 };
1983 static int nhashtab = sizeof(hashtab) / sizeof(struct keytab) - 1;
1984 #endif /* NOICP */
1985 #endif /* FTP_SECURITY */
1986 
1987 static char *
strval(s1,s2)1988 strval(s1,s2) char * s1, * s2; {
1989     if (!s1) s1 = "";
1990     if (!s2) s2 = "";
1991     return(*s1 ? s1 : (*s2 ? s2 : "(none)"));
1992 }
1993 
1994 #ifndef NOCSETS
1995 static char * rfnptr = NULL;
1996 static int rfnlen = 0;
1997 static char rfnbuf[RFNBUFSIZ];          /* Remote filename translate buffer */
1998 static char * xgnbp = NULL;
1999 
2000 static int
strgetc()2001 strgetc() {                             /* Helper function for xgnbyte() */
2002     int c;
2003     if (!xgnbp)
2004       return(-1);
2005     if (!*xgnbp)
2006       return(-1);
2007     c = (unsigned) *xgnbp++;
2008     return(((unsigned) c) & 0xff);
2009 }
2010 
2011 static int                              /* Helper function for xpnbyte() */
2012 #ifdef CK_ANSIC
strputc(char c)2013 strputc(char c)
2014 #else
2015 strputc(c) char c;
2016 #endif /* CK_ANSIC */
2017 {
2018     rfnlen = rfnptr - rfnbuf;
2019     if (rfnlen >= (RFNBUFSIZ - 1))
2020       return(-1);
2021     *rfnptr++ = c;
2022     *rfnptr = NUL;
2023     return(0);
2024 }
2025 
2026 static int
2027 #ifdef CK_ANSIC
xprintc(char c)2028 xprintc(char c)
2029 #else
2030 xprintc(c) char c;
2031 #endif /* CK_ANSIC */
2032 {
2033     printf("%c",c);
2034     return(0);
2035 }
2036 
2037 static VOID
bytswap(c0,c1)2038 bytswap(c0,c1) int * c0, * c1; {
2039     int t;
2040     t = *c0;
2041     *c0 = *c1;
2042     *c1 = t;
2043 }
2044 #endif /* NOCSETS */
2045 
2046 #ifdef CKLOGDIAL
2047 char ftplogbuf[CXLOGBUFL] = { NUL, NUL }; /* Connection Log */
2048 int ftplogactive = 0;
2049 long ftplogprev = 0L;
2050 
2051 VOID
ftplogend()2052 ftplogend() {
2053     extern int dialog;
2054     extern char diafil[];
2055     long d1, d2, t1, t2;
2056     char buf[32], * p;
2057 
2058     debug(F111,"ftp cx log active",ckitoa(dialog),ftplogactive);
2059     debug(F110,"ftp cx log buf",ftplogbuf,0);
2060 
2061     if (!ftplogactive || !ftplogbuf[0]) /* No active record */
2062       return;
2063 
2064     ftplogactive = 0;                   /* Record is not active */
2065 
2066     d1 = mjd((char *)ftplogbuf);        /* Get start date of this session */
2067     ckstrncpy(buf,ckdate(),31);         /* Get current date */
2068     d2 = mjd(buf);                      /* Convert them to mjds */
2069     p = ftplogbuf;                      /* Get start time */
2070     p[11] = NUL;
2071     p[14] = NUL;                        /* Convert to seconds */
2072     t1 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2073     p[11] = ':';
2074     p[14] = ':';
2075     p = buf;                            /* Get end time */
2076     p[11] = NUL;
2077     p[14] = NUL;
2078     t2 = atol(p+9) * 3600L + atol(p+12) * 60L + atol(p+15);
2079     t2 = ((d2 - d1) * 86400L) + (t2 - t1); /* Compute elapsed time */
2080     if (t2 > -1L) {
2081         ftplogprev = t2;
2082         p = hhmmss(t2);
2083         ckstrncat(ftplogbuf,"E=",CXLOGBUFL); /* Append to log record */
2084         ckstrncat(ftplogbuf,p,CXLOGBUFL);
2085     } else
2086       ftplogprev = 0L;
2087     debug(F101,"ftp cx log dialog","",dialog);
2088     if (dialog) {                       /* If logging */
2089         int x;
2090         x = diaopn(diafil,1,1);         /* Open log in append mode */
2091         if (x > 0) {
2092             debug(F101,"ftp cx log open","",x);
2093             x = zsoutl(ZDIFIL,ftplogbuf); /* Write the record */
2094             debug(F101,"ftp cx log write","",x);
2095             x = zclose(ZDIFIL);         /* Close the log */
2096             debug(F101,"ftp cx log close","",x);
2097         }
2098     }
2099 }
2100 
2101 VOID
dologftp()2102 dologftp() {
2103     ftplogend();                        /* Previous session not closed out? */
2104     ftplogprev = 0L;
2105     ftplogactive = 1;                   /* Record is active */
2106 
2107     ckmakxmsg(ftplogbuf,CXLOGBUFL,
2108               ckdate()," ",strval(ftp_logname,NULL)," ",ckgetpid(),
2109               " T=FTP N=", strval(ftp_host,NULL)," H=",myhost,
2110               " P=", ckitoa(ftp_port)," "); /* SMS 2007/02/15 */
2111     debug(F110,"ftp cx log begin",ftplogbuf,0);
2112 }
2113 #endif /* CKLOGDIAL */
2114 
2115 static char * dummy[2] = { NULL, NULL };
2116 
2117 static struct keytab modetab[] = {
2118     { "active",  0, 0 },
2119     { "passive", 1, 0 }
2120 };
2121 
2122 #ifndef NOCMDL
2123 int                                     /* Called from ckuusy.c */
2124 #ifdef CK_ANSIC
doftparg(char c)2125 doftparg(char c)
2126 #else
2127 doftparg(c) char c;
2128 #endif /* CK_ANSIC */
2129 /* doftparg */ {
2130     int x, z;
2131     char *xp;
2132     extern char **xargv, *xarg0;
2133     extern int xargc, stayflg, haveftpuid;
2134     extern char uidbuf[];
2135 
2136     xp = *xargv+1;                      /* Pointer for bundled args */
2137     while (c) {
2138         if (ckstrchr("MuDPkcHzm",c)) {  /* Options that take arguments */
2139             if (*(xp+1)) {
2140                 fatal("?Invalid argument bundling");
2141             }
2142             xargv++, xargc--;
2143             if ((xargc < 1) || (**xargv == '-')) {
2144                 fatal("?Required argument missing");
2145             }
2146         }
2147         switch (c) {                    /* Big switch on arg */
2148           case 'h':                     /* help */
2149            printf("C-Kermit's FTP client command-line personality.  Usage:\n");
2150             printf("  %s [ options ] host [ port ] [-pg files ]\n\n",xarg0);
2151             printf("Options:\n");
2152             printf("  -h           = help (this message)\n");
2153             printf("  -m mode      = \"passive\" (default) or \"active\"\n");
2154             printf("  -u name      = username for autologin (or -M)\n");
2155             printf("  -P password  = password for autologin (RISKY)\n");
2156             printf("  -A           = autologin anonymously\n");
2157             printf("  -D directory = cd after autologin\n");
2158             printf("  -b           = force binary mode\n");
2159             printf("  -a           = force text (\"ascii\") mode (or -T)\n");
2160             printf("  -d           = debug (double to add timestamps)\n");
2161             printf("  -n           = no autologin\n");
2162             printf("  -v           = verbose (default)\n");
2163             printf("  -q           = quiet\n");
2164             printf("  -S           = Stay (issue command prompt when done)\n");
2165             printf("  -Y           = do not execute Kermit init file\n");
2166             printf("  -p files     = files to put after autologin (or -s)\n");
2167             printf("  -g files     = files to get after autologin\n");
2168             printf("  -R           = recursive (for use with -p)\n");
2169 
2170 #ifdef FTP_SECURITY
2171             printf("\nSecurity options:\n");
2172             printf("  -k realm     = Kerberos 4 realm\n");
2173             printf("  -f           = Kerboros 5 credentials forwarding\n");
2174             printf("  -x           = autoencryption mode\n");
2175             printf("  -c cipher    = SRP cipher type\n");
2176             printf("  -H hash      = SRP encryption hash\n");
2177             printf("  -z option    = Security options\n");
2178 #endif /* FTP_SECURITY */
2179 
2180             printf("\n-p or -g, if given, should be last.  Example:\n");
2181             printf("  ftp -A kermit.columbia.edu -D kermit -ag TESTFILE\n");
2182 
2183             doexit(GOOD_EXIT,-1);
2184             break;
2185 
2186           case 'R':                     /* Recursive */
2187             recursive = 1;
2188             break;
2189 
2190           case 'd':                     /* Debug */
2191 #ifdef DEBUG
2192             if (deblog) {
2193                 extern int debtim;
2194                 debtim = 1;
2195             } else {
2196                 deblog = debopn("debug.log",0);
2197                 debok = 1;
2198             }
2199 #endif /* DEBUG */
2200             /* fall thru on purpose */
2201 
2202           case 't':                     /* Trace */
2203             ftp_deb++;
2204             break;
2205 
2206           case 'n':                     /* No autologin */
2207             ftp_log = 0;
2208             break;
2209 
2210           case 'i':                     /* No prompt */
2211           case 'v':                     /* Verbose */
2212             break;                      /* (ignored) */
2213 
2214           case 'q':                     /* Quiet */
2215             quiet = 1;
2216             break;
2217 
2218           case 'S':                     /* Stay */
2219             stayflg = 1;
2220             break;
2221 
2222           case 'M':
2223           case 'u':                     /* My User Name */
2224             if ((int)strlen(*xargv) > 63) {
2225                 fatal("username too long");
2226             }
2227             ckstrncpy(uidbuf,*xargv,UIDBUFLEN);
2228             haveftpuid = 1;
2229             break;
2230 
2231           case 'A':
2232             ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2233             haveftpuid = 1;
2234             break;
2235 
2236           case 'T':                     /* Text */
2237           case 'a':                     /* "ascii" */
2238           case 'b':                     /* Binary */
2239             binary = (c == 'b') ? FTT_BIN : FTT_ASC;
2240             ftp_xfermode = XMODE_M;
2241             filepeek = 0;
2242             patterns = 0;
2243             break;
2244 
2245           case 'g':                     /* Get */
2246           case 'p':                     /* Put */
2247           case 's': {                   /* Send (= Put) */
2248               int havefiles, rc;
2249               if (ftp_action) {
2250                   fatal("Only one FTP action at a time please");
2251               }
2252               if (*(xp+1)) {
2253                   fatal("invalid argument bundling after -s");
2254               }
2255               nfils = 0;                /* Initialize file counter */
2256               havefiles = 0;            /* Assume nothing to send  */
2257               cmlist = xargv + 1;       /* Remember this pointer */
2258 
2259               while (++xargv, --xargc > 0) { /* Traverse the list */
2260                   if (c == 'g') {
2261                       havefiles++;
2262                       nfils++;
2263                       continue;
2264                   }
2265 #ifdef RECURSIVE
2266                   if (!strcmp(*xargv,".")) {
2267                       havefiles = 1;
2268                       nfils++;
2269                       recursive = 1;
2270                   } else
2271 #endif /* RECURSIVE */
2272                     if ((rc = zchki(*xargv)) > -1 || (rc == -2)) {
2273                         if  (rc != -2)
2274                           havefiles = 1;
2275                         nfils++;
2276                     } else if (iswild(*xargv) && nzxpand(*xargv,0) > 0) {
2277                         havefiles = 1;
2278                         nfils++;
2279                     }
2280               }
2281               xargc++, xargv--;         /* Adjust argv/argc */
2282               if (!havefiles) {
2283                   if (c == 'g') {
2284                       fatal("No files to put");
2285                   } else {
2286                       fatal("No files to get");
2287                   }
2288               }
2289               ftp_action = c;
2290               break;
2291           }
2292           case 'D':                     /* Directory */
2293             makestr(&ftp_rdir,*xargv);
2294             break;
2295 
2296           case 'm':                     /* Mode (Active/Passive */
2297             ftp_psv = lookup(modetab,*xargv,2,NULL);
2298             if (ftp_psv < 0) fatal("Invalid mode");
2299             break;
2300 
2301           case 'P':
2302             makestr(&ftp_tmp,*xargv);   /* You-Know-What */
2303             break;
2304 
2305           case 'Y':                     /* No initialization file */
2306             break;                      /* (already done in prescan) */
2307 
2308 #ifdef CK_URL
2309           case 'U': {                   /* URL */
2310               /* These are set by urlparse() - any not set are NULL */
2311               if (g_url.hos) {
2312 /*
2313   Kermit has accepted host:port notation since many years before URLs were
2314   invented.  Unfortunately, URLs conflict with this notation.  Thus "ftp
2315   host:449" looks like a URL and results in service = host and host = 449.
2316   Here we try to catch this situation transparently to the user.
2317 */
2318                   if (ckstrcmp(g_url.svc,"ftp",-1,0)
2319 #ifdef CK_SSL
2320                        && ckstrcmp(g_url.svc,"ftps",-1,0)
2321 #endif /* CK_SSL */
2322                        ) {
2323                       if (!g_url.usr &&
2324                           !g_url.psw &&
2325                           !g_url.por &&
2326                           !g_url.pth) {
2327                           g_url.por = g_url.hos;
2328                           g_url.hos = g_url.svc;
2329                           g_url.svc = "ftp";
2330                       } else {
2331                           ckmakmsg(tmpbuf,TMPBUFSIZ,"Non-FTP URL: service=",
2332                                    g_url.svc," host=",g_url.hos);
2333                           fatal(tmpbuf);
2334                       }
2335                   }
2336                   makestr(&ftp_host,g_url.hos);
2337                   if (g_url.usr) {
2338                       haveftpuid = 1;
2339                       ckstrncpy(uidbuf,g_url.usr,UIDBUFLEN);
2340                       makestr(&ftp_logname,uidbuf);
2341                   }
2342                   if (g_url.psw) {
2343                       makestr(&ftp_tmp,g_url.psw);
2344                   }
2345                   if (g_url.pth) {
2346                       if (!g_url.usr) {
2347                           haveftpuid = 1;
2348                           ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
2349                           makestr(&ftp_logname,uidbuf);
2350                       }
2351                       if (ftp_action) {
2352                           fatal("Only one FTP action at a time please");
2353                       }
2354                       if (!stayflg)
2355                         quiet = 1;
2356                       nfils = 1;
2357                       dummy[0] = g_url.pth;
2358                       cmlist = dummy;
2359                       ftp_action = 'g';
2360                   }
2361                   xp = NULL;
2362                   haveurl = 1;
2363               }
2364               break;
2365           }
2366 #endif /* CK_URL */
2367 
2368 #ifdef FTP_SECURITY
2369           case 'k': {                   /* K4 Realm */
2370 #ifdef FTP_KRB4
2371               ckstrncpy(ftp_realm,*xargv, REALM_SZ);
2372 #endif /* FTP_KRB4 */
2373               if (ftp_deb) printf("K4 Realm = [%s]\n",*xargv);
2374               break;
2375           }
2376           case 'f': {
2377 #ifdef FTP_GSSAPI
2378               ftp_cfw = 1;
2379               if (ftp_deb) printf("K5 Credentials Forwarding\n");
2380 #else /* FTP_GSSAPI */
2381               printf("K5 Credentials Forwarding not supported\n");
2382 #endif /* FTP_GSSAPI */
2383               break;
2384           }
2385           case 'x': {
2386               ftp_cry = 1;
2387               if (ftp_deb) printf("Autoencryption\n");
2388               break;
2389           }
2390           case 'c': {                   /* Cipher */
2391 #ifdef FTP_SRP
2392               if (!srp_selcipher(*xargv)) {
2393                   if (ftp_deb) printf("SRP cipher type: \"%s\"\n",*xargv);
2394               } else
2395                 printf("?Invalid SRP cipher type: \"%s\"\n",*xargv);
2396 #else /* FTP_SRP */
2397               printf("?SRP not supported\n");
2398 #endif /* FTP_SRP */
2399               break;
2400           }
2401           case 'H': {
2402 #ifdef FTP_SRP
2403               if (!srp_selhash(*xargv)) {
2404                   if (ftp_deb) printf("SRP hash type: \"%s\"\n",*xargv);
2405               } else
2406                 printf("?Invalid SRP hash type: \"%s\"\n",*xargv);
2407 #else /* FTP_SRP */
2408               printf("?SRP not supported\n");
2409 #endif /* FTP_SRP */
2410               break;
2411           }
2412           case 'z': {
2413               /* *xargv contains a value of the form tag=value */
2414               /* we need to lookup the tag and save the value  */
2415               char * p = NULL, * q = NULL;
2416               makestr(&p,*xargv);
2417               y = ckindex("=",p,0,0,1);
2418               if (y > 0)
2419                 p[y-1] = '\0';
2420               x = lookup(ftpztab,p,nftpztab,&z);
2421               if (x < 0) {
2422                   printf("?Invalid security option: \"%s\"\n",p);
2423               } else {
2424                   if (ftp_deb)
2425 		    printf("Security option: \"%s",p);
2426                   if (ftpztab[z].flgs & CM_ARG) {
2427                       if (y <= 0)
2428                         fatal("?Missing required value");
2429                       q = &p[y];
2430                       if (!*q)
2431                         fatal("?Missing required value");
2432                       if (ftp_deb)
2433 			printf("=%s\"",q);
2434                   }
2435                   switch (ftpztab[z].kwval) { /* -z options w/args */
2436                     case FT_NOGSS:
2437 #ifdef FTP_GSSAPI
2438                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2439                           if (ftp_auth_type[z] == FTA_GK5) {
2440                               for (y = z;
2441                                    y < (FTPATYPS-1) && ftp_auth_type[y];
2442                                    y++
2443                                    )
2444                                 ftp_auth_type[y] = ftp_auth_type[y+1];
2445                               ftp_auth_type[FTPATYPS-1] = 0;
2446                               break;
2447                           }
2448                       }
2449 #endif /* FTP_GSSAPI */
2450                       break;
2451                     case FT_NOK4:
2452 #ifdef FTP_KRB4
2453                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2454                           if (ftp_auth_type[z] == FTA_K4) {
2455                               for (y = z;
2456                                    y < (FTPATYPS-1) && ftp_auth_type[y];
2457                                    y++
2458                                    )
2459                                 ftp_auth_type[y] = ftp_auth_type[y+1];
2460                               ftp_auth_type[FTPATYPS-1] = 0;
2461                               break;
2462                           }
2463                       }
2464 #endif /* FTP_KRB4 */
2465                       break;
2466                     case FT_NOSRP:
2467 #ifdef FTP_SRP
2468                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2469                           if (ftp_auth_type[z] == FTA_SRP) {
2470                               for (y = z;
2471                                    y < (FTPATYPS-1) && ftp_auth_type[y];
2472                                    y++
2473                                    )
2474                                 ftp_auth_type[y] = ftp_auth_type[y+1];
2475                               ftp_auth_type[FTPATYPS-1] = 0;
2476                               break;
2477                           }
2478                       }
2479 #endif /* FTP_SRP */
2480                       break;
2481                     case FT_NOSSL:
2482 #ifdef CK_SSL
2483                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2484                           if (ftp_auth_type[z] == FTA_SSL) {
2485                               for (y = z;
2486                                    y < (FTPATYPS-1) && ftp_auth_type[y];
2487                                    y++
2488                                    )
2489                                 ftp_auth_type[y] = ftp_auth_type[y+1];
2490                               ftp_auth_type[FTPATYPS-1] = 0;
2491                               break;
2492                           }
2493                       }
2494 #endif /* CK_SSL */
2495                       break;
2496                     case FT_NOTLS:
2497 #ifdef CK_SSL
2498                       for (z = 0; z < FTPATYPS && ftp_auth_type[z]; z++) {
2499                           if (ftp_auth_type[z] == FTA_TLS) {
2500                               for (y = z;
2501                                    y < (FTPATYPS-1) && ftp_auth_type[y];
2502                                    y++
2503                                    )
2504                                 ftp_auth_type[y] = ftp_auth_type[y+1];
2505                               ftp_auth_type[FTPATYPS-1] = 0;
2506                               break;
2507                           }
2508                       }
2509 #endif /* CK_SSL */
2510                       break;
2511                     case FT_CERTFI:
2512 #ifdef CK_SSL
2513                       makestr(&ssl_rsa_cert_file,q);
2514 #endif /* CK_SSL */
2515                       break;
2516                     case FT_OKCERT:
2517 #ifdef CK_SSL
2518                       ssl_certsok_flag = 1;
2519 #endif /* CK_SSL */
2520                       break;
2521                     case FT_DEBUG:
2522 #ifdef DEBUG
2523                       if (deblog) {
2524                           extern int debtim;
2525                           debtim = 1;
2526                       } else {
2527                           deblog = debopn("debug.log",0);
2528                       }
2529 #endif /* DEBUG */
2530                       break;
2531                     case FT_KEY:
2532 #ifdef CK_SSL
2533                       makestr(&ssl_rsa_key_file,q);
2534 #endif /* CK_SSL */
2535                       break;
2536                     case FT_SECURE:
2537                       /* no equivalent */
2538                       break;
2539                     case FT_VERIFY:
2540 #ifdef CK_SSL
2541                       if (!rdigits(q))
2542                         printf("?Bad number: %s\n",q);
2543                       ssl_verify_flag = atoi(q);
2544 #endif /* CK_SSL */
2545                       break;
2546                   }
2547               }
2548               if (ftp_deb) printf("\"\n");
2549               free(p);
2550               break;
2551           }
2552 #endif /* FTP_SECURITY */
2553 
2554           default:
2555             fatal2(*xargv,
2556                    "unknown command-line option, type \"ftp -h\" for help"
2557                    );
2558         }
2559         if (!xp) break;
2560         c = *++xp;                      /* See if options are bundled */
2561     }
2562     return(0);
2563 }
2564 #endif /* NOCMDL */
2565 
2566 int
ftpisconnected()2567 ftpisconnected() {
2568     return(connected);
2569 }
2570 
2571 int
ftpisloggedin()2572 ftpisloggedin() {
2573     return(connected ? loggedin : 0);
2574 }
2575 
2576 int
ftpissecure()2577 ftpissecure() {
2578     return((ftp_dpl == FPL_CLR && !ssl_ftp_proxy) ? 0 : 1);
2579 }
2580 
2581 static VOID
ftscreen(n,c,z,s)2582 ftscreen(n, c, z, s) int n; char c; CK_OFF_T z; char * s; {
2583     if (displa && fdispla && !backgrd && !quiet && !out2screen) {
2584         if (!dpyactive) {
2585             ckscreen(SCR_PT,'S',(CK_OFF_T)0,"");
2586             dpyactive = 1;
2587         }
2588         ckscreen(n,c,z,s);
2589     }
2590 }
2591 
2592 #ifndef OS2
2593 /*  g m s t i m e r  --  Millisecond timer */
2594 
2595 long
gmstimer()2596 gmstimer() {
2597 #ifdef HAVE_MSECS
2598     /* For those versions of ztime() that also set global ztmsec. */
2599     char *p = NULL;
2600     long z;
2601     ztime(&p);
2602     if (!p) return(0L);
2603     if (!*p) return(0L);
2604     z = atol(p+11) * 3600L + atol(p+14) * 60L + atol(p+17);
2605     return(z * 1000 + ztmsec);
2606 #else
2607     return((long)time(NULL) * 1000L);
2608 #endif /* HAVE_MSECS */
2609 }
2610 #endif /* OS2 */
2611 
2612 /*  d o s e t f t p  --  The SET FTP command  */
2613 
2614 int
dosetftp()2615 dosetftp() {
2616     int cx;
2617     if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0) /* Set what? */
2618       return(cx);
2619     switch (cx) {
2620 
2621       case FTS_FNC:                     /* Filename collision action */
2622         if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
2623           return(x);
2624         if ((y = cmcfm()) < 0)
2625           return(y);
2626         ftp_fnc = x;
2627         return(1);
2628 
2629       case FTS_CNV:                     /* Filename conversion */
2630         if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
2631           return(x);
2632         if ((y = cmcfm()) < 0)
2633           return(y);
2634         ftp_cnv = x;
2635         return(1);
2636 
2637       case FTS_DBG:                     /* Debug messages */
2638         return(seton(&ftp_deb));
2639 
2640       case FTS_LOG:                     /* Auto-login */
2641         return(seton(&ftp_log));
2642 
2643       case FTS_PSV:                     /* Passive mode */
2644 	return(dosetftppsv());
2645 
2646       case FTS_SPC:                     /* Send port commands */
2647         x = seton(&ftp_spc);
2648         if (x > 0) sendport = ftp_spc;
2649         return(x);
2650 
2651       case FTS_TYP:                     /* Type */
2652         if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
2653           return(x);
2654         if ((y = cmcfm()) < 0) return(y);
2655 	ftp_typ = x;
2656 	g_ftp_typ = x;
2657 	tenex = (ftp_typ == FTT_TEN);
2658         return(1);
2659 
2660       case FTS_USN:                     /* Unique server names */
2661         return(seton(&ftp_usn));
2662 
2663       case FTS_VBM:                     /* Verbose mode */
2664         if ((x = seton(&ftp_vbm)) < 0)  /* Per-command copy */
2665           return(x);
2666         ftp_vbx = ftp_vbm;              /* Global sticky copy */
2667         return(x);
2668 
2669       case FTS_TST:                     /* "if (testing)" messages */
2670         return(seton(&testing));
2671 
2672       case FTS_PRM:                     /* Send permissions */
2673         return(setonaut(&ftp_prm));
2674 
2675       case FTS_AUT:                     /* Auto-authentication */
2676         return(seton(&ftp_aut));
2677 
2678       case FTS_ERR:                     /* Error action */
2679         if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
2680           return(x);
2681         if ((y = cmcfm()) < 0)
2682           return(y);
2683         ftp_err = x;
2684         return(success = 1);
2685 
2686 #ifndef NOCSETS
2687       case FTS_XLA:                     /* Translation */
2688         return(seton(&ftp_xla));
2689 
2690       case FTS_CSR:                     /* Server charset */
2691         if ((x = cmkey(fcstab,nfilc,"character-set","utf8",xxstring)) < 0)
2692           return(x);
2693         if ((y = cmcfm()) < 0)
2694           return(y);
2695         ftp_csr = x;
2696         ftp_xla = 1;                    /* Also enable translation */
2697         return(success = 1);
2698 #endif /* NOCSETS */
2699 
2700       case FTS_GFT:
2701         return(seton(&get_auto));       /* GET-filetype-switching */
2702 
2703       case FTS_DAT:
2704         return(seton(&ftp_dates));      /* Set file dates */
2705 
2706 #ifdef FTP_TIMEOUT
2707       case FTS_TMO:			/* Timeout */
2708         if ((x = cmnum("Number of seconds","0",10,&z,xxstring)) < 0)
2709           return(x);
2710         if ((y = cmcfm()) < 0)
2711           return(y);
2712 	ftp_timeout = z;
2713 	return(success = 1);
2714 #endif	/* FTP_TIMEOUT */
2715 
2716       case FTS_STO: {			/* Server time offset */
2717 	  char * s, * p = NULL;
2718 	  long k;
2719 	  if ((x = cmfld("[+-]hh[:mm[:ss]]","+0",&s,xxstring)) < 0)
2720 	    return(x);
2721 	  if (!strcmp(s,"+0")) {
2722 	      s = NULL;
2723 	  } else if ((x = delta2sec(s,&k)) < 0) { /* Check format */
2724 	      printf("?Invalid time offset\n");
2725 	      return(-9);
2726 	  }
2727 	  makestr(&p,s);		/* Make a safe copy the string */
2728 	  if ((x = cmcfm()) < 0) {	/* Get confirmation */
2729 	      if (p)
2730 		makestr(&p,NULL);
2731 	      return(x);
2732 	  }
2733 	  fts_sto = p;			/* Confirmed - set the string. */
2734 	  return(success = 1);
2735       }
2736       case FTS_APW: {
2737 	  char * s;
2738 	  if ((x = cmtxt("Text", "", &s, xxstring)) < 0)
2739 	    return(x);
2740 	  makestr(&ftp_apw, *s ? s : NULL);
2741 	  return(success = 1);
2742       }
2743 
2744       case FTS_BUG: {
2745           if ((x = cmkey(ftpbugtab,nftpbug,"","",xxstring)) < 0)
2746 	    return(x);
2747           switch (x) {
2748 #ifdef CK_SSL
2749           case FTB_SV2:
2750 	    return seton(&ftp_bug_use_ssl_v2);
2751           case FTB_SV3:
2752             return seton(&ftp_bug_use_ssl_v3);
2753 #endif /* CK_SSL */
2754           default:
2755 	    return(-2);
2756           }
2757       }
2758 
2759 #ifdef FTP_SECURITY
2760       case FTS_CRY:                     /* Auto-encryption */
2761         return(seton(&ftp_cry));
2762 
2763       case FTS_CFW:                     /* Credential-forwarding */
2764         return(seton(&ftp_cfw));
2765 
2766       case FTS_CPL:                     /* Command protection level */
2767         if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2768         if ((y = cmcfm()) < 0) return(y);
2769         success = fts_cpl(x);
2770         return(success);
2771 
2772       case FTS_DPL:                     /* Data protection level */
2773         if ((x = cmkey(ftppro,nftppro,"","",xxstring)) < 0) return(x);
2774         if ((y = cmcfm()) < 0) return(y);
2775           success = fts_dpl(x);
2776           return(success);
2777 
2778       case FTS_ATP: {                   /* FTP Auth Type */
2779           int i, j, atypes[8];
2780 
2781           for (i = 0; i < 8; i++) {
2782               if ((y = cmkey(ftpauth,nftpauth,"",
2783                              (i == 0) ? "automatic" : "",
2784                              xxstring)) < 0) {
2785                   if (y == -3)
2786                     break;
2787                   return(y);
2788               }
2789               if (i > 0 && (y == FTA_AUTO)) {
2790                   printf("?Choice may only be used in first position.\r\n");
2791                   return(-9);
2792               }
2793               for (j = 0; j < i; j++) {
2794                   if (atypes[j] == y) {
2795                       printf("\r\n?Choice has already been used.\r\n");
2796                       return(-9);
2797                   }
2798               }
2799               atypes[i] = y;
2800               if (y == FTA_AUTO) {
2801                   i++;
2802                   break;
2803               }
2804           }
2805           if (i < 8)
2806             atypes[i] = 0;
2807           if ((z = cmcfm()) < 0)
2808             return(z);
2809           if (atypes[0] == FTA_AUTO) {
2810               i = 0;
2811 #ifdef FTP_GSSAPI
2812               ftp_auth_type[i++] = FTA_GK5;
2813 #endif /* FTP_GSSAPI */
2814 #ifdef FTP_SRP
2815               ftp_auth_type[i++] = FTA_SRP;
2816 #endif /* FTP_SRP */
2817 #ifdef FTP_KRB4
2818               ftp_auth_type[i++] = FTA_K4;
2819 #endif /* FTP_KRB4 */
2820 #ifdef CK_SSL
2821               ftp_auth_type[i++] = FTA_TLS;
2822               ftp_auth_type[i++] = FTA_SSL;
2823 #endif /* CK_SSL */
2824               ftp_auth_type[i] = 0;
2825           } else {
2826               for (i = 0; i < 8; i++)
2827                 ftp_auth_type[i] = atypes[i];
2828           }
2829           return(success = 1);
2830       }
2831 
2832       case FTS_SRP:
2833 #ifdef FTP_SRP
2834         if ((x = cmkey(ftpsrp,nftpsrp,"","",xxstring)) < 0)
2835           return(x);
2836         switch (x) {
2837           case SRP_CIPHER:
2838             if ((x = cmkey(ciphertab,nciphertab,"","",xxstring)) < 0)
2839               return(x);
2840             if ((z = cmcfm()) < 0)
2841               return(z);
2842             success = !srp_selcipher(ciphertab[x].kwd);
2843             return(success);
2844           case SRP_HASH:
2845             if ((x = cmkey(hashtab,nhashtab,"","",xxstring)) < 0)
2846               return(x);
2847             if ((z = cmcfm()) < 0)
2848               return(z);
2849             success = !srp_selhash(hashtab[x].kwd);
2850             return(success = 1);
2851           default:
2852             if ((z = cmcfm()) < 0)
2853               return(z);
2854             return(-2);
2855         }
2856 #else /* FTP_SRP */
2857         if ((z = cmcfm()) < 0)
2858           return(z);
2859         return(-2);
2860 #endif /* FTP_SRP */
2861 #endif /* FTP_SECURITY */
2862 
2863       case FTS_DIS:
2864 	doxdis(2);			/* 2 == ftp */
2865         return(success = 1);
2866 
2867       default:
2868         return(-2);
2869     }
2870 }
2871 
2872 int
ftpbye()2873 ftpbye() {
2874     int x;
2875     if (!connected)
2876       return(1);
2877     if (testing)
2878       printf(" ftp closing %s...\n",ftp_host);
2879     x = ftpclose();
2880     return((x > -1) ? 1 : 0);
2881 }
2882 
2883 /*  o p e n f t p  --  Parse FTP hostname & port and open */
2884 
2885 static int
openftp(s,opn_tls)2886 openftp(s,opn_tls) char * s; int opn_tls; {
2887     char c, * p, * hostname = NULL, *hostsave = NULL, * service = NULL;
2888     int i, n, havehost = 0, getval = 0, rc = -9, opn_psv = -1, nologin = 0;
2889     int haveuser = 0;
2890     struct FDB sw, fl, cm;
2891     extern int nnetdir;                 /* Network services directory */
2892     extern int nhcount;                 /* Lookup result */
2893     extern char *nh_p[];                /* Network directory entry pointers */
2894     extern char *nh_p2[];               /* Network directory entry nettype */
2895 
2896     if (!s) return(-2);
2897     if (!*s) return(-2);
2898 
2899     makestr(&hostname,s);
2900     hostsave = hostname;
2901     makestr(&ftp_logname,NULL);
2902     anonymous = 0;
2903     noinit = 0;
2904 
2905     debug(F110,"ftp open",hostname,0);
2906 
2907     if (sav_psv > -1) {                 /* Restore prevailing active/passive */
2908         ftp_psv = sav_psv;              /* selection in case it was */
2909         sav_psv = -1;                   /* temporarily overriden by a switch */
2910     }
2911     if (sav_log > -1) {                 /* Ditto for autologin */
2912         ftp_log = sav_log;
2913         sav_log = -1;
2914     }
2915     cmfdbi(&sw,                         /* Switches */
2916            _CMKEY,
2917            "Service name or port;\n or switch",
2918            "",                          /* default */
2919            "",                          /* addtl string data */
2920            nftpswi,                     /* addtl numeric data 1: tbl size */
2921            4,                           /* addtl numeric data 2: none */
2922            xxstring,                    /* Processing function */
2923            ftpswitab,                   /* Keyword table */
2924            &fl                          /* Pointer to next FDB */
2925            );
2926     cmfdbi(&fl,                         /* A host name or address */
2927            _CMFLD,                      /* fcode */
2928            "",                          /* help */
2929            "xYzBoo",                    /* default */
2930            "",                          /* addtl string data */
2931            0,                           /* addtl numeric data 1 */
2932            0,                           /* addtl numeric data 2 */
2933            xxstring,
2934            NULL,
2935            &cm
2936            );
2937     cmfdbi(&cm,                         /* Command confirmation */
2938            _CMCFM,
2939            "",
2940            "",
2941            "",
2942            0,
2943            0,
2944            NULL,
2945            NULL,
2946            NULL
2947            );
2948 
2949     for (n = 0;; n++) {
2950         rc = cmfdb(&sw);                /* Parse a service name or a switch */
2951         if (rc < 0)
2952           goto xopenftp;
2953 
2954         if (cmresult.fcode == _CMCFM) { /* Done? */
2955             break;
2956         } else if (cmresult.fcode == _CMFLD) {  /* Port */
2957             if (ckstrcmp("xYzBoo",cmresult.sresult,-1,1))
2958               makestr(&service,cmresult.sresult);
2959             else
2960               makestr(&service,opn_tls?"ftps":"ftp");
2961         } else if (cmresult.fcode == _CMKEY) { /* Have a switch */
2962             c = cmgbrk();               /* get break character */
2963             getval = (c == ':' || c == '=');
2964             rc = -9;
2965             if (getval && !(cmresult.kflags & CM_ARG)) {
2966                 printf("?This switch does not take arguments\n");
2967                 goto xopenftp;
2968             }
2969             if (!getval && (cmresult.kflags & CM_ARG)) {
2970                 printf("?This switch requires an argument\n");
2971                 goto xopenftp;
2972             }
2973             switch (cmresult.nresult) { /* Switch */
2974               case OPN_ANO:             /* /ANONYMOUS */
2975                 anonymous++;
2976 		nologin = 0;
2977                 break;
2978               case OPN_NIN:             /* /NOINIT */
2979                 noinit++;
2980                 break;
2981               case OPN_NOL:             /* /NOLOGIN */
2982                 nologin++;
2983 		anonymous = 0;
2984 		makestr(&ftp_logname,NULL);
2985                 break;
2986               case OPN_PSW:             /* /PASSWORD */
2987                 if (!anonymous)         /* Don't log real passwords */
2988                   debok = 0;
2989                 rc = cmfld("Password for FTP server","",&p,xxstring);
2990                 if (rc == -3) {
2991                     makestr(&ftp_tmp,NULL);
2992                 } else if (rc < 0) {
2993                     goto xopenftp;
2994                 } else {
2995                     makestr(&ftp_tmp,brstrip(p));
2996 		    nologin = 0;
2997                 }
2998                 break;
2999               case OPN_USR:             /* /USER */
3000                 rc = cmfld("Username for FTP server","",&p,xxstring);
3001                 if (rc == -3) {
3002                     makestr(&ftp_logname,NULL);
3003                 } else if (rc < 0) {
3004                     goto xopenftp;
3005                 } else {
3006 		    nologin = 0;
3007                     anonymous = 0;
3008 		    haveuser = 1;
3009                     makestr(&ftp_logname,brstrip(p));
3010                 }
3011                 break;
3012               case OPN_ACC:
3013                 rc = cmfld("Account for FTP server","",&p,xxstring);
3014                 if (rc == -3) {
3015                     makestr(&ftp_acc,NULL);
3016                 } else if (rc < 0) {
3017                     goto xopenftp;
3018                 } else {
3019                     makestr(&ftp_acc,brstrip(p));
3020                 }
3021                 break;
3022               case OPN_ACT:
3023                 opn_psv = 0;
3024                 break;
3025               case OPN_PSV:
3026                 opn_psv = 1;
3027                 break;
3028               case OPN_TLS:
3029                 opn_tls = 1;
3030                 break;
3031               default:
3032                 break;
3033             }
3034         }
3035         if (n == 0) {                   /* After first time through */
3036             cmfdbi(&sw,                 /* accept only switches */
3037                    _CMKEY,
3038                    "\nCarriage return to confirm to command, or switch",
3039                    "",
3040                    "",
3041                    nftpswi,
3042                    4,
3043                    xxstring,
3044                    ftpswitab,
3045                    &cm
3046                    );
3047         }
3048     }
3049 #ifdef COMMENT
3050     debug(F100,"ftp openftp while exit","",0);
3051     rc = cmcfm();
3052     debug(F101,"ftp openftp cmcfm rc","",rc);
3053     if (rc < 0)
3054       goto xopenftp;
3055 #endif /* COMMENT */
3056 
3057     if (opn_psv > -1) {                 /* /PASSIVE or /ACTIVE switch given */
3058         sav_psv = ftp_psv;
3059         ftp_psv = opn_psv;
3060     }
3061     if (nologin || haveuser) {		/* /NOLOGIN or /USER switch given */
3062 	sav_log = ftp_log;
3063 	ftp_log = haveuser ? 1 : 0;
3064     }
3065     if (*hostname == '=') {             /* Bypass directory lookup */
3066         hostname++;                     /* if hostname starts with '=' */
3067         havehost++;
3068     } else if (isdigit(*hostname)) {    /* or if it starts with a digit */
3069         havehost++;
3070     }
3071     if (!service)
3072       makestr(&service,opn_tls?"ftps":"ftp");
3073 
3074 #ifndef NODIAL
3075     if (!havehost && nnetdir > 0) {     /* If there is a networks directory */
3076         lunet(hostname);                /* Look up the name */
3077         debug(F111,"ftp openftp lunet",hostname,nhcount);
3078         if (nhcount == 0) {
3079             if (testing)
3080               printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3081             success = ftpopen(hostname,service,opn_tls);
3082             debug(F101,"ftp openftp A ftpopen success","",success);
3083             rc = success;
3084         } else {
3085             int found = 0;
3086             for (i = 0; i < nhcount; i++) {
3087                 if (nh_p2[i])           /* If network type specified */
3088                   if (ckstrcmp(nh_p2[i],"tcp/ip",strlen(nh_p2[i]),0))
3089                     continue;
3090                 found++;
3091                 makestr(&hostname,nh_p[i]);
3092                 debug(F111,"ftpopen lunet substitution",hostname,i);
3093                 if (testing)
3094                   printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3095                 success = ftpopen(hostname,service,opn_tls);
3096                 debug(F101,"ftp openftp B ftpopen success","",success);
3097                 rc = success;
3098                 if (success)
3099                   break;
3100             }
3101             if (!found) {               /* E.g. if no network types match */
3102                 if (testing)
3103                   printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3104                 success = ftpopen(hostname,service,opn_tls);
3105                 debug(F101,"ftp openftp C ftpopen success","",success);
3106                 rc = success;
3107             }
3108         }
3109     } else {
3110 #endif /* NODIAL */
3111         if (testing)
3112           printf(" ftp open trying \"%s %s\"...\n",hostname,service);
3113         success = ftpopen(hostname,service,opn_tls);
3114         debug(F111,"ftp openftp D ftpopen success",hostname,success);
3115         debug(F111,"ftp openftp D ftpopen connected",hostname,connected);
3116         rc = success;
3117 #ifndef NODIAL
3118     }
3119 #endif /* NODIAL */
3120 
3121   xopenftp:
3122     debug(F101,"ftp openftp xopenftp rc","",rc);
3123     if (hostsave) free(hostsave);
3124     if (service) free(service);
3125     if (rc < 0 && ftp_logname) {
3126         free(ftp_logname);
3127         ftp_logname = NULL;
3128     }
3129     if (ftp_tmp) {
3130         free(ftp_tmp);
3131         ftp_tmp = NULL;
3132     }
3133     return(rc);
3134 }
3135 
3136 VOID					/* 12 Aug 2007 */
doftpglobaltype(x)3137 doftpglobaltype(x) int x; {
3138     ftp_xfermode = XMODE_M;		/* Set manual FTP transfer mode */
3139     ftp_typ = x;			/* Used by top-level BINARY and */
3140     g_ftp_typ = x;			/* ASCII commands. */
3141     get_auto = 0;
3142     forcetype = 1;
3143 }
3144 
3145 int
doftpacct()3146 doftpacct() {
3147     int x;
3148     char * s;
3149     if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
3150       return(x);
3151     CHECKCONN();
3152     makestr(&ftp_acc,brstrip(s));
3153     if (testing)
3154       printf(" ftp account: \"%s\"\n",ftp_acc);
3155     success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
3156     return(success);
3157 }
3158 
3159 int
doftpusr()3160 doftpusr() {                            /* Log in as USER */
3161     extern char uidbuf[];
3162     extern char pwbuf[];
3163     extern int  pwflg, pwcrypt;
3164     int x;
3165     char *s, * acct = "";
3166 
3167     debok = 0;                          /* Don't log */
3168 
3169     if ((x = cmfld("Remote username or ID",uidbuf,&s,xxstring)) < 0)
3170       return(x);
3171     ckstrncpy(line,brstrip(s),LINBUFSIZ); /* brstrip: 15 Jan 2003 */
3172     if ((x = cmfld("Remote password","",&s,xxstring)) < 0) {
3173         if (x == -3) { /* no input */
3174             if ( pwbuf[0] && pwflg ) {
3175                 ckstrncpy(tmpbuf,(char *)pwbuf,TMPBUFSIZ);
3176 #ifdef OS2
3177                 if ( pwcrypt )
3178                     ck_encrypt((char *)tmpbuf);
3179 #endif /* OS2 */
3180             }
3181         } else {
3182             return(x);
3183         }
3184     } else {
3185         ckstrncpy(tmpbuf,brstrip(s),TMPBUFSIZ);
3186     }
3187     if ((x = cmtxt("Remote account\n or Enter or CR to confirm the command",
3188                    "", &s, xxstring)) < 0)
3189       return(x);
3190     CHECKCONN();
3191     if (*s) {
3192         x = strlen(tmpbuf);
3193         if (x > 0) {
3194             acct = &tmpbuf[x+2];
3195             ckstrncpy(acct,brstrip(s),TMPBUFSIZ - x - 2);
3196         }
3197     }
3198     if (testing)
3199       printf(" ftp user \"%s\" password \"%s\"...\n",line,tmpbuf);
3200     success = ftp_user(line,tmpbuf,acct);
3201 #ifdef CKLOGDIAL
3202     dologftp();
3203 #endif /* CKLOGDIAL */
3204     return(success);
3205 }
3206 
3207 /* DO (various FTP commands)... */
3208 
3209 int
doftptyp(type)3210 doftptyp(type) int type; {              /* TYPE */
3211     CHECKCONN();
3212     ftp_typ = type;
3213     changetype(ftp_typ,ftp_vbm);
3214     debug(F101,"doftptyp changed type","",type);
3215     return(1);
3216 }
3217 
3218 static int
doftpxmkd(s,vbm)3219 doftpxmkd(s,vbm) char * s; int vbm; {   /* MKDIR action */
3220     int lcs = -1, rcs = -1;
3221 #ifndef NOCSETS
3222     if (ftp_xla) {
3223         lcs = ftp_csl;
3224         if (lcs < 0) lcs = fcharset;
3225         rcs = ftp_csx;
3226         if (rcs < 0) rcs = ftp_csr;
3227     }
3228 #endif /* NOCSETS */
3229     debug(F110,"ftp doftpmkd",s,0);
3230     if (ftpcmd("MKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3231       return(success = 1);
3232     if (ftpcode == 500 || ftpcode == 502) {
3233         if (!quiet)
3234           printf("MKD command not recognized, trying XMKD\n");
3235         if (ftpcmd("XMKD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3236           return(success = 1);
3237     }
3238     return(success = 0);
3239 }
3240 
3241 static int
doftpmkd()3242 doftpmkd() {                            /* MKDIR parse */
3243     int x;
3244     char * s;
3245     if ((x = cmtxt("Remote directory name", "", &s, xxstring)) < 0)
3246       return(x);
3247     CHECKCONN();
3248     ckstrncpy(line,s,LINBUFSIZ);
3249     if (testing)
3250       printf(" ftp mkdir \"%s\"...\n",line);
3251     return(success = doftpxmkd(line,-1));
3252 }
3253 
3254 static int
doftprmd()3255 doftprmd() {                            /* RMDIR */
3256     int x, lcs = -1, rcs = -1;
3257     char * s;
3258     if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
3259       return(x);
3260     CHECKCONN();
3261     ckstrncpy(line,s,LINBUFSIZ);
3262     if (testing)
3263       printf(" ftp rmdir \"%s\"...\n",line);
3264 #ifndef NOCSETS
3265     if (ftp_xla) {
3266         lcs = ftp_csl;
3267         if (lcs < 0) lcs = fcharset;
3268         rcs = ftp_csx;
3269         if (rcs < 0) rcs = ftp_csr;
3270     }
3271 #endif /* NOCSETS */
3272     if (ftpcmd("RMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE)
3273       return(success = 1);
3274     if (ftpcode == 500 || ftpcode == 502) {
3275         if (!quiet)
3276           printf("RMD command not recognized, trying XMKD\n");
3277         success = (ftpcmd("XRMD",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
3278     } else
3279       success = 0;
3280     return(success);
3281 }
3282 
3283 static int
doftpren()3284 doftpren() {                            /* RENAME */
3285     int x;
3286     char * s;
3287     if ((x = cmfld("Remote filename","",&s,xxstring)) < 0)
3288       return(x);
3289     ckstrncpy(line,s,LINBUFSIZ);
3290     if ((x = cmfld("New name for remote file","",&s,xxstring)) < 0)
3291       return(x);
3292     ckstrncpy(tmpbuf,s,TMPBUFSIZ);
3293     if ((x = cmcfm()) < 0)
3294       return(x);
3295     CHECKCONN();
3296     if (testing)
3297       printf(" ftp rename \"%s\" (to) \"%s\"...\n",line,tmpbuf);
3298     success = ftp_rename(line,tmpbuf);
3299     return(success);
3300 }
3301 
3302 int
doftpres()3303 doftpres() {                            /* RESET (log out without close) */
3304     int x;
3305     if ((x = cmcfm()) < 0)
3306       return(x);
3307     CHECKCONN();
3308     if (testing)
3309       printf(" ftp reset...\n");
3310     return(success = ftp_reset());
3311 }
3312 
3313 static int
doftpxhlp()3314 doftpxhlp() {                           /* HELP */
3315     int x;
3316     char * s;
3317     if ((x = cmtxt("Command name", "", &s, xxstring)) < 0)
3318       return(x);
3319     CHECKCONN();
3320     ckstrncpy(line,s,LINBUFSIZ);
3321     if (testing)
3322       printf(" ftp help \"%s\"...\n",line);
3323     /* No need to translate -- all FTP commands are ASCII */
3324     return(success = (ftpcmd("HELP",line,0,0,1) == REPLY_COMPLETE));
3325 }
3326 
3327 static int
doftpdir(cx)3328 doftpdir(cx) int cx; {                  /* [V]DIRECTORY */
3329     int x, lcs = 0, rcs = 0, xlate = 0;
3330     char * p, * s, * m = "";
3331     if (cx == FTP_VDI) {
3332         switch (servertype) {
3333           case SYS_VMS:
3334           case SYS_DOS:
3335           case SYS_TOPS10:
3336           case SYS_TOPS20:
3337             m = "*.*";
3338             break;
3339           default:
3340             m = "*";
3341         }
3342     }
3343     if ((x = cmtxt("Remote filespec",m,&s,xxstring)) < 0)
3344       return(x);
3345     if ((x = remtxt(&s)) < 0)
3346       return(x);
3347 #ifdef NOCSETS
3348     xlate = 0;
3349 #else
3350     xlate = ftp_xla;
3351 #endif /* NOCSETS */
3352     line[0] = NUL;
3353     ckstrncpy(line,s,LINBUFSIZ);
3354     s = line;
3355     CHECKCONN();
3356 
3357 #ifndef NOCSETS
3358     if (xlate) {                        /* SET FTP CHARACTER-SET-TRANSLATION */
3359         lcs = ftp_csl;                  /* Local charset */
3360         if (lcs < 0) lcs = fcharset;
3361         if (lcs < 0) xlate = 0;
3362     }
3363     if (xlate) {                        /* Still ON? */
3364         rcs = ftp_csx;                  /* Remote (Server) charset */
3365         if (rcs < 0) rcs = ftp_csr;
3366         if (rcs < 0) xlate = 0;
3367     }
3368 #endif /* NOCSETS */
3369 
3370     if (testing) {
3371         p = s;
3372         if (!p) p = "";
3373         if (*p)
3374           printf("Directory of files %s at %s:\n", line, ftp_host);
3375         else
3376           printf("Directory of files at %s:\n", ftp_host);
3377     }
3378     debug(F111,"doftpdir",s,cx);
3379 
3380     if (cx == FTP_DIR) {
3381         /* Translation of line[] is done inside recvrequest() */
3382         /* when it calls ftpcmd(). */
3383         return(success =
3384           (recvrequest("LIST","-",s,"wb",0,0,NULL,xlate,lcs,rcs) == 0));
3385     }
3386     success = 1;                        /* VDIR - one file at a time... */
3387     p = (char *)remote_files(1,(CHAR *)s,NULL,0); /* Get the file list */
3388     cancelgroup = 0;
3389     if (!ftp_vbm && !quiet)
3390       printlines = 1;
3391     while (p && !cancelfile && !cancelgroup) { /* STAT one file */
3392         if (ftpcmd("STAT",p,lcs,rcs,ftp_vbm) < 0) {
3393             success = 0;
3394             break;
3395         }
3396         p = (char *)remote_files(0,NULL,NULL,0); /* Get next file */
3397         debug(F110,"ftp vdir file",s,0);
3398     }
3399     return(success);
3400 }
3401 
3402 static int
doftppwd()3403 doftppwd() {                            /* PWD */
3404     int x, lcs = -1, rcs = -1;
3405 #ifndef NOCSETS
3406     if (ftp_xla) {
3407         lcs = ftp_csl;
3408         if (lcs < 0) lcs = fcharset;
3409         rcs = ftp_csx;
3410         if (rcs < 0) rcs = ftp_csr;
3411     }
3412 #endif /* NOCSETS */
3413     if ((x = cmcfm()) < 0)
3414       return(x);
3415     CHECKCONN();
3416     if (ftpcmd("PWD",NULL,lcs,rcs,1) == REPLY_COMPLETE) {
3417         success = 1;
3418     } else if (ftpcode == 500 || ftpcode == 502) {
3419         if (ftp_deb)
3420           printf("PWD command not recognized, trying XPWD\n");
3421         success = (ftpcmd("XPWD",NULL,lcs,rcs,1) == REPLY_COMPLETE);
3422     }
3423     return(success);
3424 }
3425 
3426 static int
doftpcwd(s,vbm)3427 doftpcwd(s,vbm) char * s; int vbm; {    /* CD (CWD) */
3428     int lcs = -1, rcs = -1;
3429 #ifndef NOCSETS
3430     if (ftp_xla) {
3431         lcs = ftp_csl;
3432         if (lcs < 0) lcs = fcharset;
3433         rcs = ftp_csx;
3434         if (rcs < 0) rcs = ftp_csr;
3435     }
3436 #endif /* NOCSETS */
3437 
3438     debug(F110,"ftp doftpcwd",s,0);
3439     if (ftpcmd("CWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3440       return(success = 1);
3441     if (ftpcode == 500 || ftpcode == 502) {
3442         if (!quiet)
3443           printf("CWD command not recognized, trying XCWD\n");
3444         if (ftpcmd("XCWD",s,lcs,rcs,vbm) == REPLY_COMPLETE)
3445           return(success = 1);
3446     }
3447     return(success = 0);
3448 }
3449 
3450 static int
doftpcdup()3451 doftpcdup() {                           /* CDUP */
3452     debug(F100,"ftp doftpcdup","",0);
3453     if (ftpcmd("CDUP",NULL,0,0,1) == REPLY_COMPLETE)
3454       return(success = 1);
3455     if (ftpcode == 500 || ftpcode == 502) {
3456         if (!quiet)
3457           printf("CDUP command not recognized, trying XCUP\n");
3458         if (ftpcmd("XCUP",NULL,0,0,1) == REPLY_COMPLETE)
3459           return(success = 1);
3460     }
3461     return(success = 0);
3462 }
3463 
3464 /* s y n c d i r  --  Synchronizes client & server directories */
3465 
3466 /*
3467   Call with:
3468     local = pointer to pathname of local file to be sent.
3469     sim   = 1 for simulation, 0 for real uploading.
3470   Returns 0 on failure, 1 on success.
3471 
3472   The 'local' argument is relative to the initial directory of the MPUT,
3473   i.e. the root of the tree being uploaded.  If the directory of the
3474   argument file is different from the directory of the previous file
3475   (which is stored in global putpath[]), this routine does the appropriate
3476   CWDs, CDUPs, and/or MKDIRs to position the FTP server in the same place.
3477 */
3478 static int cdlevel = 0, cdsimlvl = 0;	/* Tree-level trackers */
3479 
3480 static int
syncdir(local,sim)3481 syncdir(local,sim) char * local; int sim; {
3482     char buf[CKMAXPATH+1];
3483     char tmp[CKMAXPATH+1];
3484     char msgbuf[CKMAXPATH+64];
3485     char c, * p = local, * s = buf, * q = buf, * psep, * ssep;
3486     int i, k = 0, done = 0, itsadir = 0, saveq;
3487 
3488     debug(F110,"ftp syncdir local (new)",local,0);
3489     debug(F110,"ftp syncdir putpath (old)",putpath,0);
3490 
3491     itsadir = isdir(local);		/* Is the local file a directory? */
3492     saveq = quiet;
3493 
3494     while ((*s = *p)) {                 /* Copy the argument filename */
3495         if (++k == CKMAXPATH)           /* so we can poke it. */
3496           return(-1);
3497         if (*s == '/')                  /* Pointer to rightmost dirsep */
3498           q = s;
3499         s++;
3500         p++;
3501     }
3502     if (!itsadir)			/* If it's a regular file */
3503       *q = NUL;                         /* keep just the path part */
3504 
3505     debug(F110,"ftp syncdir buf",buf,0);
3506     if (!strcmp(buf,putpath)) {         /* Same path as previous file? */
3507         if (itsadir) {                  /* This file is a directory? */
3508             if (doftpcwd(local,0)) {    /* Try to CD to it */
3509                 doftpcdup();            /* Worked - CD back up */
3510             } else if (sim) {           /* Simulating... */
3511                 if (fdispla == XYFD_B) {
3512                     printf("WOULD CREATE DIRECTORY %s\n",local);
3513                 } else if (fdispla) {
3514                     ckmakmsg(msgbuf,CKMAXPATH,
3515                              "WOULD CREATE DIRECTORY",local,NULL,NULL);
3516                     ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3517                 }
3518                 /* See note above */
3519                 return(0);
3520             } else if (!doftpxmkd(local,0)) { /* Can't CD - try to create */
3521                 return(0);
3522             } else {			/* Remote directory created OK */
3523                 if (fdispla == XYFD_B) {
3524                     printf("CREATED DIRECTORY %s\n",local);
3525                 } else if (fdispla) {
3526                     ckmakmsg(msgbuf,CKMAXPATH+64,
3527                              "CREATED DIRECTORY ",local,NULL,NULL);
3528                     ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3529                 }
3530             }
3531         }
3532         debug(F110,"ftp syncdir no change",buf,0);
3533         return(1);                      /* Yes, done. */
3534     }
3535     ckstrncpy(tmp,buf,CKMAXPATH+1);     /* Make a safe (pre-poked) copy */
3536     debug(F110,"ftp syncdir new path",buf,0); /* for later (see end) */
3537 
3538     p = buf;                            /* New */
3539     s = putpath;                        /* Old */
3540 
3541     debug(F110,"ftp syncdir A (old) s",s,0); /* Previous */
3542     debug(F110,"ftp syncdir A (new) p",p,0); /* New */
3543 
3544     psep = buf;
3545     ssep = putpath;
3546     while (*p != NUL && *s != NUL && *p == *s) {
3547 	if (*p == '/') { psep = p+1; ssep = s+1; }
3548 	p++,s++;
3549     }
3550     /*
3551       psep and ssep point to the first path segment that differs.
3552       We have to do as many CDUPs as there are path segments in ssep.
3553       then we have to do as many MKDs and CWDs as there are segments in psep.
3554     */
3555     s = ssep;
3556     p = psep;
3557 
3558     debug(F110,"ftp syncdir B (old) s",s,0); /* Previous */
3559     debug(F110,"ftp syncdir B (new) p",p,0); /* New */
3560 
3561     /* p and s now point to the leftmost spot where the paths differ */
3562 
3563     if (*s) {                           /* We have to back up */
3564         k = 1;                          /* How many levels counting this one */
3565         while ((c = *s++)) {            /* Count dirseps remaining in prev */
3566             if (c == '/' && *s)
3567               k++;
3568         }
3569 	debug(F101,"ftp syncdir levels up","",k);
3570 
3571         for (i = 1; i <= k; i++) {       /* Do that many CDUPs */
3572             debug(F111,"ftp syncdir CDUP A",p,i);
3573 	    if (fdispla == XYFD_B)
3574 	      printf(" CDUP\n");
3575             if (sim && cdsimlvl) {
3576                 cdsimlvl--;
3577             } else {
3578                 if (!doftpcdup()) {
3579                     quiet = saveq;
3580                     return(0);
3581                 }
3582             }
3583             cdlevel--;
3584         }
3585         if (!*p)                        /* If we don't have to go down */
3586           goto xcwd;                    /* we're done. */
3587     }
3588 #ifdef COMMENT
3589     while (p > buf && *p && *p != '/')  /* If in middle of segment */
3590       p--;                              /* back up to beginning */
3591     if (*p == '/')                      /* and terminate there */
3592       p++;
3593 #endif	/* COMMENT */
3594 
3595     debug(F110,"ftp syncdir NEW PATH",p,0);
3596 
3597     s = p;                              /* Point to start of new down path. */
3598     while (1) {                         /* Loop through characters. */
3599         if (*s == '/' || !*s) {         /* Have a segment. */
3600             if (!*s)                    /* If end of string, */
3601               done++;                   /* after this segment we're done. */
3602             else
3603               *s = NUL;                 /* NUL out the separator. */
3604             if (*p) {                   /* If segment is not empty */
3605                 debug(F110,"ftp syncdir down segment",p,0);
3606                 if (!doftpcwd(p,0)) {   /* Try to CD to it */
3607                     if (sim) {
3608                         if (fdispla == XYFD_B) {
3609                             printf(" WOULD CREATE DIRECTORY %s\n",local);
3610                         } else if (fdispla) {
3611                             ckmakmsg(msgbuf,CKMAXPATH,
3612 				     "WOULD CREATE DIRECTORY",
3613                                      local,NULL,NULL);
3614                             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3615                         }
3616                         cdsimlvl++;
3617                     } else {
3618                         if (!doftpxmkd(p,0)) { /* Can't CD - try to create */
3619 			    debug(F110,"ftp syncdir mkdir failed",p,0);
3620 /*
3621   Suppose we are executing SEND /RECURSIVE.  Locally we have a directory
3622   FOO but the remote has a regular file with the same name.  We can't CD
3623   to it, can't MKDIR it either.  There's no way out but to fail and let
3624   the user handle the problem.
3625 */
3626                             quiet = saveq;
3627                             return(0);
3628                         }
3629 			debug(F110,"ftp syncdir mkdir OK",p,0);
3630                         if (fdispla == XYFD_B) {
3631                             printf(" CREATED DIRECTORY %s\n",p);
3632                         } else if (fdispla) {
3633                             ckmakmsg(msgbuf,CKMAXPATH,
3634                                      "CREATED DIRECTORY ",p,NULL,NULL);
3635                             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,msgbuf);
3636                         }
3637                         if (!doftpcwd(p,0)) { /* Try again to CD */
3638 			    debug(F110,"ftp syncdir CD failed",p,0);
3639                             quiet = saveq;
3640                             return(0);
3641                         }
3642                         if (fdispla == XYFD_B) printf(" CWD %s\n",p);
3643 			debug(F110,"ftp syncdir CD OK",p,0);
3644                     }
3645                 }
3646                 cdlevel++;
3647             }
3648             if (done)                   /* Quit if no next segment */
3649               break;
3650             p = s+1;                    /* Point to next segment */
3651         }
3652         s++;                            /* Point to next source char */
3653     }
3654 
3655   xcwd:
3656     ckstrncpy(putpath,tmp,CKMAXPATH+1); /* All OK - make this the new path */
3657     quiet = saveq;
3658     return(1);
3659 }
3660 
3661 #ifdef DOUPDATE
3662 #ifdef DEBUG
3663 static VOID
dbtime(s,xx)3664 dbtime(s,xx) char * s; struct tm * xx; { /* Write struct tm to debug log */
3665     if (deblog) {
3666         debug(F111,"ftp year ",s,xx->tm_year);
3667         debug(F111,"ftp month",s,xx->tm_mon);
3668         debug(F111,"ftp day  ",s,xx->tm_mday);
3669         debug(F111,"ftp hour ",s,xx->tm_hour);
3670         debug(F111,"ftp min  ",s,xx->tm_min);
3671         debug(F111,"ftp sec  ",s,xx->tm_sec);
3672     }
3673 }
3674 #endif /* DEBUG */
3675 
3676 /*  t m c o m p a r e  --  Compare two struct tm's */
3677 
3678 /*  Like strcmp() but for struct tm's  */
3679 /*  Returns -1 if xx < yy, 0 if they are equal, 1 if xx > yy */
3680 
3681 static int
tmcompare(xx,yy)3682 tmcompare(xx,yy) struct tm * xx, * yy; {
3683 
3684     if (xx->tm_year < yy->tm_year)      /* First year less than second */
3685       return(-1);
3686     if (xx->tm_year > yy->tm_year)      /* First year greater than second */
3687       return(1);
3688 
3689     /* Years are equal so compare months */
3690 
3691     if (xx->tm_mon  < yy->tm_mon)       /* And so on... */
3692       return(-1);
3693     if (xx->tm_mon  > yy->tm_mon)
3694       return(1);
3695 
3696     if (xx->tm_mday < yy->tm_mday)
3697       return(-1);
3698     if (xx->tm_mday > yy->tm_mday)
3699       return(1);
3700 
3701     if (xx->tm_hour < yy->tm_hour)
3702       return(-1);
3703     if (xx->tm_hour > yy->tm_hour)
3704       return(1);
3705 
3706     if (xx->tm_min  < yy->tm_min)
3707       return(-1);
3708     if (xx->tm_min  > yy->tm_min)
3709       return(1);
3710 
3711     if (xx->tm_sec  < yy->tm_sec)
3712       return(-1);
3713     if (xx->tm_sec  > yy->tm_sec)
3714       return(1);
3715 
3716     return(0);
3717 }
3718 #endif /* DOUPDATE */
3719 
3720 #ifndef HAVE_TIMEGM             /* For platforms that do not have timegm() */
3721 static CONST int MONTHDAYS[] = { /* Number of days in each month. */
3722     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3723 };
3724 
3725 /* Macro for whether a given year is a leap year. */
3726 #define ISLEAP(year) \
3727 (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
3728 #endif /* HAVE_TIMEGM */
3729 
3730 /*  m k u t i m e  --  Like mktime() but argument is already UTC */
3731 
3732 static time_t
3733 #ifdef CK_ANSIC
mkutime(struct tm * tm)3734 mkutime(struct tm * tm)
3735 #else
3736 mkutime(tm) struct tm * tm;
3737 #endif /* CK_ANSIC */
3738 /* mkutime */ {
3739 #ifdef HAVE_TIMEGM
3740     return(timegm(tm));                 /* Have system service, use it. */
3741 #else
3742 /*
3743   Contributed by Russ Allbery (rra@stanford.edu), used by permission.
3744   Given a struct tm representing a calendar time in UTC, convert it to
3745   seconds since epoch.  Returns (time_t) -1 if the time is not
3746   convertable.  Note that this function does not canonicalize the provided
3747   struct tm, nor does it allow out-of-range values or years before 1970.
3748   Result should be identical with timegm().
3749 */
3750     time_t result = 0;
3751     int i;
3752     /*
3753       We do allow some ill-formed dates, but we don't do anything special
3754       with them and our callers really shouldn't pass them to us.  Do
3755       explicitly disallow the ones that would cause invalid array accesses
3756       or other algorithm problems.
3757     */
3758 #ifdef DEBUG
3759     if (deblog) {
3760         debug(F101,"mkutime tm_mon","",tm->tm_mon);
3761         debug(F101,"mkutime tm_year","",tm->tm_year);
3762     }
3763 #endif /* DEBUG */
3764     if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
3765       return((time_t) -1);
3766 
3767     /* Convert to time_t. */
3768     for (i = 1970; i < tm->tm_year + 1900; i++)
3769       result += 365 + ISLEAP(i);
3770     for (i = 0; i < tm->tm_mon; i++)
3771       result += MONTHDAYS[i];
3772     if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
3773       result++;
3774     result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
3775     result = 60 * result + tm->tm_min;
3776     result = 60 * result + tm->tm_sec;
3777     debug(F101,"mkutime result","",result);
3778     return(result);
3779 #endif /* HAVE_TIMEGM */
3780 }
3781 
3782 
3783 /*
3784   s e t m o d t i m e  --  Set file modification time.
3785 
3786   f = char * filename;
3787   t = time_t date/time to set (Secs since 19700101 0:00:00 UTC, NOT local)
3788 
3789   UNIX-specific; isolates mainline code from hideous #ifdefs.
3790   Returns:
3791     0 on success,
3792    -1 on error.
3793 
3794 */
3795 static int
3796 #ifdef CK_ANSIC
setmodtime(char * f,time_t t)3797 setmodtime(char * f, time_t t)
3798 #else
3799 setmodtime(f,t) char * f; time_t t;
3800 #endif /* CK_ANSIC */
3801 /* setmodtime */ {
3802 #ifdef NT
3803     struct _stat sb;
3804 #else /* NT */
3805     struct stat sb;
3806 #endif /* NT */
3807     int x, rc = 0;
3808 #ifdef BSD44
3809     struct timeval tp[2];
3810 #else  /* def BSD44 */
3811 #ifdef V7
3812     struct utimbuf {
3813         time_t timep[2];
3814     } tp;
3815 #else  /* def V7 */
3816 #ifdef SYSUTIMEH
3817 #ifdef NT
3818     struct _utimbuf tp;
3819 #else /* NT */
3820     struct utimbuf tp;
3821 #endif /* NT */
3822 #else /* def SYSUTIMEH */
3823 #ifdef VMS
3824     struct utimbuf tp;
3825 #define SYSUTIMEH               /* Our utimbuf matches this one. */
3826 #else /* def VMS */
3827     struct utimbuf {
3828         time_t atime;
3829         time_t mtime;
3830     } tp;
3831 #endif /* def VMS [else] */
3832 #endif /* def SYSUTIMEH [else] */
3833 #endif /* def V7 [else] */
3834 #endif /* def BSD44 [else] */
3835 
3836     if (stat(f,&sb) < 0) {
3837         debug(F111,"setmodtime stat failure",f,errno);
3838         return(-1);
3839     }
3840 #ifdef BSD44
3841     tp[0].tv_sec = sb.st_atime;         /* Access time first */
3842     tp[1].tv_sec = t;                   /* Update time second */
3843     debug(F111,"setmodtime BSD44",f,t);
3844 #else
3845 #ifdef V7
3846     tp.timep[0] = t;                    /* Set modif. time to creation date */
3847     tp.timep[1] = sb.st_atime;          /* Don't change the access time */
3848     debug(F111,"setmodtime V7",f,t);
3849 #else
3850 #ifdef SYSUTIMEH
3851     tp.modtime = t;                     /* Set modif. time to creation date */
3852     tp.actime = sb.st_atime;            /* Don't change the access time */
3853     debug(F111,"setmodtime SYSUTIMEH",f,t);
3854 #else
3855     tp.mtime = t;                       /* Set modif. time to creation date */
3856     tp.atime = sb.st_atime;             /* Don't change the access time */
3857     debug(F111,"setmodtime (other)",f,t);
3858 #endif /* SYSUTIMEH */
3859 #endif /* V7 */
3860 #endif /* BSD44 */
3861 
3862     /* Try to set the file date */
3863 
3864 #ifdef BSD44
3865     x = utimes(f,tp);
3866     debug(F111,"setmodtime utimes()","BSD44",x);
3867 #else
3868 #ifdef IRIX65
3869     {
3870       /*
3871         The following produces the nonsensical warning:
3872         Argument  of type "const struct utimbuf *" is incompatible with
3873         parameter of type "const struct utimbuf *".  If you can make it
3874         go away, be my guest.
3875       */
3876         const struct utimbuf * t2 = &tp;
3877         x = utime(f,t2);
3878     }
3879 #else
3880     x = utime(f,&tp);
3881     debug(F111,"setmodtime utime()","other",x);
3882 #endif /* IRIX65 */
3883 #endif /* BSD44 */
3884     if (x)
3885       rc = -1;
3886 
3887     debug(F101,"setmodtime result","",rc);
3888     return(rc);
3889 }
3890 
3891 
3892 /*
3893   c h k m o d t i m e  --  Check/Set file modification time.
3894 
3895   fc = function code:
3896     0 = Check; returns:
3897       -1 on error,
3898        0 if local older than remote,
3899        1 if modtimes are equal,
3900        2 if local newer than remote.
3901     1 = Set (local file's modtime from remote's); returns:
3902       -1 on error,
3903        0 on success.
3904 */
3905 static int
chkmodtime(local,remote,fc)3906 chkmodtime(local,remote,fc) char * local, * remote; int fc; {
3907 #ifdef NT
3908     struct _stat statbuf;
3909 #else /* NT */
3910     struct stat statbuf;
3911 #endif /* NT */
3912     struct tm * tmlocal = NULL;
3913     struct tm tmremote;
3914     int rc = 0, havedate = 0, lcs = -1, rcs = -1, flag = 0;
3915     char * s, timebuf[64];
3916 
3917     debug(F111,"chkmodtime",local,mdtmok);
3918     if (!mdtmok)			/* Server supports MDTM? */
3919       return(-1);			/* No don't bother. */
3920 
3921 #ifndef NOCSETS
3922     if (ftp_xla) {
3923         lcs = ftp_csl;
3924         if (lcs < 0) lcs = fcharset;
3925         rcs = ftp_csx;
3926         if (rcs < 0) rcs = ftp_csr;
3927     }
3928 #endif /* NOCSETS */
3929 
3930     if (fc == 0) {
3931         rc = stat(local,&statbuf);
3932         if (rc == 0) {                  /* Get local file's mod time */
3933 	    /* Convert to struct tm */
3934             tmlocal = gmtime((time_t *)&statbuf.st_mtime);
3935 #ifdef DEBUG
3936             if (tmlocal) {
3937                 dbtime(local,tmlocal);
3938             }
3939 #endif /* DEBUG */
3940         }
3941     }
3942     /* Get remote file's mod time as yyyymmddhhmmss */
3943 
3944     if (havemdtm) {			/* Already got it from MLSD? */
3945 	s = havemdtm;
3946 	flag++;
3947     } else if (ftpcmd("MDTM",remote,lcs,rcs,0) == REPLY_COMPLETE) {
3948         char c;
3949         bzero((char *)&tmremote, sizeof(struct tm));
3950         s = ftp_reply_str;
3951         while ((c = *s++)) {            /* Skip past response code */
3952             if (c == SP) {
3953                 flag++;
3954                 break;
3955             }
3956         }
3957     }
3958     if (flag) {
3959 	debug(F111,"ftp chkmodtime string",s,flag);
3960 	if (fts_sto) {			/* User gave server time offset? */
3961 	    char * p;
3962 	    debug(F110,"ftp chkmodtime offset",fts_sto,0);
3963 	    ckmakmsg(timebuf,64,s," ",fts_sto,NULL); /* Build delta time */
3964 	    if ((p = cmcvtdate(timebuf,1))) { /* Apply delta time */
3965 		ckstrncpy(timebuf,p,64);      /* Convert to MDTM format */
3966 		timebuf[8]  = timebuf[9];  /* h */
3967 		timebuf[9]  = timebuf[10]; /* h */
3968 		timebuf[10] = timebuf[12]; /* m */
3969 		timebuf[11] = timebuf[13]; /* m */
3970 		timebuf[12] = timebuf[12]; /* s */
3971 		timebuf[13] = timebuf[13]; /* s */
3972 		timebuf[14] = NUL;
3973 		s = timebuf;
3974 		debug(F110,"ftp chkmodtime adjust",s,0);
3975 	    }
3976 	}
3977         if (flag) {                     /* Convert to struct tm */
3978             char * pat;
3979             int y2kbug = 0;             /* Seen in Kerberos 4 FTP servers */
3980             if (!ckstrcmp(s,"191",3,0)) {
3981                 pat = "%05d%02d%02d%02d%02d%02d";
3982                 y2kbug++;
3983                 debug(F110,"ftp chkmodtime Y2K BUG detected",s,0);
3984             } else {
3985                 pat = "%04d%02d%02d%02d%02d%02d";
3986             }
3987             if (sscanf(s,               /* Parse into struct tm */
3988                        pat,
3989                        &(tmremote.tm_year),
3990                        &(tmremote.tm_mon),
3991                        &(tmremote.tm_mday),
3992                        &(tmremote.tm_hour),
3993                        &(tmremote.tm_min),
3994                        &(tmremote.tm_sec)
3995                        ) == 6) {
3996                 tmremote.tm_year -= (y2kbug ? 19000 : 1900);
3997                 debug(F101,"ftp chkmodtime year","",tmremote.tm_year);
3998                 tmremote.tm_mon--;
3999 
4000 #ifdef DEBUG
4001 		debug(F100,"SERVER TIME FOLLOWS:","",0);
4002                 dbtime(remote,&tmremote);
4003 #endif /* DEBUG */
4004 
4005                 if (havedate > -1)
4006 		  havedate = 1;
4007             }
4008         }
4009     } else {				/* Failed */
4010 	debug(F101,"ftp chkmodtime ftpcode","",ftpcode);
4011 	if (ftpcode == 500 ||		/* Command unrecognized */
4012 	    ftpcode == 502 ||		/* Command not implemented */
4013 	    ftpcode == 202)		/* Command superfluous */
4014 	  mdtmok = 0;			/* Don't ask this server again */
4015 	return(-1);
4016     }
4017     if (fc == 0) {                      /* Compare */
4018         if (havedate == 1) {		/* Only if we have both file dates */
4019             /*
4020               Compare with local file's time.  We don't use
4021               clock time (time_t) here in case of signed/unsigned
4022               confusion, etc.
4023             */
4024 	    int xx;
4025 #ifdef COMMENT
4026 #ifdef DEBUG
4027 	    if (deblog) {
4028 		dbtime("LOCAL",tmlocal);
4029 		dbtime("REMOT",&tmremote);
4030 	    }
4031 #endif /* DEBUG */
4032 #endif /* COMMENT */
4033 	    xx = tmcompare(tmlocal,&tmremote);
4034 	    debug(F101,"chkmodtime tmcompare","",xx);
4035             return(xx + 1);
4036         }
4037     } else if (ftp_dates) {             /* Set */
4038         /*
4039           Here we must convert struct tm to time_t
4040           without applying timezone conversion, for which
4041           there is no portable API.  The method is hidden
4042           in mkutime(), defined above.
4043         */
4044         time_t utc;
4045         utc = mkutime(&tmremote);
4046         debug(F111,"ftp chkmodtime mkutime",remote,utc);
4047         if (utc != (time_t)-1)
4048           return(setmodtime(local,utc));
4049     }
4050     return(-1);
4051 }
4052 
4053 /* getfile() returns: -1 on error, 0 if file received, 1 if file skipped */
4054 
4055 static int
getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)4056 getfile(remote,local,recover,append,pipename,xlate,fcs,rcs)
4057     char * local, * remote, * pipename; int recover, append, xlate, fcs, rcs;
4058 /* getfile */ {
4059     int rc = -1;
4060     ULONG t0, t1;
4061 
4062 #ifdef GFTIMER
4063     CKFLOAT sec;
4064 #else
4065     int sec = 0;
4066 #endif /* GFTIMER */
4067     char fullname[CKMAXPATH+1];
4068 
4069     debug(F110,"ftp getfile remote A",remote,0);
4070     debug(F110,"ftp getfile local A",local,0);
4071     debug(F110,"ftp getfile pipename",pipename,0);
4072     if (!remote) remote = "";
4073 
4074 #ifdef PATTERNS
4075     /* Automatic type switching? */
4076     if (ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype) {
4077         int x;
4078         x = matchname(remote,0,servertype);
4079         debug(F111,"ftp getfile matchname",remote,x);
4080         switch (x) {
4081           case 0: ftp_typ = FTT_ASC; break;
4082           case 1: ftp_typ = tenex ? FTT_TEN : FTT_BIN; break;
4083           default: if (g_ftp_typ > -1) ftp_typ = g_ftp_typ;
4084         }
4085         changetype(ftp_typ,ftp_vbm);
4086         binary = ftp_typ;               /* For file-transfer display */
4087     }
4088 #endif /* PATTERNS */
4089 
4090 #ifndef NOCSETS
4091     ftp_csx = -1;                       /* For file-transfer display */
4092     ftp_csl = -1;                       /* ... */
4093 
4094     if (rcs > -1)                       /* -1 means no translation */
4095       if (ftp_typ == FTT_ASC)           /* File type is "ascii"? */
4096         if (fcs < 0)                    /* File charset not forced? */
4097           fcs = fcharset;               /* use prevailing FILE CHARACTER-SET */
4098     if (fcs > -1 && rcs > -1) {         /* Set up translation functions */
4099         debug(F110,"ftp getfile","initxlate",0);
4100         initxlate(rcs,fcs);             /* NB: opposite order of PUT */
4101         ftp_csx = rcs;
4102         ftp_csl = fcs;
4103     } else
4104       xlate = 0;
4105 #endif /* NOCSETS */
4106 
4107     if (!local) local = "";
4108     if (!pipename && !*local)
4109       local = remote;
4110 
4111     out2screen = !strcmp(local,"-");
4112 
4113     fullname[0] = NUL;
4114     if (pipename) {
4115         ckstrncpy(fullname,pipename,CKMAXPATH+1);
4116     } else {
4117         zfnqfp(local,CKMAXPATH,fullname);
4118         if (!fullname[0])
4119           ckstrncpy(fullname,local,CKMAXPATH+1);
4120     }
4121     if (!out2screen && displa && fdispla) { /* Screen */
4122         ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,remote);
4123         ftscreen(SCR_AN,0,(CK_OFF_T)0,fullname);
4124         ftscreen(SCR_FS,0,fsize,"");
4125     }
4126     tlog(F110,ftp_typ ? "ftp get BINARY:" : "ftp get TEXT:", remote, 0);
4127     tlog(F110," as",fullname,0);
4128     debug(F111,"ftp getfile size",remote,fsize);
4129     debug(F111,"ftp getfile local",local,out2screen);
4130 
4131     ckstrncpy(filnam, pipename ? remote : local, CKMAXPATH);
4132 
4133     t0 = gmstimer();                    /* Start time */
4134     debug(F111,"ftp getfile t0",remote,t0); /* ^^^ */
4135     rc = recvrequest("RETR",
4136                      local,
4137                      remote,
4138                      append ? "ab" : "wb",
4139                      0,
4140                      recover,
4141                      pipename,
4142                      xlate,
4143                      fcs,
4144                      rcs
4145                      );
4146     t1 = gmstimer();                    /* End time */
4147     debug(F111,"ftp getfile t1",remote,t1);
4148     debug(F111,"ftp getfile sec",remote,(t1-t0)/1000);
4149 #ifdef GFTIMER
4150     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4151     fpxfsecs = sec;                     /* (for doxlog()) */
4152 #else
4153     sec = (t1 - t0) / 1000;
4154     xfsecs = (int)sec;
4155 #endif /* GFTIMER */
4156 
4157 #ifdef FTP_TIMEOUT
4158     if (ftp_timed_out)
4159       rc = -4;
4160 #endif	/* FTP_TIMEOUT */
4161 
4162     debug(F111,"ftp recvrequest rc",remote,rc);
4163     if (cancelfile || cancelgroup) {
4164         debug(F111,"ftp get canceled",ckitoa(cancelfile),cancelgroup);
4165         ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4166     } else if (rc > 0) {
4167         debug(F111,"ftp get skipped",ckitoa(cancelfile),cancelgroup);
4168         ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,cmarg);
4169     } else if (rc < 0) {
4170         switch (ftpcode) {
4171           case -4:                      /* Network error */
4172           case -2:                      /* File error */
4173             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,ck_errstr());
4174             break;
4175           case -3:
4176             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,
4177 		     "Failure to make data connection");
4178             break;
4179           case -1:			/* (should be covered above) */
4180             ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4181             break;
4182           default:
4183             ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4184         }
4185     } else {                            /* Tudo bem */
4186         ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4187         if (rc == 0) {
4188             ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,""); /* For screen */
4189             makestr(&rrfspec,remote);     /* For WHERE command */
4190             makestr(&rfspec,fullname);
4191         }
4192     }
4193     if (rc > -1) {
4194 	if (ftp_dates)			/* If FTP DATES ON... */
4195 	  if (!pipename && !out2screen)	/* and it's a real file */
4196 	    if (rc < 1 && rc != -3)	/* and it wasn't skipped */
4197 	      if (connected)		/* and we still have a connection */
4198 		if (zchki(local) > -1) { /* and the file wasn't discarded */
4199 		    chkmodtime(local,remote,1); /* set local file date */
4200 		    debug(F110,"ftp get set date",local,0);
4201 		}
4202 	filcnt++;			/* Used by \v(filenum) */
4203     }
4204 #ifdef TLOG
4205     if (tralog) {
4206         if (rc > 0) {
4207             tlog(F100," recovery skipped","",0);
4208         } else if (rc == 0) {
4209             tlog(F101," complete, size", "", fsize);
4210         } else if (cancelfile) {
4211             tlog(F100," canceled by user","",0);
4212 #ifdef FTP_TIMEOUT
4213         } else if (ftp_timed_out) {
4214             tlog(F100," timed out","",0);
4215 #endif	/* FTP_TIMEOUT */
4216         } else {
4217             tlog(F110," failed:",ftp_reply_str,0);
4218         }
4219         if (!tlogfmt)
4220           doxlog(what,local,fsize,ftp_typ,rc,"");
4221     }
4222 #endif /* TLOG */
4223     return(rc);
4224 }
4225 
4226 /* putfile() returns: -1 on error, >0 if file not selected, 0 on success. */
4227 /* Positive return value is Skip Reason, SKP_xxx, from ckcker.h. */
4228 
4229 static int
putfile(cx,local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)4230 putfile(cx,
4231     local,remote,force,moving,mvto,rnto,srvrn,x_cnv,x_usn,xft,prm,fcs,rcs,flg)
4232     char * local, * remote, * mvto, *rnto, *srvrn;
4233     int cx, force, moving, x_cnv, x_usn, xft, fcs, rcs, flg, prm;
4234 
4235 /* putfile */ {
4236 
4237     char asname[CKMAXPATH+1];
4238     char fullname[CKMAXPATH+1];
4239     int k = -1, x = 0, y = 0, o = -1, rc = 0, nc = 0;
4240     int xlate = 0, restart = 0, mt = -1;
4241     char * s = NULL, * cmd = NULL;
4242     ULONG t0 = 0, t1 = 0;		/* Times for stats */
4243     int ofcs = 0, orcs = 0;
4244 
4245 #ifdef GFTIMER
4246     CKFLOAT sec = 0.0;
4247 #else
4248     int sec = 0;
4249 #endif /* GFTIMER */
4250     debug(F111,"ftp putfile flg",local,flg);
4251     debug(F110,"ftp putfile srv_renam",srvrn,0);
4252     debug(F101,"ftp putfile fcs","",fcs);
4253     debug(F101,"ftp putfile rcs","",rcs);
4254 
4255     ofcs = fcs;                         /* Save charset args */
4256     orcs = rcs;
4257 
4258     sendstart = (CK_OFF_T)0;
4259     restart = flg & PUT_RES;
4260     if (!remote)
4261       remote = "";
4262 
4263     /* FTP protocol command to send to server */
4264     cmd = (cx == FTP_APP) ? "APPE" : (x_usn ? "STOU" : "STOR");
4265 
4266     if (x_cnv == SET_AUTO) {            /* Name conversion is auto */
4267         if (alike) {                    /* If server & client are alike */
4268             nc = 0;                     /* no conversion */
4269         } else {                        /* If they are different */
4270             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
4271               nc = -1;                  /* only minimal conversions needed */
4272             else                        /* otherwise */
4273               nc = 1;                   /* full conversion */
4274         }
4275     } else                              /* Not auto - do what user said */
4276       nc = x_cnv;
4277 
4278     /* If Transfer Mode is Automatic, determine file type */
4279     if (ftp_xfermode == XMODE_A && filepeek && !pipesend) {
4280         if (isdir(local)) {             /* If it's a directory */
4281             k = FT_BIN;                 /* skip the file scan */
4282         } else {
4283             debug(F110,"FTP PUT calling scanfile",local,0);
4284             k = scanfile(local,&o,nscanfile); /* Scan the file */
4285         }
4286         debug(F111,"FTP PUT scanfile",local,k);
4287         if (k > -1 && !forcetype) {
4288             ftp_typ = (k == FT_BIN) ? 1 : 0;
4289             if (xft > -1 && ftp_typ != xft) {
4290                 if (flg & PUT_SIM)
4291                   tlog(F110,"ftp put SKIP (Type):", local, 0);
4292                 return(SKP_TYP);
4293             }
4294             if (ftp_typ == 1 && tenex)  /* User said TENEX? */
4295               ftp_typ = FTT_TEN;
4296         }
4297     }
4298 #ifndef NOCSETS
4299     ftp_csx = -1;                       /* For file-transfer display */
4300     ftp_csl = -1;                       /* ... */
4301 
4302     if (rcs > -1) {                     /* -1 means no translation */
4303         if (ftp_typ == 0) {             /* File type is "ascii"? */
4304             if (fcs < 0) {              /* File charset not forced? */
4305                 if (k < 0) {            /* If we didn't scan */
4306                     fcs = fcharset;     /* use prevailing FILE CHARACTER-SET */
4307                 } else {                /* If we did scan, use scan result */
4308                     switch (k) {
4309                       case FT_TEXT:     /* Unknown text */
4310                         fcs = fcharset;
4311                         break;
4312                       case FT_7BIT:     /* 7-bit text */
4313                         fcs = dcset7;
4314                         break;
4315                       case FT_8BIT:     /* 8-bit text */
4316                         fcs = dcset8;
4317                         break;
4318                       case FT_UTF8:     /* UTF-8 */
4319                         fcs = FC_UTF8;
4320                         break;
4321                       case FT_UCS2:     /* UCS-2 */
4322                         fcs = FC_UCS2;
4323                         if (o > -1)     /* Input file byte order */
4324                           fileorder = o;
4325                         break;
4326                       default:
4327                         rcs = -1;
4328                     }
4329                 }
4330             }
4331         }
4332     }
4333     if (fcs > -1 && rcs > -1) {         /* Set up translation functions */
4334         debug(F110,"ftp putfile","initxlate",0);
4335         initxlate(fcs,rcs);
4336         debug(F111,"ftp putfile rcs",fcsinfo[rcs].keyword,rcs);
4337         xlate = 1;
4338         ftp_csx = rcs;
4339         ftp_csl = fcs;
4340     }
4341 #endif /* NOCSETS */
4342 
4343     binary = ftp_typ;                   /* For file-transfer display */
4344     asname[0] = NUL;
4345 
4346     if (recursive) {                    /* If sending recursively, */
4347         if (!syncdir(local,flg & PUT_SIM)) /* synchronize directories. */
4348           return(-1);                   /* Don't PUT if it fails. */
4349         else if (isdir(local))          /* It's a directory */
4350           return(0);                    /* Don't send it! */
4351     }
4352     if (*remote) {                      /* If an as-name template was given */
4353 #ifndef NOSPL
4354         if (cmd_quoting) {              /* and COMMAND QUOTING is ON */
4355             y = CKMAXPATH;              /* evaluate it for this file */
4356             s = asname;
4357             zzstring(remote,&s,&y);
4358         } else
4359 #endif /* NOSPL */
4360           ckstrncpy(asname,remote,CKMAXPATH);   /* (or take it literally) */
4361     } else {                                    /* No as-name */
4362         nzltor(local,asname,nc,0,CKMAXPATH);    /* use local name strip path */
4363         debug(F110,"FTP PUT nzltor",asname,0);
4364     }
4365     /* Preliminary messages and log entries */
4366 
4367     fullname[0] = NUL;
4368     zfnqfp(local,CKMAXPATH,fullname);
4369     if (!fullname[0]) ckstrncpy(fullname,local,CKMAXPATH+1);
4370     fullname[CKMAXPATH] = NUL;
4371 
4372     if (displa && fdispla) {            /* Screen */
4373         ftscreen(SCR_FN,'F',(CK_OFF_T)pktnum,local);
4374         ftscreen(SCR_AN,0,(CK_OFF_T)0,asname);
4375         ftscreen(SCR_FS,0,fsize,"");
4376     }
4377 #ifdef DOUPDATE
4378     if (flg & (PUT_UPD|PUT_DIF)) {	/* Date-checking modes... */
4379         mt = chkmodtime(fullname,asname,0);
4380         debug(F111,"ftp putfile chkmodtime",asname,mt);
4381         if (mt == 0 && ((flg & PUT_DIF) == 0)) { /* Local is older */
4382             tlog(F110,"ftp put /update SKIP (Older modtime): ",fullname,0);
4383 	    /* Skip this one */
4384             ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_DAT,fullname);
4385             filcnt++;
4386             return(SKP_DAT);
4387         } else if (mt == 1) {           /* Times are equal */
4388             tlog(F110,"ftp put /update SKIP (Equal modtime): ",fullname,0);
4389             ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_EQU,fullname); /* Skip it */
4390             filcnt++;
4391             return(SKP_DAT);
4392         }
4393 	/* Local file is newer */
4394         tlog(F110,ftp_typ ? "ftp put /update BINARY:" :
4395              "ftp put /update TEXT:", fullname, 0);
4396     } else if (flg & PUT_RES) {
4397         tlog(F110,ftp_typ ? "ftp put /recover BINARY:" :
4398              "ftp put /recover TEXT:", fullname, 0);
4399     } else {
4400         tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4401     }
4402 #else
4403     tlog(F110,ftp_typ ? "ftp put BINARY:" : "ftp put TEXT:", fullname, 0);
4404 #endif /* DOUPDATE */
4405     tlog(F110," as",asname,0);
4406 
4407 #ifndef NOCSETS
4408     if (xlate) {
4409         debug(F111,"ftp putfile fcs",fcsinfo[fcs].keyword,fcs);
4410         tlog(F110," file character set:",fcsinfo[fcs].keyword,0);
4411         tlog(F110," server character set:",fcsinfo[rcs].keyword,0);
4412     } else if (!ftp_typ) {
4413         tlog(F110," character sets:","no conversion",0);
4414         fcs = ofcs;                     /* Binary file but we still must */
4415         rcs = orcs;                     /* translate its name */
4416     }
4417 #endif /* NOCSETS */
4418 
4419     /* PUT THE FILE */
4420 
4421     t0 = gmstimer();                    /* Start time */
4422     if (flg & PUT_SIM) {                /* rc > 0 is a skip reason code */
4423         if (flg & (PUT_UPD|PUT_DIF)) {	/* (see SKP_xxx in ckcker.h) */
4424             rc = (mt < 0) ?             /* Update mode... */
4425               SKP_XNX :                 /* Remote file doesn't exist */
4426                 SKP_XUP;                /* Remote file is older */
4427         } else {
4428             rc = SKP_SIM;               /* "Would be sent", period. */
4429         }
4430     } else {
4431         rc = sendrequest(cmd,local,asname,xlate,fcs,rcs,restart);
4432     }
4433     t1 = gmstimer();                    /* End time */
4434     filcnt++;                           /* File number */
4435 
4436 #ifdef GFTIMER
4437     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4438     fpxfsecs = sec;                     /* (for doxlog()) */
4439 #else
4440     sec = (t1 - t0) / 1000;
4441     xfsecs = (int)sec;
4442 #endif /* GFTIMER */
4443 
4444     debug(F111,"ftp sendrequest rc",local,rc);
4445 
4446     if (cancelfile || cancelgroup) {
4447         debug(F111,"ftp put canceled",ckitoa(cancelfile),cancelgroup);
4448         ftscreen(SCR_ST,ST_INT,(CK_OFF_T)0,"");
4449     } else if (rc > 0) {
4450         debug(F101,"ftp put skipped",local,rc);
4451         ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)rc,fullname);
4452     } else if (rc < 0) {
4453         debug(F111,"ftp put error",local,ftpcode);
4454         ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,&ftp_reply_str[4]);
4455     } else {
4456         debug(F111,"ftp put not canceled",ckitoa(displa),fdispla);
4457         ftscreen(SCR_PT,'Z',(CK_OFF_T)0,"");
4458         debug(F111,"ftp put ST_OK",local,rc);
4459         ftscreen(SCR_ST,ST_OK,(CK_OFF_T)0,"");
4460         debug(F110,"ftp put old sfspec",sfspec,0);
4461         makestr(&sfspec,fullname);      /* For WHERE command */
4462         debug(F110,"ftp put new sfspec",sfspec,0);
4463         debug(F110,"ftp put old srfspec",srfspec,0);
4464         makestr(&srfspec,asname);
4465         debug(F110,"ftp put new srfspec",srfspec,0);
4466     }
4467 
4468     /* Final log entries */
4469 
4470 #ifdef TLOG
4471     if (tralog) {
4472         if (rc > 0) {
4473             if (rc == SKP_XNX)
4474               tlog(F100," /simulate: WOULD BE SENT:","no remote file",0);
4475             else if (rc == SKP_XUP)
4476               tlog(F100," /simulate: WOULD BE SENT:","remote file older",0);
4477             else if (rc == SKP_SIM)
4478               tlog(F100," /simulate: WOULD BE SENT","",0);
4479             else
4480               tlog(F110," skipped:",gskreason(rc),0);
4481         } else if (rc == 0) {
4482             tlog(F101," complete, size", "", fsize);
4483         } else if (cancelfile) {
4484             tlog(F100," canceled by user","",0);
4485         } else {
4486             tlog(F110," failed:",ftp_reply_str,0);
4487         }
4488         if (!tlogfmt)
4489           doxlog(what,local,fsize,ftp_typ,rc,"");
4490     }
4491 #endif /* TLOG */
4492 
4493     if (rc < 0)                         /* PUT did not succeed */
4494       return(-1);                       /* so done. */
4495 
4496     if (flg & PUT_SIM)                  /* Simulating, skip the rest. */
4497       return(SKP_SIM);
4498 
4499 #ifdef UNIX
4500     /* Set permissions too? */
4501 
4502     if (prm) {                          /* Change permissions? */
4503         s = zgperm(local);              /* Get perms of local file */
4504         if (!s) s = "";
4505         x = strlen(s);
4506         if (x > 3) s += (x - 3);
4507         if (rdigits(s)) {
4508             ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,s," ",asname,NULL);
4509             x =
4510               ftpcmd("SITE CHMOD",ftpcmdbuf,fcs,rcs,ftp_vbm) == REPLY_COMPLETE;
4511             tlog(F110, x ? " chmod" : " chmod failed",
4512                  s,
4513                  0
4514                  );
4515             if (!x)
4516               return(-1);
4517         }
4518     }
4519 #endif /* UNIX */
4520 
4521     /* Disposition of source file */
4522 
4523     if (moving) {
4524         x = zdelet(local);
4525         tlog(F110, (x > -1) ?
4526              " deleted" : " failed to delete",
4527              local,
4528              0
4529              );
4530         if (x < 0)
4531           return(-1);
4532     } else if (mvto) {
4533         x = zrename(local,mvto);
4534         tlog(F110, (x > -1) ?
4535              " moved source to" : " failed to move source to",
4536              mvto,
4537              0
4538              );
4539         if (x < 0)
4540           return(-1);
4541         /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,mvto); */
4542 
4543     } else if (rnto) {
4544         char * s = rnto;
4545 #ifndef NOSPL
4546         int y;                          /* Pass it thru the evaluator */
4547         extern int cmd_quoting;         /* for \v(filename) */
4548         if (cmd_quoting) {              /* But only if cmd_quoting is on */
4549             y = CKMAXPATH;
4550             s = (char *)asname;
4551             zzstring(rnto,&s,&y);
4552             s = (char *)asname;
4553         }
4554 #endif /* NOSPL */
4555         if (s) if (*s) {
4556             int x;
4557             x = zrename(local,s);
4558             tlog(F110, (x > -1) ?
4559                  " renamed source file to" :
4560                  " failed to rename source file to",
4561                  s,
4562                  0
4563                  );
4564             if (x < 0)
4565               return(-1);
4566             /* ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,s); */
4567         }
4568     }
4569 
4570     /* Disposition of destination file */
4571 
4572     if (srvrn) {                        /* /SERVER-RENAME: */
4573         char * s = srvrn;
4574 #ifndef NOSPL
4575         int y;                          /* Pass it thru the evaluator */
4576         extern int cmd_quoting; /* for \v(filename) */
4577         debug(F111,"ftp putfile srvrn",s,1);
4578 
4579         if (cmd_quoting) {              /* But only if cmd_quoting is on */
4580             y = CKMAXPATH;
4581             s = (char *)fullname;       /* We can recycle this buffer now */
4582             zzstring(srvrn,&s,&y);
4583             s = (char *)fullname;
4584         }
4585 #endif /* NOSPL */
4586         debug(F111,"ftp putfile srvrn",s,2);
4587         if (s) if (*s) {
4588             int x;
4589             x = ftp_rename(asname,s);
4590             debug(F111,"ftp putfile ftp_rename",asname,x);
4591             tlog(F110, (x > 0) ?
4592                  " renamed destination file to" :
4593                  " failed to rename destination file to",
4594                  s,
4595                  0
4596                  );
4597             if (x < 1)
4598               return(-1);
4599         }
4600     }
4601     return(0);
4602 }
4603 
4604 /* xxout must only be used for ASCII transfers */
4605 static int
4606 #ifdef CK_ANSIC
xxout(char c)4607 xxout(char c)
4608 #else
4609 xxout(c) char c;
4610 #endif /* CK_ANSIC */
4611 {
4612 #ifndef OS2
4613 #ifndef VMS
4614 #ifndef MAC
4615 #ifndef OSK
4616     /* For Unix, DG, Stratus, Amiga, Gemdos, other */
4617     if (c == '\012') {
4618 	if (zzout(dout,(CHAR)'\015') < 0)
4619 	  return(-1);
4620 	ftpsnd.bytes++;
4621     }
4622 #else /* OSK */
4623     if (c == '\015') {
4624 	c = '\012';
4625 	if (zzout(dout,(CHAR)'\015') < 0)
4626 	  return(-1);
4627 	ftpsnd.bytes++;
4628     }
4629 #endif /* OSK */
4630 #else /* MAC */
4631     if (c == '\015') {
4632 	c = '\012';
4633 	if (zzout(dout,(CHAR)'\015') < 0)
4634 	  return(-1);
4635 	ftpsnd.bytes++;
4636     }
4637 #endif /* MAC */
4638 #endif /* VMS */
4639 #endif /* OS2 */
4640     if (zzout(dout,(CHAR)c) < 0)
4641       return(-1);
4642     ftpsnd.bytes++;
4643     return(0);
4644 }
4645 
4646 static int
4647 #ifdef CK_ANSIC
scrnout(char c)4648 scrnout(char c)
4649 #else
4650 scrnout(c) char c;
4651 #endif /* CK_ANSIC */
4652 {
4653     return(putchar(c));
4654 }
4655 
4656 static int
4657 #ifdef CK_ANSIC
pipeout(char c)4658 pipeout(char c)
4659 #else
4660 pipeout(c) char c;
4661 #endif /* CK_ANSIC */
4662 {
4663     return(zmchout(c));
4664 }
4665 
4666 static int
ispathsep(c)4667 ispathsep(c) int c; {
4668     switch (servertype) {
4669       case SYS_VMS:
4670       case SYS_TOPS10:
4671       case SYS_TOPS20:
4672         return(((c == ']') || (c == '>') || (c == ':')) ? 1 : 0);
4673       case SYS_OS2:
4674       case SYS_WIN32:
4675       case SYS_DOS:
4676         return(((c == '\\') || (c == '/') || (c == ':')) ? 1 : 0);
4677       case SYS_VOS:
4678         return((c == '>') ? 1 : 0);
4679       default:
4680         return((c == '/') ? 1 : 0);
4681     }
4682 }
4683 
4684 static int
iscanceled()4685 iscanceled() {
4686 #ifdef CK_CURSES
4687     extern int ck_repaint();
4688 #endif /* CK_CURSES */
4689     int x, rc = 0;
4690     char c = 0;
4691     if (cancelfile)
4692       return(1);
4693     x = conchk();                       /* Any chars waiting at console? */
4694     if (x-- > 0) {                      /* Yes...  */
4695         c = coninc(5);                  /* Get one */
4696         switch (c) {
4697           case 032:                     /* Ctrl-X or X */
4698           case 'z':
4699           case 'Z': cancelgroup++;      /* fall thru on purpose */
4700           case 030:                     /* Ctrl-Z or Z */
4701           case 'x':
4702           case 'X': cancelfile++; rc++; break;
4703 #ifdef CK_CURSES
4704           case 'L':
4705           case 'l':
4706           case 014:                     /* Ctrl-L or L or Ctrl-W */
4707           case 027:
4708             ck_repaint();               /* Refresh screen */
4709 #endif /* CK_CURSES */
4710         }
4711     }
4712     while (x-- > 0)                     /* Soak up any rest */
4713       c = coninc(1);
4714     return(rc);
4715 }
4716 
4717 #ifdef FTP_TIMEOUT
4718 /* fc = 0 for read; 1 for write */
4719 static int
check_data_connection(fd,fc)4720 check_data_connection(fd,fc) int fd, fc; {
4721     int x;
4722     struct timeval tv;
4723     fd_set in, out, err;
4724 
4725     if (ftp_timeout < 1L)
4726       return(0);
4727 
4728     FD_ZERO(&in);
4729     FD_ZERO(&out);
4730     FD_ZERO(&err);
4731     FD_SET(fd,fc ? &out : &in);
4732     tv.tv_sec = ftp_timeout;		/* Time limit */
4733     tv.tv_usec = 0L;
4734 
4735 #ifdef INTSELECT
4736     x = select(FD_SETSIZE,(int *)&in,(int *)&out,(int *)&err,&tv);
4737 #else
4738     x = select(FD_SETSIZE,&in,&out,&err,&tv);
4739 #endif /* INTSELECT */
4740 
4741     if (x == 0) {
4742 #ifdef EWOULDBLOCK
4743 	errno = EWOULDBLOCK;
4744 #else
4745 #ifdef EAGAIN
4746 	errno = EAGAIN;
4747 #else
4748 	errno = 11;
4749 #endif	/* EAGAIN */
4750 #endif	/* EWOULDBLOCK */
4751 	debug(F100,"ftp check_data_connection TIMOUT","",0);
4752 	return(-3);
4753     }
4754     return(0);
4755 }
4756 #endif	/* FTP_TIMEOUT */
4757 
4758 /* zzsend - used by buffered output macros. */
4759 
4760 static int
4761 #ifdef CK_ANSIC
zzsend(int fd,CHAR c)4762 zzsend(int fd, CHAR c)
4763 #else
4764 zzsend(fd,c) int fd; CHAR c;
4765 #endif /* CK_ANSIC */
4766 {
4767     int rc;
4768 
4769     debug(F101,"zzsend ucbufsiz","",ucbufsiz);
4770     debug(F101,"zzsend nout","",nout);
4771     debug(F111,"zzsend","secure?",ftpissecure());
4772 
4773     if (iscanceled())                   /* Check for cancellation */
4774       return(-9);
4775 
4776 #ifdef FTP_TIMEOUT
4777     ftp_timed_out = 0;
4778     if (check_data_connection(fd,1) < 0) {
4779 	ftp_timed_out = 1;
4780 	return(-3);
4781     }
4782 #endif	/* FTP_TIMEOUT */
4783 
4784     rc = (!ftpissecure()) ?
4785       send(fd, (SENDARG2TYPE)ucbuf, nout, 0) :
4786         secure_putbuf(fd, ucbuf, nout);
4787     ucbuf[nout] = NUL;
4788     nout = 0;
4789     ucbuf[nout++] = c;
4790     spackets++;
4791     pktnum++;
4792     if (rc > -1 && fdispla != XYFD_B) {
4793         spktl = nout;
4794         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
4795     }
4796     return(rc);
4797 }
4798 
4799 /* c m d l i n p u t  --  Command-line PUT */
4800 
4801 int
cmdlinput(stay)4802 cmdlinput(stay) int stay; {
4803     int x, rc = 0, done = 0, good = 0, status = 0;
4804     ULONG t0, t1;                       /* Times for stats */
4805 #ifdef GFTIMER
4806     CKFLOAT sec;
4807 #else
4808     int sec = 0;
4809 #endif /* GFTIMER */
4810 
4811     if (quiet) {                        /* -q really means quiet */
4812         displa = 0;
4813         fdispla = 0;
4814     } else {
4815         displa = 1;
4816         fdispla = XYFD_B;
4817     }
4818     testing = 0;
4819     out2screen = 0;
4820     dpyactive = 0;
4821     what = W_FTP|W_SEND;
4822 
4823 #ifndef NOSPL
4824     cmd_quoting = 0;
4825 #endif /* NOSPL */
4826     sndsrc = nfils;
4827 
4828     t0 = gmstimer();                    /* Record starting time */
4829 
4830     while (!done && !cancelgroup) {     /* Loop for all files */
4831 
4832         cancelfile = 0;
4833         x = gnfile();                   /* Get next file from list(s) */
4834         if (x == 0)                     /* (see gnfile() comments...) */
4835           x = gnferror;
4836 
4837         switch (x) {
4838           case 1:                       /* File to send */
4839             rc = putfile(FTP_PUT,       /* Function (PUT, APPEND) */
4840                          filnam,        /* Local file to send */
4841                          filnam,        /* Remote name for file */
4842                          forcetype,     /* Text/binary mode forced */
4843                          0,             /* Not moving */
4844                          NULL,          /* No move-to */
4845                          NULL,          /* No rename-to */
4846                          NULL,          /* No server-rename */
4847                          ftp_cnv,       /* Filename conversion */
4848                          0,             /* Unique-server-names */
4849                          -1,            /* All file types */
4850                          0,             /* No permissions */
4851                          -1,            /* No character sets */
4852                          -1,            /* No character sets */
4853                          0              /* No update or restart */
4854                          );
4855             if (rc > -1) {
4856                 good++;
4857                 status = 1;
4858             }
4859             if (cancelfile) {
4860                 continue;               /* Or break? */
4861             }
4862             if (rc < 0) {
4863                 ftp_fai++;
4864             }
4865             continue;                   /* Or break? */
4866 
4867           case 0:                       /* No more files, done */
4868             done++;
4869             continue;
4870 
4871           case -2:
4872           case -1:
4873             printf("?%s: file not found - \"%s\"\n",
4874                    puterror ? "Fatal" : "Warning",
4875                    filnam
4876                    );
4877             continue;                   /* or break? */
4878           case -3:
4879             printf("?Warning access denied - \"%s\"\n", filnam);
4880             continue;                   /* or break? */
4881           case -5:
4882             printf("?Too many files match\n");
4883             done++;
4884             break;
4885           case -6:
4886             if (good < 1)
4887               printf("?No files selected\n");
4888             done++;
4889             break;
4890           default:
4891             printf("?getnextfile() - unknown failure\n");
4892             done++;
4893         }
4894     }
4895     if (status > 0) {
4896         if (cancelgroup)
4897           status = 0;
4898         else if (cancelfile && good < 1)
4899           status = 0;
4900     }
4901     success = status;
4902     x = success;
4903     if (x > -1) {
4904         lastxfer = W_FTP|W_SEND;
4905         xferstat = success;
4906     }
4907     t1 = gmstimer();                    /* End time */
4908 #ifdef GFTIMER
4909     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
4910     if (!sec) sec = 0.001;
4911     fptsecs = sec;
4912 #else
4913     sec = (t1 - t0) / 1000;
4914     if (!sec) sec = 1;
4915 #endif /* GFTIMER */
4916     tfcps = (long) (tfc / sec);
4917     tsecs = (int)sec;
4918     lastxfer = W_FTP|W_SEND;
4919     xferstat = success;
4920     if (dpyactive)
4921       ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
4922     if (!stay)
4923       doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
4924     return(success);
4925 }
4926 
4927 
4928 /*  d o f t p p u t  --  Parse and execute PUT, MPUT, and APPEND  */
4929 
4930 int
4931 #ifdef CK_ANSIC
doftpput(int cx,int who)4932 doftpput(int cx, int who)               /* who == 1 for ftp, 0 for kermit */
4933 #else
4934 doftpput(cx,who) int cx, who;
4935 #endif /* CK_ANSIC */
4936 {
4937     struct FDB sf, fl, sw, cm;
4938     int n, rc, confirmed = 0, wild = 0, getval = 0, mput = 0, done = 0;
4939     int x_cnv = 0, x_usn = 0, x_prm = 0, putflags = 0, status = 0, good = 0;
4940     char * s, * s2;
4941 
4942     int x_csl, x_csr = -1;              /* Local and remote charsets */
4943     int x_xla = 0;
4944     int x_recurse = 0;
4945     char c, * p;                        /* Workers */
4946 #ifdef PUTARRAY
4947     int range[2];                       /* Array range */
4948     char ** ap = NULL;                  /* Array pointer */
4949     int arrayx = -1;                    /* Array index */
4950 #endif /* PUTARRAY */
4951     ULONG t0 = 0L, t1 = 0L;             /* Times for stats */
4952 #ifdef GFTIMER
4953     CKFLOAT sec;
4954 #else
4955     int sec = 0;
4956 #endif /* GFTIMER */
4957 
4958     struct stringint pv[SND_MAX+1];    /* Temporary array for switch values */
4959     success = 0;                        /* Assume failure */
4960     forcetype = 0;                      /* No /TEXT or /BINARY given yet */
4961     out2screen = 0;                     /* Not outputting file to screen */
4962     putflags = 0;                       /* PUT options */
4963     x_cnv = ftp_cnv;                    /* Filename conversion */
4964     x_usn = ftp_usn;                    /* Unique server names */
4965     x_prm = ftp_prm;                    /* Permissions */
4966     if (x_prm == SET_AUTO)              /* Permissions AUTO */
4967       x_prm = alike;
4968 
4969 #ifndef NOCSETS
4970     x_csr = ftp_csr;                    /* Inherit global server charset */
4971     x_csl = ftp_csl;
4972     if (x_csl < 0)
4973       x_csl = fcharset;
4974     x_xla = ftp_xla;
4975 #endif /* NOCSETS */
4976 
4977     makestr(&filefile,NULL);            /* No filename list file yet. */
4978     makestr(&srv_renam,NULL);		/* Clear /SERVER-RENAME: */
4979     makestr(&snd_rename,NULL);		/*  PUT /RENAME */
4980     makestr(&snd_move,NULL);		/*  PUT /MOVE */
4981     putpath[0] = NUL;                   /* Initialize for syncdir(). */
4982     puterror = ftp_err;                 /* Inherit global error action. */
4983     what = W_SEND|W_FTP;                /* What we're doing (sending w/FTP) */
4984     asnambuf[0] = NUL;                  /* Clear as-name buffer */
4985 
4986     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
4987         ftp_typ = g_ftp_typ;
4988         /* g_ftp_typ = -1; */
4989     }
4990     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
4991         pv[i].sval = NULL;              /* to null pointers */
4992         pv[i].ival = -1;                /* and -1 int values */
4993         pv[i].wval = (CK_OFF_T)-1;	/* and -1 wide values */
4994     }
4995     if (who == 0) {                     /* Called with unprefixed command */
4996         switch (cx) {
4997           case XXRSEN:  pv[SND_RES].ival = 1; break;
4998           case XXCSEN:  pv[SND_CMD].ival = 1; break;
4999           case XXMOVE:  pv[SND_DEL].ival = 1; break;
5000           case XXMMOVE: pv[SND_DEL].ival = 1; /* fall thru */
5001           case XXMSE:   mput++; break;
5002         }
5003     } else {
5004 	if (cx == FTP_REP)
5005 	  pv[SND_RES].ival = 1;
5006         if (cx == FTP_MPU)
5007           mput++;
5008     }
5009     cmfdbi(&sw,                         /* First FDB - command switches */
5010            _CMKEY,                      /* fcode */
5011            "Filename, or switch",       /* hlpmsg */
5012            "",                          /* default */
5013            "",                          /* addtl string data */
5014            nputswi,                     /* addtl numeric data 1: tbl size */
5015            4,                           /* addtl numeric data 2: 4 = cmswi */
5016            xxstring,                    /* Processing function */
5017            putswi,                      /* Keyword table */
5018            &sf                          /* Pointer to next FDB */
5019            );
5020     cmfdbi(&fl,                         /* 3rd FDB - local filespec */
5021            _CMFLD,                      /* fcode */
5022            "",                          /* hlpmsg */
5023            "",                          /* default */
5024            "",                          /* addtl string data */
5025            0,                           /* addtl numeric data 1 */
5026            0,                           /* addtl numeric data 2 */
5027            xxstring,
5028            NULL,
5029            &cm
5030            );
5031     cmfdbi(&cm,                         /* 4th FDB - Confirmation */
5032            _CMCFM,                      /* fcode */
5033            "",                          /* hlpmsg */
5034            "",                          /* default */
5035            "",                          /* addtl string data */
5036            0,                           /* addtl numeric data 1 */
5037            0,                           /* addtl numeric data 2 */
5038            NULL,
5039            NULL,
5040            NULL
5041            );
5042 
5043   again:
5044     cmfdbi(&sf,                         /* 2nd FDB - file to send */
5045            _CMIFI,                      /* fcode */
5046            "",                          /* hlpmsg */
5047            "",                          /* default */
5048            "",                          /* addtl string data */
5049            /* 0 = parse files, 1 = parse files or dirs, 2 = skip symlinks */
5050            nolinks | x_recurse,         /* addtl numeric data 1 */
5051            0,                           /* dirflg 0 means "not dirs only" */
5052            xxstring,
5053            NULL,
5054 #ifdef COMMENT
5055            mput ? &cm : &fl
5056 #else
5057 	   &fl
5058 #endif /* COMMENT */
5059            );
5060 
5061     while (1) {                         /* Parse zero or more switches */
5062         x = cmfdb(&sw);                 /* Parse something */
5063         debug(F101,"ftp put cmfdb A","",x);
5064         debug(F101,"ftp put fcode A","",cmresult.fcode);
5065         if (x < 0)                      /* Error */
5066           goto xputx;                   /* or reparse needed */
5067         if (cmresult.fcode != _CMKEY)   /* Break out of loop if not a switch */
5068           break;
5069         c = cmgbrk();                   /* Get break character */
5070         getval = (c == ':' || c == '='); /* to see how they ended the switch */
5071         if (getval && !(cmresult.kflags & CM_ARG)) {
5072             printf("?This switch does not take arguments\n");
5073             x = -9;
5074             goto xputx;
5075         }
5076         if (!getval && (cmgkwflgs() & CM_ARG)) {
5077             printf("?This switch requires an argument\n");
5078             x = -9;
5079             goto xputx;
5080         }
5081         n = cmresult.nresult;           /* Numeric result = switch value */
5082         debug(F101,"ftp put switch","",n);
5083 
5084         switch (n) {                    /* Process the switch */
5085           case SND_AFT:                 /* Send /AFTER:date-time */
5086           case SND_BEF:                 /* Send /BEFORE:date-time */
5087           case SND_NAF:                 /* Send /NOT-AFTER:date-time */
5088           case SND_NBE:                 /* Send /NOT-BEFORE:date-time */
5089             if (!getval) break;
5090             if ((x = cmdate("File date-time","",&s,0,xxstring)) < 0) {
5091                 if (x == -3) {
5092                     printf("?Date-time required\n");
5093                     x = -9;
5094                 }
5095                 goto xputx;
5096             }
5097             pv[n].ival = 1;
5098             makestr(&(pv[n].sval),s);
5099             break;
5100 
5101           case SND_ASN:                 /* /AS-NAME: */
5102             debug(F101,"ftp put /as-name getval","",getval);
5103             if (!getval) break;
5104             if ((x = cmfld("Name to send under","",&s,NULL)) < 0) {
5105                 if (x == -3) {
5106                     printf("?name required\n");
5107                     x = -9;
5108                 }
5109                 goto xputx;
5110             }
5111             makestr(&(pv[n].sval),brstrip(s));
5112             debug(F110,"ftp put /as-name 1",pv[n].sval,0);
5113             if (pv[n].sval) pv[n].ival = 1;
5114             break;
5115 
5116 #ifdef PUTARRAY
5117           case SND_ARR:                 /* /ARRAY */
5118             if (!getval) break;
5119             ap = NULL;
5120             if ((x = cmfld("Array name (a single letter will do)",
5121                            "",
5122                            &s,
5123                            NULL
5124                            )) < 0) {
5125                 if (x == -3)
5126 		  break;
5127 		else
5128 		  return(x);
5129             }
5130             if ((x = arraybounds(s,&(range[0]),&(range[1]))) < 0) {
5131                 printf("?Bad array: %s\n",s);
5132                 return(-9);
5133             }
5134             if (!(ap = a_ptr[x])) {
5135                 printf("?No such array: %s\n",s);
5136                 return(-9);
5137             }
5138             pv[n].ival = 1;
5139             pv[SND_CMD].ival = 0;       /* Undo any conflicting ones... */
5140             pv[SND_RES].ival = 0;
5141             pv[SND_FIL].ival = 0;
5142             arrayx = x;
5143             break;
5144 #endif /* PUTARRAY */
5145 
5146           case SND_BIN:                 /* /BINARY */
5147           case SND_TXT:                 /* /TEXT or /ASCII */
5148           case SND_TEN:                 /* /TENEX */
5149             pv[SND_BIN].ival = 0;
5150             pv[SND_TXT].ival = 0;
5151             pv[SND_TEN].ival = 0;
5152             pv[n].ival = 1;
5153             break;
5154 
5155 #ifdef PUTPIPE
5156           case SND_CMD:                 /* These take no args */
5157             if (nopush) {
5158                 printf("?Sorry, system command access is disabled\n");
5159                 x = -9;
5160                 goto xputx;
5161             }
5162 #ifdef PIPESEND
5163             else if (sndfilter) {
5164                 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
5165                 x = -9;
5166                 goto xputx;
5167             }
5168 #endif /* PIPESEND */
5169             sw.hlpmsg = "Command, or switch"; /* Change help message */
5170             pv[n].ival = 1;             /* Just set the flag */
5171             pv[SND_ARR].ival = 0;
5172             break;
5173 #endif /* PUTPIPE */
5174 
5175 #ifdef CKSYMLINK
5176           case SND_LNK:
5177             nolinks = 0;
5178             goto again;			/* Because CMIFI params changed... */
5179           case SND_NLK:
5180             nolinks = 2;
5181             goto again;
5182 #endif /* CKSYMLINK */
5183 
5184 #ifdef FTP_RESTART
5185           case SND_RES:                 /* /RECOVER (resend) */
5186             pv[SND_ARR].ival = 0;       /* fall thru on purpose... */
5187 #endif /* FTP_RESTART */
5188 
5189           case SND_NOB:
5190           case SND_DEL:                 /* /DELETE */
5191           case SND_SHH:                 /* /QUIET */
5192           case SND_UPD:                 /* /UPDATE */
5193           case SND_SIM:                 /* /UPDATE */
5194           case SND_USN:                 /* /UNIQUE */
5195             pv[n].ival = 1;             /* Just set the flag */
5196             break;
5197 
5198           case SND_REC:                 /* /RECURSIVE */
5199             recursive = 2;              /* Must be set before cmifi() */
5200             x_recurse = 1;
5201             goto again;			/* Because CMIFI params changed... */
5202             break;
5203 
5204 #ifdef UNIXOROSK
5205           case SND_DOT:                 /* /DOTFILES */
5206             matchdot = 1;
5207             break;
5208           case SND_NOD:                 /* /NODOTFILES */
5209             matchdot = 0;
5210             break;
5211 #endif /* UNIXOROSK */
5212 
5213           case SND_ERR:                 /* /ERROR-ACTION */
5214             if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
5215               goto xputx;
5216             pv[n].ival = x;
5217             break;
5218 
5219           case SND_EXC:                 /* Excludes */
5220             if (!getval) break;
5221             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
5222                 if (x == -3) {
5223                     printf("?Pattern required\n");
5224                     x = -9;
5225                 }
5226                 goto xputx;
5227             }
5228             if (s) if (!*s) s = NULL;
5229             makestr(&(pv[n].sval),s);
5230             if (pv[n].sval)
5231               pv[n].ival = 1;
5232             break;
5233 
5234           case SND_PRM:                 /* /PERMISSIONS */
5235             if (!getval)
5236               x = 1;
5237             else if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5238               goto xputx;
5239             pv[SND_PRM].ival = x;
5240             break;
5241 
5242 #ifdef PIPESEND
5243           case SND_FLT:                 /* /FILTER */
5244             debug(F101,"ftp put /filter getval","",getval);
5245             if (!getval) break;
5246             if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
5247                 if (x == -3)
5248                   s = "";
5249                 else
5250                   goto xputx;
5251             }
5252             if (*s) s = brstrip(s);
5253             y = strlen(s);
5254             for (x = 0; x < y; x++) {   /* Make sure they included "\v(...)" */
5255                 if (s[x] != '\\') continue;
5256                 if (s[x+1] == 'v') break;
5257             }
5258             if (x == y) {
5259                 printf(
5260                 "?Filter must contain a replacement variable for filename.\n"
5261                        );
5262                 x = -9;
5263                 goto xputx;
5264             }
5265             if (s) if (!*s) s = NULL;
5266             makestr(&(pv[n].sval),s);
5267             if (pv[n].sval)
5268               pv[n].ival = 1;
5269             break;
5270 #endif /* PIPESEND */
5271 
5272           case SND_NAM:                 /* /FILENAMES */
5273             if (!getval) break;
5274             if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
5275               goto xputx;
5276             debug(F101,"ftp put /filenames","",x);
5277             pv[n].ival = x;
5278             break;
5279 
5280           case SND_SMA:                 /* Smaller / larger than */
5281           case SND_LAR: {
5282 	      CK_OFF_T y;
5283 	      if (!getval) break;
5284 	      if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
5285 		goto xputx;
5286 	      pv[n].wval = y;
5287 	      break;
5288 	  }
5289           case SND_FIL:                 /* Name of file containing filenames */
5290             if (!getval) break;
5291             if ((x = cmifi("Name of file containing list of filenames",
5292                                "",&s,&y,xxstring)) < 0) {
5293                 if (x == -3) {
5294                     printf("?Filename required\n");
5295                     x = -9;
5296                 }
5297                 goto xputx;
5298             } else if (y && iswild(s)) {
5299                 printf("?Wildcards not allowed\n");
5300                 x = -9;
5301                 goto xputx;
5302             }
5303             if (s) if (!*s) s = NULL;
5304             makestr(&(pv[n].sval),s);
5305             if (pv[n].sval) {
5306                 pv[n].ival = 1;
5307                 pv[SND_ARR].ival = 0;
5308             } else {
5309                 pv[n].ival = 0;
5310             }
5311             mput = 0;
5312             break;
5313 
5314           case SND_MOV:                 /* MOVE after */
5315           case SND_REN:                 /* RENAME after */
5316           case SND_SRN: {               /* SERVER-RENAME after */
5317               char * m = "";
5318               switch (n) {
5319                 case SND_MOV:
5320                   m = "device and/or directory for source file after sending";
5321                   break;
5322                 case SND_REN:
5323                   m = "new name for source file after sending";
5324                   break;
5325                 case SND_SRN:
5326                   m = "new name for destination file after sending";
5327                   break;
5328               }
5329               if (!getval) break;
5330               if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
5331                   if (x == -3) {
5332                       printf("%s\n", n == SND_MOV ?
5333                              "?Destination required" :
5334                              "?New name required"
5335                              );
5336                       x = -9;
5337                   }
5338                   goto xputx;
5339               }
5340               if (s) if (!*s) s = NULL;
5341               makestr(&(pv[n].sval),s ? brstrip(s) : NULL);
5342               pv[n].ival = (pv[n].sval) ? 1 : 0;
5343               break;
5344           }
5345           case SND_STA:                 /* Starting position (= PSEND) */
5346             if (!getval) break;
5347             if ((x = cmnum("0-based position","0",10,&y,xxstring)) < 0)
5348               goto xputx;
5349             pv[n].ival = y;
5350             break;
5351 
5352           case SND_TYP:                 /* /TYPE */
5353             if (!getval) break;
5354             if ((x = cmkey(txtbin,3,"","all",xxstring)) < 0)
5355               goto xputx;
5356             pv[n].ival = (x == 2) ? -1 : x;
5357             break;
5358 
5359 #ifndef NOCSETS
5360           case SND_CSL:                 /* Local character set */
5361           case SND_CSR:                 /* Remote (server) charset */
5362             if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0) {
5363 		return((x == -3) ? -2 : x);
5364             }
5365 	    if (n == SND_CSL)
5366               x_csl = x;
5367             else
5368               x_csr = x;
5369             x_xla = 1;                  /* Overrides global OFF setting */
5370             break;
5371 
5372           case SND_XPA:                 /* Transparent */
5373             x_xla = 0;
5374             x_csr = -1;
5375             x_csl = -1;
5376             break;
5377 #endif /* NOCSETS */
5378         }
5379     }
5380 #ifdef PIPESEND
5381     if (pv[SND_RES].ival > 0) { /* /RECOVER */
5382         if (sndfilter || pv[SND_FLT].ival > 0) {
5383             printf("?Sorry, no /RECOVER or /START if SEND FILTER selected\n");
5384             x = -9;
5385             goto xputx;
5386         }
5387 	if (sfttab[0] > 0 && sfttab[SFT_REST] == 0)
5388 	  printf("WARNING: Server says it doesn't support REST.\n");
5389     }
5390 #endif /* PIPESEND */
5391 
5392     cmarg = "";
5393     cmarg2 = asnambuf;
5394     line[0] = NUL;
5395     s = line;
5396     wild = 0;
5397 
5398     switch (cmresult.fcode) {           /* How did we get out of switch loop */
5399       case _CMIFI:                      /* Input filename */
5400         if (pv[SND_FIL].ival > 0) {
5401             printf("?You may not give a PUT filespec and a /LISTFILE\n");
5402             x = -9;
5403             goto xputx;
5404         }
5405         ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Name */
5406         if (pv[SND_ARR].ival > 0)
5407           ckstrncpy(asnambuf,line,CKMAXPATH);
5408         else
5409           wild = cmresult.nresult;      /* Wild flag */
5410         debug(F111,"ftp put wild",line,wild);
5411         if (!wild && !recursive && !mput)
5412           nolinks = 0;
5413         break;
5414       case _CMFLD:                      /* Field */
5415         /* Only allowed with /COMMAND and /ARRAY */
5416         if (pv[SND_FIL].ival > 0) {
5417             printf("?You may not give a PUT filespec and a /LISTFILE\n");
5418             x = -9;
5419             goto xputx;
5420         }
5421 	/* For MPUT it's OK to have filespecs that don't match any files */
5422 	if (mput)
5423 	  break;
5424         if (pv[SND_CMD].ival < 1 && pv[SND_ARR].ival < 1) {
5425 #ifdef CKROOT
5426             if (ckrooterr)
5427               printf("?Off limits: %s\n",cmresult.sresult);
5428             else
5429 #endif /* CKROOT */
5430               printf("?%s - \"%s\"\n",
5431                    iswild(cmresult.sresult) ?
5432                    "No files match" : "File not found",
5433                    cmresult.sresult
5434                    );
5435             x = -9;
5436             goto xputx;
5437         }
5438         ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
5439         if (pv[SND_ARR].ival > 0)
5440           ckstrncpy(asnambuf,line,CKMAXPATH);
5441         break;
5442       case _CMCFM:                      /* Confirmation */
5443         confirmed = 1;
5444         break;
5445       default:
5446         printf("?Unexpected function code: %d\n",cmresult.fcode);
5447         x = -9;
5448         goto xputx;
5449     }
5450     debug(F110,"ftp put string",s,0);
5451     debug(F101,"ftp put confirmed","",confirmed);
5452 
5453     /* Save and change protocol and transfer mode */
5454     /* Global values are restored in main parse loop */
5455 
5456     g_displa = fdispla;
5457     if (ftp_dis > -1)
5458       fdispla = ftp_dis;
5459     g_skipbup = skipbup;
5460 
5461     if (pv[SND_NOB].ival > -1) {        /* /NOBACKUP (skip backup file) */
5462         g_skipbup = skipbup;
5463         skipbup = 1;
5464     }
5465     if (pv[SND_TYP].ival > -1) {        /* /TYPE */
5466         xfiletype = pv[SND_TYP].ival;
5467         if (xfiletype == 2)
5468           xfiletype = -1;
5469     }
5470     if (pv[SND_BIN].ival > 0) {         /* /BINARY really means binary... */
5471         forcetype = 1;                  /* So skip file scan */
5472         ftp_typ = FTT_BIN;              /* Set binary */
5473     } else if (pv[SND_TXT].ival > 0) {  /* Similarly for /TEXT... */
5474         forcetype = 1;
5475         ftp_typ = FTT_ASC;
5476     } else if (pv[SND_TEN].ival > 0) {  /* and /TENEX*/
5477         forcetype = 1;
5478         ftp_typ = FTT_TEN;
5479     } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
5480         forcetype = 1;
5481         ftp_typ = binary;
5482         g_ftp_typ = binary;
5483     }
5484 
5485 #ifdef PIPESEND
5486     if (pv[SND_CMD].ival > 0) {         /* /COMMAND - strip any braces */
5487         debug(F110,"PUT /COMMAND before stripping",s,0);
5488         s = brstrip(s);
5489         debug(F110,"PUT /COMMAND after stripping",s,0);
5490         if (!*s) {
5491             printf("?Sorry, a command to send from is required\n");
5492             x = -9;
5493             goto xputx;
5494         }
5495         cmarg = s;
5496     }
5497 #endif /* PIPESEND */
5498 
5499 /* Set up /MOVE and /RENAME */
5500 
5501     if (pv[SND_DEL].ival > 0 &&
5502         (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
5503         printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
5504         x = -9;
5505         goto xputx;
5506     }
5507 #ifdef CK_TMPDIR
5508     if (pv[SND_MOV].ival > 0) {
5509         int len;
5510         char * p = pv[SND_MOV].sval;
5511         len = strlen(p);
5512         if (!isdir(p)) {                /* Check directory */
5513 #ifdef CK_MKDIR
5514             char * s = NULL;
5515             s = (char *)malloc(len + 4);
5516             if (s) {
5517                 strcpy(s,p);            /* safe */
5518 #ifdef datageneral
5519                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
5520 #else
5521                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
5522 #endif /* datageneral */
5523                 s[len++] = 'X';
5524                 s[len] = NUL;
5525 #ifdef NOMKDIR
5526                 x = -1;
5527 #else
5528                 x = zmkdir(s);
5529 #endif /* NOMKDIR */
5530                 free(s);
5531                 if (x < 0) {
5532                     printf("?Can't create \"%s\"\n",p);
5533                     x = -9;
5534                     goto xputx;
5535                 }
5536             }
5537 #else
5538             printf("?Directory \"%s\" not found\n",p);
5539             x = -9;
5540             goto xputx;
5541 #endif /* CK_MKDIR */
5542         }
5543         makestr(&snd_move,p);
5544     }
5545 #endif /* CK_TMPDIR */
5546 
5547     if (pv[SND_REN].ival > 0) {         /* /RENAME */
5548         char * p = pv[SND_REN].sval;
5549         if (!p) p = "";
5550         if (!*p) {
5551             printf("?New name required for /RENAME\n");
5552             x = -9;
5553             goto xputx;
5554         }
5555         p = brstrip(p);
5556 #ifndef NOSPL
5557     /* If name given is wild, rename string must contain variables */
5558         if (wild) {
5559             char * s = tmpbuf;
5560             x = TMPBUFSIZ;
5561             zzstring(p,&s,&x);
5562             if (!strcmp(tmpbuf,p)) {
5563                 printf(
5564     "?/RENAME for file group must contain variables such as \\v(filename)\n"
5565                        );
5566                 x = -9;
5567                 goto xputx;
5568             }
5569         }
5570 #endif /* NOSPL */
5571         makestr(&snd_rename,p);
5572         debug(F110,"FTP snd_rename",snd_rename,0);
5573     }
5574     if (pv[SND_SRN].ival > 0) {         /* /SERVER-RENAME */
5575         char * p = pv[SND_SRN].sval;
5576         if (!p) p = "";
5577         if (!*p) {
5578             printf("?New name required for /SERVER-RENAME\n");
5579             x = -9;
5580             goto xputx;
5581         }
5582         p = brstrip(p);
5583 #ifndef NOSPL
5584         if (wild) {
5585             char * s = tmpbuf;
5586             x = TMPBUFSIZ;
5587             zzstring(p,&s,&x);
5588             if (!strcmp(tmpbuf,p)) {
5589                 printf(
5590 "?/SERVER-RENAME for file group must contain variables such as \\v(filename)\n"
5591                        );
5592                 x = -9;
5593                 goto xputx;
5594             }
5595         }
5596 #endif /* NOSPL */
5597         makestr(&srv_renam,p);
5598         debug(F110,"ftp put srv_renam",srv_renam,0);
5599     }
5600     if (!confirmed) {                   /* CR not typed yet, get more fields */
5601         char * lp;
5602         if (mput) {                     /* MPUT or MMOVE */
5603             nfils = 0;                  /* We already have the first one */
5604 #ifndef NOMSEND
5605 	    if (cmresult.fcode == _CMIFI) {
5606 		/* First filespec is valid */
5607 		msfiles[nfils++] = line;    /* Store pointer */
5608 		lp = line + (int)strlen(line) + 1; /* Point past it */
5609 		debug(F111,"ftp put mput",msfiles[nfils-1],nfils-1);
5610 	    } else {
5611 		/* First filespec matches no files */
5612 		debug(F110,"ftp put mput skipping first filespec",
5613 		      cmresult.sresult,
5614 		      0
5615 		      );
5616 		lp = line;
5617 	    }
5618 	    /* Parse a filespec, a "field", or confirmation */
5619 
5620 	    cmfdbi(&sf,			/* 1st FDB - file to send */
5621 		   _CMIFI,		/* fcode */
5622 		   "",			/* hlpmsg */
5623 		   "",			/* default */
5624 		   "",			/* addtl string data */
5625 		   nolinks | x_recurse,	/* addtl numeric data 1 */
5626 		   0,			/* dirflg 0 means "not dirs only" */
5627 		   xxstring,
5628 		   NULL,
5629 		   &fl
5630 		   );
5631 	    cmfdbi(&fl,			/* 2nd FDB - local filespec */
5632 		   _CMFLD,		/* fcode */
5633 		   "",			/* hlpmsg */
5634 		   "",			/* default */
5635 		   "",			/* addtl string data */
5636 		   0,			/* addtl numeric data 1 */
5637 		   0,			/* addtl numeric data 2 */
5638 		   xxstring,
5639 		   NULL,
5640 		   &cm
5641 		   );
5642 	    cmfdbi(&cm,			/* 3rd FDB - Confirmation */
5643 		   _CMCFM,		/* fcode */
5644 		   "",
5645 		   "",
5646 		   "",
5647 		   0,
5648 		   0,
5649 		   NULL,
5650 		   NULL,
5651 		   NULL
5652 		   );
5653 
5654             while (!confirmed) {	/* Get more filenames */
5655 		x = cmfdb(&sf);		/* Parse something */
5656 		debug(F101,"ftp put cmfdb B","",x);
5657 		debug(F101,"ftp put fcode B","",cmresult.fcode);
5658 		if (x < 0)		/* Error */
5659 		  goto xputx;		/* or reparse needed */
5660 		switch (cmresult.fcode) {
5661 		  case _CMCFM:		/* End of command */
5662 		    confirmed++;
5663 		    if (nfils < 1) {
5664 			debug(F100,"ftp put mput no files match","",0);
5665 			printf("?No files match MPUT list\n");
5666 			x = -9;
5667 			goto xputx;
5668 		    }
5669 		    break;
5670 		  case _CMFLD:		/* No match */
5671 		    debug(F110,"ftp put mput skipping",cmresult.sresult,0);
5672 		    continue;
5673 		  case _CMIFI:		/* Good match */
5674 		    s = cmresult.sresult;
5675 		    msfiles[nfils++] = lp; /* Got one, count, point to it, */
5676 		    p = lp;		   /* remember pointer, */
5677 		    while ((*lp++ = *s++)) /* and copy it into buffer */
5678 		      if (lp > (line + LINBUFSIZ)) { /* Avoid memory leak */
5679 			  printf("?MPUT list too long\n");
5680 			  line[0] = NUL;
5681 			  x = -9;
5682 			  goto xputx;
5683 		      }
5684 		    debug(F111,"ftp put mput adding",msfiles[nfils-1],nfils-1);
5685 		    if (nfils == 1)	/* Take care of \v(filespec) */
5686 		      fspec[0] = NUL;
5687 #ifdef ZFNQFP
5688 		    zfnqfp(p,TMPBUFSIZ,tmpbuf);
5689 		    p = tmpbuf;
5690 #endif /* ZFNQFP */
5691 		    if (((int)strlen(fspec) + (int)strlen(p) + 1) < fspeclen) {
5692 			strcat(fspec,p);    /* safe */
5693 			strcat(fspec," ");  /* safe */
5694 		    } else {
5695 #ifdef COMMENT
5696 			printf("WARNING - \\v(filespec) buffer overflow\n");
5697 #else
5698 			debug(F101,"doxput filespec buffer overflow","",0);
5699 #endif /* COMMENT */
5700 		    }
5701 		}
5702 	    }
5703 #endif /* NOMSEND */
5704         } else {                        /* Regular PUT */
5705             nfils = -1;
5706             if ((x = cmtxt(wild ?
5707 "\nOptional as-name template containing replacement variables \
5708 like \\v(filename)" :
5709                            "Optional name to send it with",
5710                            "",&p,NULL)) < 0)
5711               goto xputx;
5712 
5713             if (p) if (!*p) p = NULL;
5714             p = brstrip(p);
5715 
5716             if (p && *p) {
5717                 makestr(&(pv[SND_ASN].sval),p);
5718                 if (pv[SND_ASN].sval)
5719                   pv[SND_ASN].ival = 1;
5720                 debug(F110,"ftp put /as-name 2",pv[SND_ASN].sval,0);
5721             }
5722         }
5723     }
5724     /* Set cmarg2 from as-name, however we got it. */
5725 
5726     CHECKCONN();
5727     if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
5728         char * p;
5729         p = brstrip(pv[SND_ASN].sval);
5730         ckstrncpy(asnambuf,p,CKMAXPATH+1);
5731     }
5732     debug(F110,"ftp put asnambuf",asnambuf,0);
5733 
5734     if (pv[SND_FIL].ival > 0) {
5735         if (confirmed) {
5736             if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
5737                 debug(F110,"ftp put can't open",pv[SND_FIL].sval,0);
5738                 printf("?Failure to open %s\n",pv[SND_FIL].sval);
5739                 x = -9;
5740                 goto xputx;
5741             }
5742             makestr(&filefile,pv[SND_FIL].sval); /* Open, remember name */
5743             debug(F110,"ftp PUT /LISTFILE opened",filefile,0);
5744             wild = 1;
5745         }
5746     }
5747     if (confirmed && !line[0] && !filefile) {
5748 #ifndef NOMSEND
5749         if (filehead) {                 /* OK if we have a SEND-LIST */
5750             nfils = filesinlist;
5751             sndsrc = nfils;             /* Like MSEND */
5752             addlist = 1;                /* But using a different list... */
5753             filenext = filehead;
5754             goto doput;
5755         }
5756 #endif /* NOMSEND */
5757         printf("?Filename required but not given\n");
5758         x = -9;
5759         goto xputx;
5760     }
5761 #ifndef NOMSEND
5762     addlist = 0;                        /* Don't use SEND-LIST. */
5763 #endif /* NOMSEND */
5764 
5765     if (mput) {                         /* MPUT (rather than PUT) */
5766 #ifndef NOMSEND
5767         cmlist = msfiles;               /* List of filespecs */
5768         sndsrc = nfils;                 /* rather filespec and as-name */
5769 #endif /* NOMSEND */
5770         pipesend = 0;
5771     } else if (filefile) {              /* File contains list of filenames */
5772         s = "";
5773         cmarg = "";
5774         line[0] = NUL;
5775         nfils = 1;
5776         sndsrc = 1;
5777 
5778     } else if (pv[SND_ARR].ival < 1 && pv[SND_CMD].ival < 1) {
5779 
5780         /* Not MSEND, MMOVE, /LIST, or /ARRAY */
5781         nfils = sndsrc = -1;
5782         if (!wild) {
5783             if (zchki(s) < 0) {
5784                 printf("?Read access denied - \"%s\"\n", s);
5785                 x = -9;
5786                 goto xputx;
5787             }
5788         }
5789         if (s != line)                  /* We might already have done this. */
5790           ckstrncpy(line,s,LINBUFSIZ);  /* Copy of string just parsed. */
5791 #ifdef DEBUG
5792         else
5793           debug(F110,"doxput line=s",line,0);
5794 #endif /* DEBUG */
5795         cmarg = line;                   /* File to send */
5796     }
5797 #ifndef NOMSEND
5798     zfnqfp(cmarg,fspeclen,fspec);       /* Get full name */
5799 #endif /* NOMSEND */
5800 
5801     if (!mput) {                        /* For all but MPUT... */
5802 #ifdef PIPESEND
5803         if (pv[SND_CMD].ival > 0)       /* /COMMAND sets pipesend flag */
5804           pipesend = 1;
5805         debug(F101,"ftp put /COMMAND pipesend","",pipesend);
5806         if (pipesend && filefile) {
5807             printf("?Invalid switch combination\n");
5808             x = -9;
5809             goto xputx;
5810         }
5811 #endif /* PIPESEND */
5812 
5813 #ifndef NOSPL
5814     /* If as-name given and filespec is wild, as-name must contain variables */
5815         if ((wild || mput) && asnambuf[0]) {
5816             char * s = tmpbuf;
5817             x = TMPBUFSIZ;
5818             zzstring(asnambuf,&s,&x);
5819             if (!strcmp(tmpbuf,asnambuf)) {
5820                 printf(
5821     "?As-name for file group must contain variables such as \\v(filename)\n"
5822                        );
5823                 x = -9;
5824                 goto xputx;
5825             }
5826         }
5827 #endif /* NOSPL */
5828     }
5829 
5830   doput:
5831 
5832     if (pv[SND_SHH].ival > 0) {         /* SEND /QUIET... */
5833         fdispla = 0;
5834         debug(F101,"ftp put display","",fdispla);
5835     } else {
5836         displa = 1;
5837         if (ftp_deb)
5838 	  fdispla = XYFD_B;
5839     }
5840 
5841 #ifdef PUTARRAY                         /* SEND /ARRAY... */
5842     if (pv[SND_ARR].ival > 0) {
5843         if (!ap) { x = -2; goto xputx; } /* (shouldn't happen) */
5844         if (range[0] == -1)             /* If low end of range not specified */
5845           range[0] = 1;                 /* default to 1 */
5846         if (range[1] == -1)             /* If high not specified */
5847           range[1] = a_dim[arrayx];     /* default to size of array */
5848         if ((range[0] < 0) ||           /* Check range */
5849             (range[0] > a_dim[arrayx]) ||
5850             (range[1] < range[0]) ||
5851             (range[1] > a_dim[arrayx])) {
5852             printf("?Bad array range - [%d:%d]\n",range[0],range[1]);
5853             x = -9;
5854             goto xputx;
5855         }
5856         sndarray = ap;                  /* Array pointer */
5857         sndxin = arrayx;                /* Array index */
5858         sndxlo = range[0];              /* Array range */
5859         sndxhi = range[1];
5860         sndxnam[7] = (char)((sndxin == 1) ? 64 : sndxin + ARRAYBASE);
5861         if (!asnambuf[0])
5862           ckstrncpy(asnambuf,sndxnam,CKMAXPATH);
5863         cmarg = "";
5864     }
5865 #endif /* PUTARRAY */
5866 
5867     moving = 0;
5868 
5869     if (pv[SND_ARR].ival < 1) {         /* File selection & disposition... */
5870         if (pv[SND_DEL].ival > 0)       /* /DELETE was specified */
5871           moving = 1;
5872         if (pv[SND_AFT].ival > 0)       /* Copy SEND criteria */
5873           ckstrncpy(sndafter,pv[SND_AFT].sval,19);
5874         if (pv[SND_BEF].ival > 0)
5875           ckstrncpy(sndbefore,pv[SND_BEF].sval,19);
5876         if (pv[SND_NAF].ival > 0)
5877           ckstrncpy(sndnafter,pv[SND_NAF].sval,19);
5878         if (pv[SND_NBE].ival > 0)
5879           ckstrncpy(sndnbefore,pv[SND_NBE].sval,19);
5880         if (pv[SND_EXC].ival > 0)
5881           makelist(pv[SND_EXC].sval,sndexcept,NSNDEXCEPT);
5882         if (pv[SND_SMA].ival > -1)
5883           sndsmaller = pv[SND_SMA].wval;
5884         if (pv[SND_LAR].ival > -1)
5885           sndlarger = pv[SND_LAR].wval;
5886         if (pv[SND_NAM].ival > -1)
5887           x_cnv = pv[SND_NAM].ival;
5888         if (pv[SND_USN].ival > -1)
5889           x_usn = pv[SND_USN].ival;
5890         if (pv[SND_ERR].ival > -1)
5891           puterror = pv[SND_ERR].ival;
5892 
5893 #ifdef DOUPDATE
5894         if (pv[SND_UPD].ival > 0) {
5895             if (x_usn) {
5896                 printf("?Conflicting switches: /UPDATE /UNIQUE\n");
5897                 x = -9;
5898                 goto xputx;
5899             }
5900             putflags |= PUT_UPD;
5901 	    ftp_dates |= 2;
5902         }
5903 #ifdef COMMENT
5904 	/* This works but it's useless, maybe dangerous */
5905         if (pv[SND_DIF].ival > 0) {
5906             if (x_usn) {
5907                 printf("?Conflicting switches: /DATES-DIFFER /UNIQUE\n");
5908                 x = -9;
5909                 goto xputx;
5910             }
5911             putflags |= PUT_DIF;
5912 	    ftp_dates |= 2;
5913         }
5914 #endif /* COMMENT */
5915 #endif /* DOUPDATE */
5916 
5917         if (pv[SND_SIM].ival > 0)
5918           putflags |= PUT_SIM;
5919 
5920         if (pv[SND_PRM].ival > -1) {
5921 #ifdef UNIX
5922             if (x_usn) {
5923                 printf("?Conflicting switches: /PERMISSIONS /UNIQUE\n");
5924                 x = -9;
5925                 goto xputx;
5926             }
5927             x_prm = pv[SND_PRM].ival;
5928 #else /* UNIX */
5929             printf("?/PERMISSIONS switch is not supported\n");
5930 #endif /* UNIX */
5931         }
5932 #ifdef FTP_RESTART
5933         if (pv[SND_RES].ival > 0) {
5934 	    if (!sizeok) {
5935 		printf("?PUT /RESTART can't be used because SIZE disabled.\n");
5936                 x = -9;
5937                 goto xputx;
5938 	    }
5939             if (x_usn || putflags) {
5940                 printf("?Conflicting switches: /RECOVER %s\n",
5941                        x_usn && putflags ? "/UNIQUE /UPDATE" :
5942                        (x_usn ? "/UNIQUE" : "/UPDATE")
5943                        );
5944                 x = -9;
5945                 goto xputx;
5946             }
5947 #ifndef NOCSETS
5948             if (x_xla &&
5949                 (x_csl == FC_UCS2 ||
5950                  x_csl == FC_UTF8 ||
5951                  x_csr == FC_UCS2 ||
5952                  x_csr == FC_UTF8)) {
5953                 printf("?/RECOVER can not be used with Unicode translation\n");
5954                 x = -9;
5955                 goto xputx;
5956             }
5957 #endif /* NOCSETS */
5958             putflags = PUT_RES;
5959         }
5960 #endif /* FTP_RESTART */
5961     }
5962     debug(F101,"ftp PUT restart","",putflags & PUT_RES);
5963     debug(F101,"ftp PUT update","",putflags & PUT_UPD);
5964 
5965 #ifdef PIPESEND
5966     if (pv[SND_FLT].ival > 0) {         /* Have SEND FILTER? */
5967         if (!pv[SND_FLT].sval) {
5968             sndfilter = NULL;
5969         } else {
5970             sndfilter = (char *) malloc((int) strlen(pv[SND_FLT].sval) + 1);
5971             if (sndfilter) strcpy(sndfilter,pv[SND_FLT].sval); /* safe */
5972         }
5973         debug(F110,"ftp put /FILTER", sndfilter, 0);
5974     }
5975     if (sndfilter || pipesend)          /* No /UPDATE or /RESTART */
5976       if (putflags)                     /* with pipes or filters */
5977         putflags = 0;
5978 #endif /* PIPESEND */
5979 
5980     tfc = (CK_OFF_T)0;			/* Initialize stats and counters */
5981     filcnt = 0;
5982     pktnum = 0;
5983     spackets = 0L;
5984 
5985     if (wild)                           /* (is this necessary?) */
5986       cx = FTP_MPU;
5987 
5988     t0 = gmstimer();                    /* Record starting time */
5989 
5990     done = 0;                           /* Loop control */
5991     cancelgroup = 0;
5992 
5993     cdlevel = 0;
5994     cdsimlvl = 0;
5995     while (!done && !cancelgroup) {     /* Loop for all files */
5996                                         /* or until canceled. */
5997 #ifdef FTP_PROXY
5998         /*
5999            If we are using a proxy, we don't use the local file list;
6000            instead we use the list on the remote machine which we want
6001            sent to someone else, and we use remglob() to get the names.
6002            But in that case we shouldn't even be executing this routine;
6003            see ftp_mput().
6004         */
6005 #endif /* FTP_PROXY */
6006 
6007         cancelfile = 0;
6008         x = gnfile();                   /* Get next file from list(s) */
6009 
6010         if (x == 0)                     /* (see gnfile() comments...) */
6011           x = gnferror;
6012         debug(F111,"FTP PUT gnfile",filnam,x);
6013         debug(F111,"FTP PUT binary",filnam,binary);
6014 
6015         switch (x) {
6016           case 1:                       /* File to send */
6017             s2 = asnambuf;
6018 #ifndef NOSPL
6019             if (asnambuf[0]) {          /* As-name */
6020                 int n; char *p;         /* to be evaluated... */
6021                 n = TMPBUFSIZ;
6022                 p = tmpbuf;
6023                 zzstring(asnambuf,&p,&n);
6024                 s2 = tmpbuf;
6025                 debug(F110,"ftp put asname",s2,0);
6026             }
6027 #endif /* NOSPL */
6028             rc = putfile(cx,            /* Function (PUT, APPEND) */
6029                     filnam, s2,         /* Name to send, as-name */
6030                     forcetype, moving,  /* Parameters from switches... */
6031                     snd_move, snd_rename, srv_renam,
6032                     x_cnv, x_usn, xfiletype, x_prm,
6033 #ifndef NOCSETS
6034                     x_csl, (!x_xla ? -1 : x_csr),
6035 #else
6036                     -1, -1,
6037 #endif /* NOCSETS */
6038                     putflags
6039                     );
6040             debug(F111,"ftp put putfile rc",filnam,rc);
6041             debug(F111,"ftp put putfile cancelfile",filnam,cancelfile);
6042             debug(F111,"ftp put putfile cancelgroup",filnam,cancelgroup);
6043             if (rc > -1) {
6044                 good++;
6045                 status = 1;
6046             }
6047             if (cancelfile)
6048               continue;
6049             if (rc < 0) {
6050                 ftp_fai++;
6051                 if (puterror) {
6052                     status = 0;
6053                     printf("?Fatal upload error: %s\n",filnam);
6054                     done++;
6055                 }
6056             }
6057             continue;
6058           case 0:                       /* No more files, done */
6059             done++;
6060             continue;
6061           case -1:
6062             printf("?%s: file not found - \"%s\"\n",
6063                    puterror ? "Fatal" : "Warning",
6064                    filnam
6065                    );
6066             if (puterror) {
6067                 status = 0;
6068                 done++;
6069                 break;
6070             }
6071             continue;
6072           case -2:
6073             if (puterror) {
6074                 printf("?Fatal: file not found - \"%s\"\n", filnam);
6075                 status = 0;
6076                 done++;
6077                 break;
6078             }
6079             continue;                   /* Not readable, keep going */
6080           case -3:
6081             if (puterror) {
6082                 printf("?Fatal: Read access denied - \"%s\"\n", filnam);
6083                 status = 0;
6084                 done++;
6085                 break;
6086             }
6087             printf("?Warning access denied - \"%s\"\n", filnam);
6088             continue;
6089 #ifdef COMMENT
6090           case -4:                      /* Canceled */
6091             done++;
6092             break;
6093 #endif /* COMMENT */
6094           case -5:
6095             printf("?Too many files match\n");
6096             done++;
6097             break;
6098           case -6:
6099             if (good < 1)
6100               printf("?No files selected\n");
6101             done++;
6102             break;
6103           default:
6104             printf("?getnextfile() - unknown failure\n");
6105             done++;
6106         }
6107     }
6108     if (cdlevel > 0) {
6109         while (cdlevel--) {
6110             if (cdsimlvl) {
6111                 cdsimlvl--;
6112             } else if (!doftpcdup())
6113               break;
6114         }
6115     }
6116     if (status > 0) {
6117         if (cancelgroup)
6118           status = 0;
6119         else if (cancelfile && good < 1)
6120           status = 0;
6121     }
6122     success = status;
6123     x = success;
6124 
6125   xputx:
6126     if (x > -1) {
6127 #ifdef GFTIMER
6128         t1 = gmstimer();                /* End time */
6129         sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6130         if (!sec) sec = 0.001;
6131         fptsecs = sec;
6132 #else
6133         sec = (t1 - t0) / 1000;
6134         if (!sec) sec = 1;
6135 #endif /* GFTIMER */
6136         tfcps = (long) (tfc / sec);
6137         tsecs = (int)sec;
6138         lastxfer = W_FTP|W_SEND;
6139         xferstat = success;
6140         if (dpyactive)
6141 	  ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6142     }
6143     for (i = 0; i <= SND_MAX; i++) {    /* Free malloc'd memory */
6144         if (pv[i].sval)
6145           free(pv[i].sval);
6146     }
6147     ftreset();                          /* Undo switch effects */
6148     dpyactive = 0;
6149     return(x);
6150 }
6151 
6152 
6153 static char ** mgetlist = NULL;         /* For MGET */
6154 static int mgetn = 0, mgetx = 0;
6155 static char xtmpbuf[4096];
6156 
6157 /*
6158   c m d l i n g e t
6159 
6160   Get files specified by -g command-line option.
6161   File list is set up in cmlist[] by ckuusy.c; nfils is length of list.
6162 */
6163 int
cmdlinget(stay)6164 cmdlinget(stay) int stay; {
6165     int i, x, rc = 0, done = 0, good = 0, status = 0, append = 0;
6166     int lcs = -1, rcs = -1, xlate = 0;
6167     int first = 1;
6168     int mget = 1;
6169     int nc;
6170     char * s, * s2, * s3;
6171     ULONG t0, t1;                       /* Times for stats */
6172 #ifdef GFTIMER
6173     CKFLOAT sec;
6174 #else
6175     int sec = 0;
6176 #endif /* GFTIMER */
6177 
6178     if (quiet) {                        /* -q really means quiet */
6179         displa = 0;
6180         fdispla = 0;
6181     } else {
6182         displa = 1;
6183         fdispla = XYFD_B;
6184     }
6185     testing = 0;
6186     dpyactive = 0;
6187     out2screen = 0;
6188     what = W_FTP|W_RECV;
6189     mgetmethod = 0;
6190     mgetforced = 0;
6191 
6192     havetype = 0;
6193     havesize = (CK_OFF_T)-1;
6194     makestr(&havemdtm,NULL);
6195 
6196     if (ftp_fnc < 0)
6197       ftp_fnc = fncact;
6198 
6199 #ifndef NOSPL
6200     cmd_quoting = 0;
6201 #endif /* NOSPL */
6202     debug(F101,"ftp cmdlinget nfils","",nfils);
6203 
6204     if (ftp_cnv == CNV_AUTO) {          /* Name conversion is auto */
6205         if (alike) {                    /* If server & client are alike */
6206             nc = 0;                     /* no conversion */
6207         } else {                        /* If they are different */
6208             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6209               nc = -1;                  /* only minimal conversions needed */
6210             else                        /* otherwise */
6211               nc = 1;                   /* full conversion */
6212         }
6213     } else                              /* Not auto - do what user said */
6214       nc = ftp_cnv;
6215 
6216     if (nfils < 1)
6217       doexit(BAD_EXIT,-1);
6218 
6219     t0 = gmstimer();                    /* Starting time for this batch */
6220 
6221 #ifndef NOCSETS
6222     if (xlate) {                        /* SET FTP CHARACTER-SET-TRANSLATION */
6223         lcs = ftp_csl;                  /* Local charset */
6224         if (lcs < 0) lcs = fcharset;
6225         if (lcs < 0) xlate = 0;
6226     }
6227     if (xlate) {                        /* Still ON? */
6228         rcs = ftp_csx;                  /* Remote (Server) charset */
6229         if (rcs < 0) rcs = ftp_csr;
6230         if (rcs < 0) xlate = 0;
6231     }
6232 #endif /* NOCSETS */
6233     /*
6234       If we have only one file and it is a directory, then we ask for a
6235       listing of its contents, rather than retrieving the directory file
6236       itself.  This is what (e.g.) Netscape does.
6237     */
6238     if (nfils == 1) {
6239         if (doftpcwd((char *)cmlist[mgetx],-1)) {
6240             /* If we can CD to it, it must be a directory */
6241             if (recursive) {
6242                 cmlist[mgetx] = "*";
6243             } else {
6244                 status =
6245                   (recvrequest("LIST","-","","wb",0,0,NULL,xlate,lcs,rcs)==0);
6246                 done = 1;
6247             }
6248         }
6249     }
6250 /*
6251   The following is to work around UNIX servers which, when given a command
6252   like "NLST path/blah" (not wild) returns the basename without the path.
6253 */
6254     if (!done && servertype == SYS_UNIX && nfils == 1) {
6255         mget = iswild(cmlist[mgetx]);
6256     }
6257     if (!mget && !done) {               /* Invoked by command-line FTP URL */
6258         if (ftp_deb)
6259           printf("DOING GET...\n");
6260         done++;
6261         cancelfile = 0;                 /* This file not canceled yet */
6262         s = cmlist[mgetx];
6263         rc = 0;                         /* Initial return code */
6264 	fsize = (CK_OFF_T)-1;
6265 	if (sizeok) {
6266 	    x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm); /* Get remote file's size */
6267 	    if (x == REPLY_COMPLETE)
6268 	      fsize = ckatofs(&ftp_reply_str[4]);
6269 	}
6270         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
6271         debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6272 
6273         nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6274         s2 = tmpbuf;
6275 
6276         /* If local file already exists, take collision action */
6277 
6278         if (zchki(s2) > -1) {
6279             switch (ftp_fnc) {
6280               case XYFX_A:              /* Append */
6281                 append = 1;
6282                 break;
6283               case XYFX_R:              /* Rename */
6284               case XYFX_B: {            /* Backup */
6285                   char * p = NULL;
6286                   int x = -1;
6287                   znewn(s2,&p);         /* Make unique name */
6288                   debug(F110,"ftp cmdlinget znewn",p,0);
6289                   if (ftp_fnc == XYFX_B) { /* Backup existing file */
6290                       x = zrename(s2,p);
6291                       debug(F111,"ftp cmdlinget backup zrename",p,x);
6292                   } else {              /* Rename incoming file */
6293                       x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6294                       s2 = tmpbuf;
6295                       debug(F111,"ftp cmdlinget rename incoming",p,x);
6296                   }
6297                   if (x < 0) {
6298                       printf("?Backup/Rename failed\n");
6299                       return(success = 0);
6300                   }
6301                   break;
6302               }
6303               case XYFX_D:              /* Discard */
6304                 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6305                 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6306                 tlog(F100," refused: name","",0);
6307                 debug(F110,"ftp cmdlinget skip name",s2,0);
6308                 goto xclget;
6309 
6310               case XYFX_X:              /* Overwrite */
6311               case XYFX_U:              /* Update (already handled above) */
6312 	      case XYFX_M:		/* ditto */
6313                 break;
6314             }
6315         }
6316         rc = getfile(s,                 /* Remote name */
6317                      s2,                /* Local name */
6318                      0,                 /* Recover/Restart */
6319                      append,            /* Append */
6320                      NULL,              /* Pipename */
6321                      0,                 /* Translate charsets */
6322                      -1,                /* File charset (none) */
6323                      -1                 /* Server charset (none) */
6324                      );
6325         debug(F111,"ftp cmdlinget rc",s,rc);
6326         debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6327         debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6328 
6329         if (rc < 0 && haveurl && s[0] == '/') /* URL failed - try again */
6330             rc = getfile(&s[1],         /* Remote name without leading '/' */
6331                          s2,            /* Local name */
6332                          0,             /* Recover/Restart */
6333                          append,        /* Append */
6334                          NULL,          /* Pipename */
6335                          0,             /* Translate charsets */
6336                          -1,            /* File charset (none) */
6337                          -1             /* Server charset (none) */
6338                          );
6339         if (rc > -1) {
6340             good++;
6341             status = 1;
6342         }
6343         if (cancelfile)
6344           goto xclget;
6345         if (rc < 0) {
6346             ftp_fai++;
6347 #ifdef FTP_TIMEOUT
6348 	    if (ftp_timed_out)
6349 	      status = 0;
6350 #endif	/* FTP_TIMEOUT */
6351             if (geterror) {
6352                 status = 0;
6353                 done++;
6354             }
6355         }
6356     }
6357     if (ftp_deb && !done)
6358       printf("DOING MGET...\n");
6359     while (!done && !cancelgroup) {
6360         cancelfile = 0;                 /* This file not canceled yet */
6361         s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6362         if (!s) s = "";
6363         if (!*s) {
6364             first = 1;
6365             mgetx++;
6366             if (mgetx < nfils)
6367               s = (char *)remote_files(first,(CHAR *)cmlist[mgetx],NULL,0);
6368             else
6369               s = NULL;
6370             debug(F111,"ftp cmdlinget remote_files B",s,0);
6371             if (!s) {
6372                 done = 1;
6373                 break;
6374             }
6375         }
6376         /*
6377           The semantics of NLST are ill-defined.  Suppose we have just sent
6378           NLST /path/[a-z]*.  Most servers send back names like /path/foo,
6379           /path/bar, etc.  But some send back only foo and bar, and subsequent
6380           RETR commands based on the pathless names are not going to work.
6381         */
6382         if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
6383             if ((s3 = ckstrrchr(cmlist[mgetx],'/'))) {
6384                 int len, left = 4096;
6385                 char * tmp = xtmpbuf;
6386                 len = s3 - cmlist[mgetx] + 1;
6387                 ckstrncpy(tmp,cmlist[mgetx],left);
6388                 tmp += len;
6389                 left -= len;
6390                 ckstrncpy(tmp,s,left);
6391                 s = xtmpbuf;
6392 		debug(F111,"ftp cmdlinget remote_files X",s,0);
6393             }
6394         }
6395         first = 0;                      /* Not first any more */
6396 
6397 	debug(F111,"ftp cmdlinget havetype",s,havetype);
6398 	if (havetype > 0 && havetype != FTYP_FILE) { /* Server says not file */
6399 	    debug(F110,"ftp cmdlinget not-a-file",s,0);
6400 	    continue;
6401 	}
6402         rc = 0;                         /* Initial return code */
6403 	if (havesize > (CK_OFF_T)-1) {	/* Already have file size? */
6404 	    fsize = havesize;
6405 	} else {			/* No - must ask server */
6406 	    /*
6407 	      Prior to sending the NLST command we necessarily put the
6408 	      server into ASCII mode.  We must now put it back into the
6409 	      the requested mode so the upcoming SIZE command returns
6410 	      right kind of size; this is especially important for
6411 	      GET /RECOVER; otherwise the server returns the "ASCII" size
6412 	      of the file, rather than its true size.
6413 	    */
6414 	    changetype(ftp_typ,0);	/* Change to requested type */
6415 	    fsize = (CK_OFF_T)-1;
6416 	    if (sizeok) {
6417 		x = ftpcmd("SIZE",s,lcs,rcs,ftp_vbm);
6418 		if (x == REPLY_COMPLETE)
6419 		  fsize = ckatofs(&ftp_reply_str[4]);
6420 	    }
6421 	}
6422         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
6423         debug(F111,"ftp cmdlinget filnam",filnam,fsize);
6424 
6425         nzrtol(s,tmpbuf,nc,0,CKMAXPATH); /* Strip path and maybe convert */
6426         s2 = tmpbuf;
6427 
6428         /* If local file already exists, take collision action */
6429 
6430         if (zchki(s2) > -1) {
6431             switch (ftp_fnc) {
6432               case XYFX_A:              /* Append */
6433                 append = 1;
6434                 break;
6435               case XYFX_R:              /* Rename */
6436               case XYFX_B: {            /* Backup */
6437                   char * p = NULL;
6438                   int x = -1;
6439                   znewn(s2,&p);         /* Make unique name */
6440                   debug(F110,"ftp cmdlinget znewn",p,0);
6441                   if (ftp_fnc == XYFX_B) { /* Backup existing file */
6442                       x = zrename(s2,p);
6443                       debug(F111,"ftp cmdlinget backup zrename",p,x);
6444                   } else {              /* Rename incoming file */
6445                       x = ckstrncpy(tmpbuf,p,CKMAXPATH+1);
6446                       s2 = tmpbuf;
6447                       debug(F111,"ftp cmdlinget rename incoming",p,x);
6448                   }
6449                   if (x < 0) {
6450                       printf("?Backup/Rename failed\n");
6451                       return(success = 0);
6452                   }
6453                   break;
6454               }
6455               case XYFX_D:      /* Discard */
6456                 ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
6457                 ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)SKP_NAM,s);
6458                 tlog(F100," refused: name","",0);
6459                 debug(F110,"ftp cmdlinget skip name",s2,0);
6460                 continue;
6461               case XYFX_X:              /* Overwrite */
6462               case XYFX_U:              /* Update (already handled above) */
6463               case XYFX_M:              /* ditto */
6464                 break;
6465             }
6466         }
6467                                         /* ^^^ ADD CHARSET STUFF HERE ^^^ */
6468         rc = getfile(s,                 /* Remote name */
6469                      s2,                /* Local name */
6470                      0,                 /* Recover/Restart */
6471                      append,            /* Append */
6472                      NULL,              /* Pipename */
6473                      0,                 /* Translate charsets */
6474                      -1,                /* File charset (none) */
6475                      -1                 /* Server charset (none) */
6476                      );
6477         debug(F111,"ftp cmdlinget rc",s,rc);
6478         debug(F111,"ftp cmdlinget cancelfile",s,cancelfile);
6479         debug(F111,"ftp cmdlinget cancelgroup",s,cancelgroup);
6480 
6481         if (rc > -1) {
6482             good++;
6483             status = 1;
6484         }
6485         if (cancelfile)
6486           continue;
6487         if (rc < 0) {
6488             ftp_fai++;
6489 #ifdef FTP_TIMEOUT
6490 	    if (ftp_timed_out)
6491 	      status = 0;
6492 #endif	/* FTP_TIMEOUT */
6493             if (geterror) {
6494                 status = 0;
6495                 done++;
6496             }
6497         }
6498     }
6499 
6500   xclget:
6501     if (cancelgroup)
6502       mlsreset();
6503     if (status > 0) {
6504         if (cancelgroup)
6505           status = 0;
6506         else if (cancelfile && good < 1)
6507           status = 0;
6508     }
6509     success = status;
6510 
6511 #ifdef GFTIMER
6512     t1 = gmstimer();                    /* End time */
6513     sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
6514     if (!sec) sec = 0.001;
6515     fptsecs = sec;
6516 #else
6517     sec = (t1 - t0) / 1000;
6518     if (!sec) sec = 1;
6519 #endif /* GFTIMER */
6520 
6521     tfcps = (long) (tfc / sec);
6522     tsecs = (int)sec;
6523     lastxfer = W_FTP|W_RECV;
6524     xferstat = success;
6525     if (dpyactive)
6526       ftscreen(status > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
6527     if (!stay)
6528       doexit(success ? GOOD_EXIT : BAD_EXIT, -1);
6529     return(success);
6530 }
6531 
6532 /*  d o f t p g e t  --  Parse and execute GET, MGET, MDELETE, ...  */
6533 
6534 /*
6535   Note: if we wanted to implement /AFTER:, /BEFORE:, etc, we could use
6536   zstrdat() to convert to UTC-based time_t.  But it doesn't make sense from
6537   the user-interface perspective, since the server's directory listings show
6538   its own local times and since we don't know what timezone it's in, there's
6539   no way to reconcile our local times with the server's.
6540 */
6541 int
doftpget(cx,who)6542 doftpget(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
6543     struct FDB fl, sw, cm;
6544     int i, n, rc, getval = 0, mget = 0, done = 0, pipesave = 0;
6545     int x_cnv = 0, x_prm = 0, restart = 0, status = 0, good = 0;
6546     int x_fnc = 0, first = 0, skipthis = 0, append = 0, selected = 0;
6547     int renaming = 0, mdel = 0, listfile = 0, updating = 0, getone = 0;
6548     int moving = 0, deleting = 0, toscreen = 0, haspath = 0;
6549     int gotsize = 0;
6550     int matchdot = 0;
6551     CK_OFF_T getlarger = (CK_OFF_T)-1;
6552     CK_OFF_T getsmaller = (CK_OFF_T)-1;
6553     char * msg, * s, * s2, * nam, * pipename = NULL, * pn = NULL;
6554     char * src = "", * local = "";
6555     char * pat = "";
6556 
6557     int x_csl = -1, x_csr = -1;         /* Local and remote charsets */
6558     int x_xla = 0;
6559     char c;                             /* Worker char */
6560     ULONG t0 = 0L, t1;                  /* Times for stats */
6561 #ifdef GFTIMER
6562     CKFLOAT sec;
6563 #else
6564     int sec = 0;
6565 #endif /* GFTIMER */
6566 
6567     struct stringint pv[SND_MAX+1];    /* Temporary array for switch values */
6568 
6569     success = 0;                        /* Assume failure */
6570     forcetype = 0;                      /* No /TEXT or /BINARY given yet */
6571     restart = 0;                        /* No restart yet */
6572     out2screen = 0;			/* No TO-SCREEN switch given yet */
6573     mgetmethod = 0;			/* No NLST or MLSD switch yet */
6574     mgetforced = 0;
6575 
6576     g_displa = fdispla;
6577     if (ftp_dis > -1)
6578       fdispla = ftp_dis;
6579 
6580     x_cnv = ftp_cnv;                    /* Filename conversion */
6581     if (x_cnv == CNV_AUTO) {		/* Name conversion is auto */
6582         if (alike) {                    /* If server & client are alike */
6583             x_cnv = 0;			/* no conversion */
6584         } else {                        /* If they are different */
6585             if (servertype == SYS_UNIX || servertype == SYS_WIN32)
6586               x_cnv = -1;		/* only minimal conversions needed */
6587             else                        /* otherwise */
6588               x_cnv = 1;		/* full conversion */
6589         }
6590     } else                              /* Not auto - do what user said */
6591       x_cnv = ftp_cnv;
6592 
6593     x_prm = ftp_prm;                    /* Permissions */
6594     if (x_prm == SET_AUTO)              /* Permissions AUTO */
6595       x_prm = alike;
6596 
6597 #ifndef NOCSETS
6598     x_csr = ftp_csr;                    /* Inherit global server charset */
6599     x_csl = ftp_csl;                    /* Inherit global local charset */
6600     if (x_csl < 0)                      /* If none, use current */
6601       x_csl = fcharset;                 /* file character-set. */
6602     x_xla = ftp_xla;                    /* Translation On/Off */
6603 #endif /* NOCSETS */
6604 
6605     geterror = ftp_err;                 /* Inherit global error action. */
6606     asnambuf[0] = NUL;                  /* No as-name yet. */
6607     pipesave = pipesend;
6608     pipesend = 0;
6609 
6610     havetype = 0;
6611     havesize = (CK_OFF_T)-1;
6612     makestr(&havemdtm,NULL);
6613 
6614     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
6615         ftp_typ = g_ftp_typ;
6616         /* g_ftp_typ = -1; */
6617     }
6618     for (i = 0; i <= SND_MAX; i++) {    /* Initialize switch values */
6619         pv[i].sval = NULL;              /* to null pointers */
6620         pv[i].ival = -1;                /* and -1 int values */
6621         pv[i].wval = (CK_OFF_T)-1;	/* and -1 wide values */
6622     }
6623     zclose(ZMFILE);                     /* In case it was left open */
6624 
6625     x_fnc = ftp_fnc > -1 ? ftp_fnc : fncact; /* Filename collision action */
6626 
6627     if (fp_nml) {                       /* Reset /NAMELIST */
6628         if (fp_nml != stdout)
6629           fclose(fp_nml);
6630         fp_nml = NULL;
6631     }
6632     makestr(&ftp_nml,NULL);
6633 
6634     /* Initialize list of remote filespecs */
6635 
6636     if (!mgetlist) {
6637         mgetlist = (char **)malloc(MGETMAX * sizeof(char *));
6638         if (!mgetlist) {
6639             printf("?Memory allocation failure - MGET list\n");
6640             return(-9);
6641         }
6642         for (i = 0; i < MGETMAX; i++)
6643           mgetlist[i] = NULL;
6644     }
6645     mgetn = 0;                          /* Number of mget arguments */
6646     mgetx = 0;                          /* Current arg */
6647 
6648     if (who == 0) {                     /* Called with unprefixed command */
6649         if (cx == XXGET || cx == XXREGET || cx == XXRETR)
6650           getone++;
6651         switch (cx) {
6652           case XXREGET: pv[SND_RES].ival = 1; break;
6653           case XXRETR:  pv[SND_DEL].ival = 1; break;
6654           case XXGET:
6655           case XXMGET:  mget++; break;
6656         }
6657     } else {                            /* FTP command */
6658         if (cx == FTP_GET || cx == FTP_RGE)
6659           getone++;
6660         switch (cx) {
6661           case FTP_DEL:                 /* (fall thru on purpose) */
6662           case FTP_MDE: mdel++;         /* (ditto) */
6663           case FTP_GET:                 /* (ditto) */
6664           case FTP_MGE: mget++; break;
6665           case FTP_RGE: pv[SND_RES].ival = 1; break;
6666         }
6667     }
6668     cmfdbi(&sw,                         /* First FDB - command switches */
6669            _CMKEY,                      /* fcode */
6670            "Remote filename;\n or switch", /* hlpmsg */
6671            "",                          /* default */
6672            "",                          /* addtl string data */
6673            mdel ? ndelswi : ngetswi,    /* addtl numeric data 1: tbl size */
6674            4,                           /* addtl numeric data 2: 4 = cmswi */
6675            xxstring,                    /* Processing function */
6676            mdel ? delswi : getswi,      /* Keyword table */
6677            &fl                          /* Pointer to next FDB */
6678            );
6679     cmfdbi(&fl,                         /* 2nd FDB - remote filename */
6680            _CMFLD,                      /* fcode */
6681            "",                          /* hlpmsg */
6682            "",                          /* default */
6683            "",                          /* addtl string data */
6684            0,                           /* addtl numeric data 1 */
6685            0,                           /* addtl numeric data 2 */
6686            xxstring,
6687            NULL,
6688            &cm
6689            );
6690     cmfdbi(&cm,                         /* 3rd FDB - Confirmation */
6691            _CMCFM,                      /* fcode */
6692            "",                          /* hlpmsg */
6693            "",                          /* default */
6694            "",                          /* addtl string data */
6695            0,                           /* addtl numeric data 1 */
6696            0,                           /* addtl numeric data 2 */
6697            NULL,
6698            NULL,
6699            NULL
6700            );
6701 
6702     while (1) {                         /* Parse 0 or more switches */
6703         x = cmfdb(&sw);                 /* Parse something */
6704         debug(F101,"ftp get cmfdb","",x);
6705         if (x < 0)                      /* Error */
6706           goto xgetx;                   /* or reparse needed */
6707         if (cmresult.fcode != _CMKEY)   /* Break out of loop if not a switch */
6708           break;
6709         c = cmgbrk();                   /* Get break character */
6710         getval = (c == ':' || c == '='); /* to see how they ended the switch */
6711         if (getval && !(cmresult.kflags & CM_ARG)) {
6712             printf("?This switch does not take arguments\n");
6713             x = -9;
6714             goto xgetx;
6715         }
6716         n = cmresult.nresult;           /* Numeric result = switch value */
6717         debug(F101,"ftp get switch","",n);
6718 
6719         if (!getval && (cmgkwflgs() & CM_ARG)) {
6720             printf("?This switch requires an argument\n");
6721             x = -9;
6722             goto xgetx;
6723         }
6724         switch (n) {                    /* Process the switch */
6725           case SND_ASN:                 /* /AS-NAME: */
6726             debug(F101,"ftp get /as-name getval","",getval);
6727             if (!getval) break;
6728             if ((x = cmfld("Name to store it under","",&s,NULL)) < 0) {
6729                 if (x == -3) {
6730                     printf("?name required\n");
6731                     x = -9;
6732                 }
6733                 goto xgetx;
6734             }
6735             s = brstrip(s);
6736             if (!*s) s = NULL;
6737             makestr(&(pv[n].sval),s);
6738             pv[n].ival = 1;
6739             break;
6740 
6741           case SND_BIN:                 /* /BINARY */
6742           case SND_TXT:                 /* /TEXT or /ASCII */
6743           case SND_TEN:                 /* /TENEX */
6744             pv[SND_BIN].ival = 0;
6745             pv[SND_TXT].ival = 0;
6746             pv[SND_TEN].ival = 0;
6747             pv[n].ival = 1;
6748             break;
6749 
6750 #ifdef PUTPIPE
6751           case SND_CMD:                 /* These take no args */
6752             if (nopush) {
6753                 printf("?Sorry, system command access is disabled\n");
6754                 x = -9;
6755                 goto xgetx;
6756             }
6757 #ifdef PIPESEND
6758             else if (rcvfilter) {
6759                 printf("?Sorry, no PUT /COMMAND when SEND FILTER selected\n");
6760                 x = -9;
6761                 goto xgetx;
6762             }
6763 #endif /* PIPESEND */
6764             sw.hlpmsg = "Command, or switch"; /* Change help message */
6765             pv[n].ival = 1;             /* Just set the flag */
6766             pv[SND_ARR].ival = 0;
6767             break;
6768 #endif /* PUTPIPE */
6769 
6770           case SND_SHH:                 /* /QUIET */
6771           case SND_RES:                 /* /RECOVER (reget) */
6772           case SND_NOB:                 /* /NOBACKUPFILES */
6773           case SND_DEL:                 /* /DELETE */
6774           case SND_UPD:                 /* /UPDATE */
6775           case SND_USN:                 /* /UNIQUE */
6776           case SND_NOD:                 /* /NODOTFILES */
6777           case SND_REC:                 /* /RECOVER */
6778           case SND_MAI:                 /* /TO-SCREEN */
6779             pv[n].ival = 1;             /* Just set the flag */
6780             break;
6781 
6782           case SND_DIF:                 /* /DATES-DIFFER */
6783 	    pv[SND_COL].ival = XYFX_M;	/* Now it's a collision option */
6784 	    pv[n].ival = 1;
6785 	    break;
6786 
6787           case SND_COL:                 /* /COLLISION: */
6788             if ((x = cmkey(ftpcolxtab,nftpcolx,"","",xxstring)) < 0)
6789               goto xgetx;
6790 	    if (x == XYFX_M)
6791 	      pv[SND_DIF].ival = 1;	/* (phase this out) */
6792 	    pv[n].ival = x;		/* this should be sufficient */
6793             break;
6794 
6795           case SND_ERR:                 /* /ERROR-ACTION */
6796             if ((x = cmkey(qorp,2,"","",xxstring)) < 0)
6797               goto xgetx;
6798             pv[n].ival = x;
6799             break;
6800 
6801           case SND_EXC:                 /* Exception list */
6802             if (!getval) break;
6803             if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
6804                 if (x == -3) {
6805                     printf("?Pattern required\n");
6806                     x = -9;
6807                 }
6808                 goto xgetx;
6809             }
6810             if (s) if (!*s) s = NULL;
6811             makestr(&(pv[n].sval),s);
6812             if (pv[n].sval)
6813               pv[n].ival = 1;
6814             break;
6815 
6816 #ifdef PIPESEND
6817           case SND_FLT:
6818             debug(F101,"ftp get /filter getval","",getval);
6819             if (!getval) break;
6820             if ((x = cmfld("Filter program to send through","",&s,NULL)) < 0) {
6821                 if (x == -3)
6822                   s = "";
6823                 else
6824                   goto xgetx;
6825             }
6826             s = brstrip(s);
6827             if (pv[SND_MAI].ival < 1) {
6828                 y = strlen(s);
6829                 /* Make sure they included "\v(...)" */
6830                 for (x = 0; x < y; x++) {
6831                     if (s[x] != '\\') continue;
6832                     if (s[x+1] == 'v') break;
6833                 }
6834                 if (x == y) {
6835                     printf(
6836                 "?Filter must contain a replacement variable for filename.\n"
6837                            );
6838                     x = -9;
6839                     goto xgetx;
6840                 }
6841             }
6842             if (*s) {
6843                 pv[n].ival = 1;
6844                 makestr(&(pv[n].sval),s);
6845             } else {
6846                 pv[n].ival = 0;
6847                 makestr(&(pv[n].sval),NULL);
6848             }
6849             break;
6850 #endif /* PIPESEND */
6851 
6852           case SND_NAM:
6853             if (!getval) break;
6854             if ((x = cmkey(fntab,nfntab,"","automatic",xxstring)) < 0)
6855               goto xgetx;
6856             debug(F101,"ftp get /filenames","",x);
6857             pv[n].ival = x;
6858             break;
6859 
6860           case SND_SMA:                 /* Smaller / larger than */
6861           case SND_LAR: {
6862 	      CK_OFF_T y;
6863 	      if (!getval) break;
6864 	      if ((x = cmnumw("Size in bytes","0",10,&y,xxstring)) < 0)
6865 		goto xgetx;
6866 	      pv[n].wval = y;
6867 	      break;
6868 	  }
6869           case SND_FIL:                 /* Name of file containing filnames */
6870             if (!getval) break;
6871             if ((x = cmifi("Name of file containing list of filenames",
6872                                "",&s,&y,xxstring)) < 0) {
6873                 if (x == -3) {
6874                     printf("?Filename required\n");
6875                     x = -9;
6876                 }
6877                 goto xgetx;
6878             } else if (y && iswild(s)) {
6879                 printf("?Wildcards not allowed BBB\n");
6880                 x = -9;
6881                 goto xgetx;
6882             }
6883             if (s) if (!*s) s = NULL;
6884             makestr(&(pv[n].sval),s);
6885             if (pv[n].sval)
6886               pv[n].ival = 1;
6887             break;
6888 
6889           case SND_MOV:                 /* MOVE after */
6890           case SND_REN:                 /* RENAME after */
6891           case SND_SRN: {               /* SERVER-RENAME */
6892               char * m = "";
6893               switch (n) {
6894                 case SND_MOV:
6895                   m =
6896                    "Device and/or directory for incoming file after reception";
6897                   break;
6898                 case SND_REN:
6899                   m = "New name for incoming file after reception";
6900                   break;
6901                 case SND_SRN:
6902                   m = "New name for source file on server after reception";
6903                   break;
6904               }
6905               if (!getval) break;
6906               if ((x = cmfld(m, "", &s, n == SND_MOV ? xxstring : NULL)) < 0) {
6907                   if (x == -3) {
6908                       printf("%s\n", n == SND_MOV ?
6909                              "?Destination required" :
6910                              "?New name required"
6911                              );
6912                       x = -9;
6913                   }
6914                   goto xgetx;
6915               }
6916               makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6917               pv[n].ival = (pv[n].sval) ? 1 : 0;
6918               break;
6919           }
6920 #ifndef NOCSETS
6921           case SND_CSL:                 /* Local character set */
6922           case SND_CSR:                 /* Remote (server) charset */
6923             if ((x = cmkey(fcstab,nfilc,"","",xxstring)) < 0)
6924               return((x == -3) ? -2 : x);
6925             if (n == SND_CSL)
6926               x_csl = x;
6927             else
6928               x_csr = x;
6929             x_xla = 1;                  /* Overrides global OFF setting */
6930             break;
6931 
6932           case SND_XPA:                 /* Transparent */
6933             x_xla =  0;
6934             x_csr = -1;
6935             x_csl = -1;
6936             break;
6937 #endif /* NOCSETS */
6938 
6939           case SND_NML:
6940             if ((x = cmofi("Local filename","-",&s,xxstring)) < 0)
6941               goto xgetx;
6942             makestr(&ftp_nml,s);
6943             break;
6944 
6945 	  case SND_PAT:			/* /PATTERN: */
6946 	    if (!getval) break;
6947 	    if ((x = cmfld("Pattern","*", &s, xxstring)) < 0)
6948 	      goto xgetx;
6949 	    makestr(&(pv[n].sval),*s ? brstrip(s) : NULL);
6950 	    pv[n].ival = (pv[n].sval) ? 1 : 0;
6951 	    break;
6952 
6953 	  case SND_NLS:			/* /NLST */
6954             pv[n].ival = 1;		/* Use NLST */
6955 	    pv[SND_MLS].ival = 0;	/* Don't use MLSD */
6956 	    break;
6957 
6958 	  case SND_MLS:			/* /MLSD */
6959             pv[n].ival = 1;		/* Use MLSD */
6960 	    pv[SND_NLS].ival = 0;	/* Don't use NLST */
6961 	    break;
6962 
6963           default:                      /* /AFTER, /PERMISSIONS, etc... */
6964             printf("?Sorry, \"%s\" works only with [M]PUT\n",atmbuf);
6965             x = -9;
6966             goto xgetx;
6967         }
6968     }
6969     line[0] = NUL;
6970     cmarg = line;
6971     cmarg2 = asnambuf;
6972     s = line;
6973 /*
6974   For GET, we want to parse an optional as-name, like with PUT.
6975   For MGET, we must parse a list of names, and then send NLST or MLSD
6976   commands for each name separately.
6977 */
6978     switch (cmresult.fcode) {           /* How did we get out of switch loop */
6979       case _CMFLD:                      /* Field */
6980         if (!getone) {
6981             s = brstrip(cmresult.sresult);
6982             makestr(&(mgetlist[mgetn++]),s);
6983             while ((x = cmfld("Remote filename","",&s,xxstring)) != -3) {
6984                 if (x < 0)
6985                   goto xgetx;
6986                 makestr(&(mgetlist[mgetn++]),brstrip(s));
6987                 if (mgetn >= MGETMAX) {
6988                     printf("?Too many items in MGET list\n");
6989                     goto xgetx;
6990                 }
6991             }
6992             if ((x = cmcfm()) < 0)
6993               goto xgetx;
6994         } else {
6995             s = brstrip(cmresult.sresult);
6996             ckstrncpy(line,s,LINBUFSIZ);
6997             if ((x = cmfld("Name to store it under","",&s,xxstring)) < 0)
6998               if (x != -3)
6999                 goto xgetx;
7000             s = brstrip(s);
7001             ckstrncpy(asnambuf,s,CKMAXPATH+1);
7002             if ((x = cmcfm()) < 0)
7003               goto xgetx;
7004         }
7005         break;
7006       case _CMCFM:                      /* Confirmation */
7007         break;
7008       default:
7009         printf("?Unexpected function code: %d\n",cmresult.fcode);
7010         x = -9;
7011         goto xgetx;
7012     }
7013     if (pv[SND_REC].ival > 0)           /* /RECURSIVE */
7014       recursive = 2;
7015 
7016     if (pv[SND_BIN].ival > 0) {         /* /BINARY really means binary... */
7017         forcetype = 1;                  /* So skip the name-pattern match */
7018         ftp_typ = XYFT_B;               /* Set binary */
7019     } else if (pv[SND_TXT].ival > 0) {  /* Similarly for /TEXT... */
7020         forcetype = 1;
7021         ftp_typ = XYFT_T;
7022     } else if (pv[SND_TEN].ival > 0) {  /* and /TENEX*/
7023         forcetype = 1;
7024         ftp_typ = FTT_TEN;
7025     } else if (ftp_cmdlin && ftp_xfermode == XMODE_M) {
7026         forcetype = 1;
7027         ftp_typ = binary;
7028         g_ftp_typ = binary;
7029     }
7030     if (pv[SND_ASN].ival > 0 && pv[SND_ASN].sval && !asnambuf[0]) {
7031         char * p;
7032         p = brstrip(pv[SND_ASN].sval);  /* As-name */
7033         ckstrncpy(asnambuf,p,CKMAXPATH+1);
7034     }
7035     debug(F110,"ftp get asnambuf",asnambuf,0);
7036 
7037 #ifdef PIPESEND
7038     if (pv[SND_CMD].ival > 0) {         /* /COMMAND - strip any braces */
7039         char * p;
7040         p = asnambuf;
7041         debug(F110,"GET /COMMAND before stripping",p,0);
7042         p = brstrip(p);
7043         debug(F110,"GET /COMMAND after stripping",p,0);
7044         if (!*p) {
7045             printf("?Sorry, a command to write to is required\n");
7046             x = -9;
7047             goto xgetx;
7048         }
7049         pipename = p;
7050         pipesend = 1;
7051     }
7052 #endif /* PIPESEND */
7053 
7054 /* Set up /MOVE and /RENAME */
7055 
7056 #ifdef COMMENT
7057     /* Conflict exists only for PUT - removed 13 Mar 2006 - fdc */
7058     if (pv[SND_DEL].ival > 0 &&
7059         (pv[SND_MOV].ival > 0 || pv[SND_REN].ival > 0)) {
7060         printf("?Sorry, /DELETE conflicts with /MOVE or /RENAME\n");
7061         x = -9;
7062         goto xgetx;
7063     }
7064 #endif	/* COMMENT */
7065 #ifdef CK_TMPDIR
7066     if (pv[SND_MOV].ival > 0 && pv[SND_MOV].sval) {
7067         int len;
7068         char * p = pv[SND_MOV].sval;
7069         len = strlen(p);
7070         if (!isdir(p)) {                /* Check directory */
7071 #ifdef CK_MKDIR
7072             char * s = NULL;
7073             s = (char *)malloc(len + 4);
7074             if (s) {
7075                 strcpy(s,p);            /* safe */
7076 #ifdef datageneral
7077                 if (s[len-1] != ':') { s[len++] = ':'; s[len] = NUL; }
7078 #else
7079                 if (s[len-1] != '/') { s[len++] = '/'; s[len] = NUL; }
7080 #endif /* datageneral */
7081                 s[len++] = 'X';
7082                 s[len] = NUL;
7083 #ifdef NOMKDIR
7084                 x = -1;
7085 #else
7086                 x = zmkdir(s);
7087 #endif /* NOMKDIR */
7088                 free(s);
7089                 if (x < 0) {
7090                     printf("?Can't create \"%s\"\n",p);
7091                     x = -9;
7092                     goto xgetx;
7093                 }
7094             }
7095 #else
7096             printf("?Directory \"%s\" not found\n",p);
7097             x = -9;
7098             goto xgetx;
7099 #endif /* CK_MKDIR */
7100         }
7101         makestr(&rcv_move,p);
7102         moving = 1;
7103     }
7104 #endif /* CK_TMPDIR */
7105 
7106     if (pv[SND_REN].ival > 0) {         /* /RENAME */
7107         char * p = pv[SND_REN].sval;
7108         if (!p) p = "";
7109         if (!*p) {
7110             printf("?New name required for /RENAME\n");
7111             x = -9;
7112             goto xgetx;
7113         }
7114         p = brstrip(p);
7115 #ifndef NOSPL
7116     /* If name given is wild, rename string must contain variables */
7117         if (mget && !getone) {
7118             char * s = tmpbuf;
7119             x = TMPBUFSIZ;
7120             zzstring(p,&s,&x);
7121             if (!strcmp(tmpbuf,p)) {
7122                 printf(
7123     "?/RENAME for file group must contain variables such as \\v(filename)\n"
7124                        );
7125                 x = -9;
7126                 goto xgetx;
7127             }
7128         }
7129 #endif /* NOSPL */
7130         renaming = 1;
7131         makestr(&rcv_rename,p);
7132         debug(F110,"FTP rcv_rename",rcv_rename,0);
7133     }
7134     if (!cmarg[0] && mgetn == 0 && getone && pv[SND_FIL].ival < 1) {
7135         printf("?Filename required but not given\n");
7136         x = -9;
7137         goto xgetx;
7138     } else if ((cmarg[0] || mgetn > 0) && pv[SND_FIL].ival > 0) {
7139         printf("?You can't give both /LISTFILE and a remote filename\n");
7140         x = -9;
7141         goto xgetx;
7142     }
7143     CHECKCONN();                        /* Check connection */
7144 
7145     if (pv[SND_COL].ival > -1)
7146       x_fnc = pv[SND_COL].ival;
7147 
7148 #ifndef NOSPL
7149     /* If as-name given for MGET, as-name must contain variables */
7150     if (mget && !getone && asnambuf[0] && x_fnc != XYFX_A) {
7151         char * s = tmpbuf;
7152         x = TMPBUFSIZ;
7153         zzstring(asnambuf,&s,&x);
7154         if (!strcmp(tmpbuf,asnambuf)) {
7155             printf(
7156     "?As-name for MGET must contain variables such as \\v(filename)\n"
7157                    );
7158             x = -9;
7159             goto xgetx;
7160         }
7161     }
7162 #endif /* NOSPL */
7163 
7164 /* doget: */
7165 
7166     if (pv[SND_SHH].ival > 0 || ftp_nml) { /* GET /QUIET... */
7167         fdispla = 0;
7168     } else {
7169         displa = 1;
7170         if (mdel || ftp_deb)
7171 	  fdispla = XYFD_B;
7172     }
7173     deleting = 0;
7174     if (pv[SND_DEL].ival > 0)           /* /DELETE was specified */
7175       deleting = 1;
7176     if (pv[SND_EXC].ival > 0)
7177       makelist(pv[SND_EXC].sval,rcvexcept,NSNDEXCEPT);
7178     if (pv[SND_SMA].wval > -1)
7179       getsmaller = pv[SND_SMA].wval;
7180     if (pv[SND_LAR].wval > -1)
7181       getlarger = pv[SND_LAR].wval;
7182     if (pv[SND_NAM].ival > -1)
7183       x_cnv = pv[SND_NAM].ival;
7184     if (pv[SND_ERR].ival > -1)
7185       geterror = pv[SND_ERR].ival;
7186     if (pv[SND_MAI].ival > -1)
7187       toscreen = 1;
7188 
7189     if (pv[SND_NLS].ival > 0) {		/* Force NLST or MLSD? */
7190 	mgetmethod = SND_NLS;
7191 	mgetforced = 1;
7192     } else if (pv[SND_MLS].ival > 0) {
7193 	mgetmethod = SND_MLS;
7194 	mgetforced = 1;
7195     }
7196 
7197 #ifdef FTP_RESTART
7198     if (pv[SND_RES].ival > 0) {
7199         if (!ftp_typ) {
7200             printf("?Sorry, GET /RECOVER requires binary mode\n");
7201             x = -9;
7202             goto xgetx;
7203 #ifdef COMMENT
7204         /* Not true - the fact that the initial REST fails does not mean */
7205         /* it will fail here.  */
7206         } else if (!okrestart) {
7207             printf("WARNING: Server might not support restart...\n");
7208 #endif /* COMMENT */
7209         }
7210         restart = 1;
7211     }
7212 #endif /* FTP_RESTART */
7213 
7214 #ifdef PIPESEND
7215     if (pv[SND_FLT].ival > 0) {         /* Have SEND FILTER? */
7216         if (pipesend) {
7217             printf("?Switch conflict: /FILTER and /COMMAND\n");
7218             x = -9;
7219             goto xgetx;
7220         }
7221         makestr(&rcvfilter,pv[SND_FLT].sval);
7222         debug(F110,"ftp get /FILTER", rcvfilter, 0);
7223     }
7224     if (rcvfilter || pipesend) {        /* /RESTART */
7225 #ifdef FTP_RESTART
7226         if (restart) {                  /* with pipes or filters */
7227             printf("?Switch conflict: /FILTER or /COMMAND and /RECOVER\n");
7228             x = -9;
7229             goto xgetx;
7230         }
7231 #endif /* FTP_RESTART */
7232         if (pv[SND_UPD].ival > 0 || x_fnc == XYFX_M || x_fnc == XYFX_U) {
7233             printf(
7234 		"?Switch conflict: /FILTER or /COMMAND and Date Checking\n");
7235             x = -9;
7236             goto xgetx;
7237         }
7238     }
7239 #endif /* PIPESEND */
7240 
7241     tfc = (CK_OFF_T)0;			/* Initialize stats and counters */
7242     filcnt = 0;
7243     pktnum = 0;
7244     rpackets = 0L;
7245 
7246     if (pv[SND_FIL].ival > 0) {
7247         if (zopeni(ZMFILE,pv[SND_FIL].sval) < 1) {
7248             debug(F111,"ftp get can't open listfile",pv[SND_FIL].sval,errno);
7249             printf("?Failure to open listfile - \"%s\"\n",pv[SND_FIL].sval);
7250             x = -9;
7251             goto xgetx;
7252         }
7253         if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) { /* Read a line */
7254             zclose(ZMFILE);                       /* Failed */
7255             debug(F110,"ftp get listfile EOF",pv[SND_FIL].sval,0);
7256             printf("?Empty listfile - \"%s\"\n",pv[SND_FIL].sval);
7257             x = -9;
7258             goto xgetx;
7259         }
7260         listfile = 1;
7261         debug(F110,"ftp get listfile first",tmpbuf,0);
7262         makestr(&(mgetlist[0]),tmpbuf);
7263     }
7264     t0 = gmstimer();                    /* Record starting time */
7265 
7266     updating = 0;			/* Checking dates? */
7267     if (pv[SND_UPD].ival > 0 || (!mdel && x_fnc == XYFX_U))
7268       updating = 1;
7269     if (pv[SND_DIF].ival > 0 || x_fnc == XYFX_M)
7270       updating = 2;
7271     if (updating)			/* These switches force FTP DATES ON */
7272       ftp_dates |= 2;
7273 
7274     what = mdel ? W_FTP|W_FT_DELE : W_RECV|W_FTP; /* What we're doing */
7275 
7276     cancelgroup = 0;                    /* Group not canceled yet */
7277     if (!(ftp_xfermode == XMODE_A && patterns && get_auto && !forcetype))
7278       changetype(ftp_typ,0);		/* Change to requested type */
7279     binary = ftp_typ;                   /* For file-transfer display */
7280     first = 1;                          /* For MGET list */
7281     done = 0;                           /* Loop control */
7282 
7283 #ifdef CK_TMPDIR
7284     if (dldir && !f_tmpdir) {           /* If they have a download directory */
7285         if ((s = zgtdir())) {           /* Get current directory */
7286             if (zchdir(dldir)) {        /* Change to download directory */
7287                 ckstrncpy(savdir,s,TMPDIRLEN);
7288                 f_tmpdir = 1;           /* Remember that we did this */
7289             }
7290         }
7291     }
7292 #endif /* CK_TMPDIR */
7293 
7294     if (ftp_nml) {                      /* /NAMELIST */
7295         debug(F110,"ftp GET ftp_nml",ftp_nml,0);
7296         if (ftp_nml[0] == '-' && ftp_nml[1] == 0)
7297           fp_nml = stdout;
7298         else
7299           fp_nml = fopen(ftp_nml, "wb");
7300         if (!fp_nml) {
7301             printf("?%s: %s\n",ftp_nml,ck_errstr());
7302             goto xgetx;
7303         }
7304     }
7305     while (!done && !cancelgroup) {     /* Loop for all files */
7306                                         /* or until canceled. */
7307 #ifdef FTP_PROXY
7308         /* do something here if proxy */
7309 #endif /* FTP_PROXY */
7310 
7311         rs_len = (CK_OFF_T)0;		/* REGET position */
7312         cancelfile = 0;                 /* This file not canceled yet */
7313         haspath = 0;                    /* Recalculate this each time thru */
7314 
7315         if (getone) {                   /* GET */
7316             char * p;
7317             s = line;
7318             src = line;                 /* Server name */
7319             done = 1;
7320             debug(F111,"ftp get file",s,0);
7321         } else if (mget) {              /* MGET */
7322             src = mgetlist[mgetx];
7323             debug(F111,"ftp mget remote_files A",src,first);
7324             s = (char *)remote_files(first,
7325 				     (CHAR *)mgetlist[mgetx],
7326 				     (CHAR *)pv[SND_PAT].sval,
7327 				     0
7328 				     );
7329             debug(F110,"ftp mget remote_files B",s,0);
7330             if (!s) s = "";
7331             if (!*s) {
7332                 first = 1;
7333                 if (listfile) {		/* Names from listfile */
7334                   again:
7335                     tmpbuf[0] = NUL;
7336                     while (!tmpbuf[0]) {
7337                         if (zsinl(ZMFILE,tmpbuf,CKMAXPATH) < 0) {
7338                             zclose(ZMFILE);
7339                             debug(F110,"ftp get listfile EOF",
7340                                   pv[SND_FIL].sval,0);
7341                             makestr(&(mgetlist[0]),NULL);
7342                             s = NULL;
7343                             done = 1;
7344                             break;
7345                         }
7346                     }
7347                     if (done)
7348                       continue;
7349 
7350                     makestr(&(mgetlist[0]),tmpbuf);
7351 		    debug(F110,"ftp get listfile next",tmpbuf,0);
7352                     s = (char *)remote_files(first,
7353 					     (CHAR *)mgetlist[0],
7354 					     (CHAR *)pv[SND_PAT].sval,
7355 					     0
7356 					     );
7357 		    debug(F110,"ftp mget remote_files C",s,0);
7358                     if (!s) {
7359                         ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7360                         ftscreen(SCR_ST,ST_MSG,(CK_OFF_T)0,"File not found");
7361                         tlog(F110,"ftp get file not found:",s,0);
7362                         goto again;
7363                     }
7364                 } else {		/* Names from command line */
7365                     mgetx++;
7366                     if (mgetx < mgetn)
7367 		      s = (char *)remote_files(first,
7368 					       (CHAR *)mgetlist[mgetx],
7369 					       (CHAR *)pv[SND_PAT].sval,
7370 					       0
7371 					       );
7372                     else
7373 		      s = NULL;
7374 		    if (!s) mgetx++;
7375 		    debug(F111,"ftp mget remote_files D",s,mgetx);
7376                 }
7377                 if (!s) {
7378 		    if (!first || mgetx >= mgetn) {
7379 			done = 1;
7380 			break;
7381 		    } else if (geterror) {
7382 			status = 0;
7383 			done = 1;
7384 			break;
7385 		    } else {
7386 			continue;
7387 		    }
7388                 }
7389             }
7390         }
7391 	debug(F111,"ftp mget remote_files E",s,0);
7392         /*
7393           The semantics of NLST are ill-defined.  Suppose we have just sent
7394           NLST /path/[a-z]*.  Most servers send back names like /path/foo,
7395           /path/bar, etc.  But some send back only foo and bar, and subsequent
7396           RETR commands based on the pathless names are not going to work.
7397         */
7398         if (servertype == SYS_UNIX && !ckstrchr(s,'/')) {
7399             char * s3;
7400             if ((s3 = ckstrrchr(mgetlist[mgetx],'/'))) {
7401                 int len, left = 4096;
7402                 char * tmp = xtmpbuf;
7403                 len = s3 - mgetlist[mgetx] + 1;
7404                 ckstrncpy(tmp,mgetlist[mgetx],left);
7405                 tmp += len;
7406                 left -= len;
7407                 ckstrncpy(tmp,s,left);
7408                 s = xtmpbuf;
7409 		debug(F111,"ftp mget remote_files F",s,0);
7410             }
7411         }
7412         first = 0;
7413         skipthis = 0;                   /* File selection... */
7414         msg = "";
7415         nam = s;                        /* Filename (without path) */
7416         rc = 0;                         /* Initial return code */
7417         s2 = "";
7418 
7419         if (!getone && !skipthis) {     /* For MGET and MDELETE... */
7420             char c, * p = s;
7421             int srvpath = 0;
7422             int usrpath = 0;
7423             int i, k = 0;
7424 
7425 	    debug(F111,"ftp mget havetype",s,havetype);
7426 	    if (havetype > 0 && havetype != FTYP_FILE) {
7427 		/* Server says it's not file... */
7428 		debug(F110,"ftp mget not-a-file",s,0);
7429 		continue;
7430 	    }
7431 /*
7432   Explanation: Some ftp servers (such as wu-ftpd) return a recursive list.
7433   But if the client did not ask for a recursive list, we have to ignore any
7434   server files that include a pathname that extends beyond any path that
7435   was included in the user's request.
7436 
7437   User's filespec is blah or path/blah (or other non-UNIX syntax).  We need to
7438   get the user's path segment.  Then, for each incoming file, if it begins
7439   with the same path segment, we must strip it (point past it).
7440 */
7441             src = mgetlist[mgetx];      /* In case it moved! */
7442 	    if (src) {
7443 		for (i = 0; src[i]; i++) { /* Find rightmost path separator */
7444 		    if (ispathsep(src[i])) /* in user's pathname */
7445 		      k = i + 1;
7446 		}
7447 	    } else {
7448 		src = "";
7449 	    }
7450             usrpath = k;                /* User path segment length */
7451             debug(F111,"ftp get usrpath",src,usrpath);
7452 
7453             p = s;                      /* Server filename */
7454             while ((c = *p++)) {        /* Look for path in server filename */
7455                 if (ispathsep(c)) {
7456 		    /* haspath++; */
7457                     nam = p;            /* Pathless name (for ckmatch) */
7458                     srvpath = p - s;    /* Server path segment length */
7459                 }
7460             }
7461             debug(F111,"ftp get srvpath",s,srvpath);
7462 
7463 	    if (usrpath == 0) {
7464 /*
7465   Here we handle the case where the user said "mget foo" where foo is a
7466   directory name, and the server is sending back names like "foo/file1",
7467   "foo/file2", etc.  This is a nasty trick but it's necessary because the
7468   user can't compensate by typing "mget foo/" because then the server is
7469   likely to send back "foo//file1, foo//file2" etc, and we still won't
7470   get a match...
7471 */
7472 		int srclen = 0, srvlen = 0;
7473 		if (src) srclen = strlen(src);
7474 		if (s) srvlen = strlen(s);
7475 		if (src && (srvlen > srclen)) {
7476 		    if (!strncmp(src,s,srclen) && ispathsep(s[srclen])) {
7477 			char * tmpsrc = NULL;
7478 			tmpsrc = (char *)malloc(srclen + 2);
7479 			strncpy(tmpsrc,src,srclen);
7480 			tmpsrc[srclen] = s[srclen];
7481 			tmpsrc[srclen+1] = NUL;
7482 			free(mgetlist[mgetx]);
7483 			mgetlist[mgetx] = tmpsrc;
7484 			tmpsrc = NULL;
7485 			src = mgetlist[mgetx];
7486 			usrpath = srclen+1;
7487 		    }
7488 		}
7489 	    }
7490 /*
7491   If as-name not given and server filename includes path that matches
7492   the pathname from the user's file specification, we must trim the common
7493   path prefix from the server's name when constructing the local name.
7494 */
7495             if (src &&			/* Wed Sep 25 17:27:48 2002 */
7496 		!asnambuf[0] &&
7497 		!recursive &&		/* Thu Sep 19 16:11:59 2002 */
7498 		(srvpath > 0) &&
7499 		!strncmp(src,s,usrpath)) {
7500                 s2 = s + usrpath;       /* Local name skips past remote path */
7501             }
7502 #ifdef COMMENT
7503 	    /* This doesn't work if the path prefix contains wildcards! */
7504 	    haspath = (srvpath > usrpath);
7505 #else
7506 	    {				/* Count path segments instead */
7507 		int x1 = 0, x2 = 0;
7508 		char *p;
7509 		for (p = s; *p; p++)
7510 		  if (ispathsep(*p)) x1++;
7511 		for (p = src; *p; p++) {
7512 		    if (ispathsep(*p)) x2++;
7513 		}
7514 		haspath = recursive ? x1 || x2 : x1 > x2;
7515 		debug(F111,"ftp get server path segments",s,x1);
7516 		debug(F111,"ftp get user   path segments",src,x2);
7517 	    }
7518 
7519 #endif /* COMMENT */
7520             debug(F111,"ftp get haspath",s+usrpath,haspath);
7521 
7522             if (haspath) {              /* Server file has path segments? */
7523                 if (!recursive) {       /* [M]GET /RECURSIVE? */
7524 /*
7525   We did not ask for a recursive listing, but the server is sending us one
7526   anyway (as wu-ftpd is wont to do).  We get here if the current filename
7527   includes a path segment beyond any path segment we asked for in our
7528   non-recursive [M]GET command.  We MUST skip this file.
7529 */
7530                     debug(F111,"ftp get skipping because of path",s,0);
7531                     continue;
7532                 }
7533             }
7534         } else if (getone && !skipthis) { /* GET (not MGET) */
7535             char * p = nam;
7536 	    while ((c = *p++)) {	/* Handle path in local name */
7537 		if (ispathsep(c)) {
7538 		    if (recursive) {	/* If recursive, keep it */
7539 			haspath = 1;
7540 			break;
7541 		    } else {		/* Otherwise lose it. */
7542 		      nam = p;
7543 		    }
7544 		}
7545             }
7546             s2 = nam;
7547         }
7548         if (!*nam)                      /* Name without path */
7549           nam = s;
7550 
7551         if (!skipthis && pv[SND_NOD].ival > 0) { /* /NODOTFILES */
7552             if (nam[0] == '.')
7553 	      continue;
7554         }
7555         if (!skipthis && rcvexcept[0]) { /* /EXCEPT: list */
7556 	    int xx;
7557             for (i = 0; i < NSNDEXCEPT; i++) {
7558                 if (!rcvexcept[i]) {
7559                     break;
7560                 }
7561 		xx = ckmatch(rcvexcept[i], nam, servertype == SYS_UNIX, 1);
7562 		debug(F111,"ftp mget /except match",rcvexcept[i],xx);
7563                 if (xx) {
7564                     tlog(F100," refused: exception list","",0);
7565 		    msg = "Refused: Exception List";
7566                     skipthis++;
7567                     break;
7568                 }
7569             }
7570         }
7571         if (!skipthis && pv[SND_NOB].ival > 0) { /* /NOBACKUPFILES */
7572             if (ckmatch(
7573 #ifdef CKREGEX
7574                         "*.~[0-9]*~"
7575 #else
7576                         "*.~*~"
7577 #endif /* CKREGEX */
7578                         ,nam,0,1) > 0)
7579               continue;
7580         }
7581         if (!x_xla) {                   /* If translation is off */
7582             x_csl = -2;                 /* unset the charsets */
7583             x_csr = -2;
7584         }
7585         ckstrncpy(filnam,s,CKMAXPATH);  /* For \v(filename) */
7586         if (!*s2)                       /* Local name */
7587           s2 = asnambuf;                /* As-name */
7588 
7589 	if (!*s2)			/* Sat Nov 16 19:19:39 2002 */
7590 	  s2 = recursive ? s : nam;	/* Fri Jan 10 13:15:19 2003 */
7591 
7592         debug(F110,"ftp get filnam  ",s,0);
7593         debug(F110,"ftp get asname A",s2,0);
7594 
7595         /* Receiving to real file */
7596         if (!pipesend &&
7597 #ifdef PIPESEND
7598             !rcvfilter &&
7599 #endif /* PIPESEND */
7600             !toscreen) {
7601 #ifndef NOSPL
7602             /* Do this here so we can decide whether to skip */
7603             if (cmd_quoting && !skipthis && asnambuf[0]) {
7604                 int n; char *p;
7605                 n = TMPBUFSIZ;
7606                 p = tmpbuf;
7607                 zzstring(asnambuf,&p,&n);
7608                 s2 = tmpbuf;
7609                 debug(F111,"ftp get asname B",s2,updating);
7610             }
7611 #endif /* NOSPL */
7612 
7613 	    local = *s2 ? s2 : s;
7614 
7615 	    if (!skipthis && x_fnc == XYFX_D) { /* File Collision = Discard */
7616 		CK_OFF_T x;
7617 		x = zchki(local);
7618 		debug(F111,"ftp get DISCARD zchki",local,x);
7619 		if (x > -1) {
7620 		    skipthis++;
7621 		    debug(F110,"ftp get skip name",local,0);
7622 		    tlog(F100," refused: name","",0);
7623 		    msg = "Refused: Name";
7624 		}
7625 	    }
7626 
7627 #ifdef DOUPDATE
7628             if (!skipthis && updating) { /* If updating and not yet skipping */
7629                 if (zchki(local) > -1) {
7630                     x = chkmodtime(local,s,0);
7631 #ifdef DEBUG
7632 		    if (deblog) {
7633 			if (updating == 2)
7634 			  debug(F111,"ftp get /dates-diff chkmodtime",local,x);
7635 			else
7636 			  debug(F111,"ftp get /update chkmodtime",local,x);
7637 		    }
7638 #endif /* DEBUG */
7639 		    if ((updating == 1 && x > 0) ||  /* /UPDATE */
7640 			(updating == 2 && x == 1)) { /* /DATES-DIFFER */
7641 			skipthis++;
7642 			tlog(F100," refused: date","",0);
7643 			msg = "Refused: Date";
7644                         debug(F110,"ftp get skip date",local,0);
7645                     }
7646                 }
7647             }
7648 #endif /* DOUPDATE */
7649         }
7650         /* Initialize file size to -1 in case server doesn't understand */
7651         /* SIZE command, so xxscreen() will know we don't know the size */
7652 
7653         fsize = (CK_OFF_T)-1;
7654 
7655 	/* Ask for size now only if we need it for selection */
7656 	/* because if you're going thru a list 100,000 files to select */
7657 	/* a small subset, 100,000 SIZE commands can take hours... */
7658 
7659 	gotsize = 0;
7660         if (!mdel && !skipthis &&        /* Don't need size for DELE... */
7661 	    (getsmaller >= (CK_OFF_T)0  || getlarger >= (CK_OFF_T)0)) {
7662 	    if (havesize >= (CK_OFF_T)0) { /* Already have file size? */
7663 		fsize = havesize;
7664 		gotsize = 1;
7665 	    } else {			/* No - must ask server */
7666 		/*
7667 		  Prior to sending the NLST command we necessarily put the
7668 		  server into ASCII mode.  We must now put it back into the
7669 		  the requested mode so the upcoming SIZE command returns
7670 		  right kind of size; this is especially important for
7671 		  GET /RECOVER; otherwise the server returns the "ASCII" size
7672 		  of the file, rather than its true size.
7673 		*/
7674 		changetype(ftp_typ,0);	/* Change to requested type */
7675 		fsize = (CK_OFF_T)-1;
7676 		if (sizeok) {
7677 		    x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7678 		    if (x == REPLY_COMPLETE) {
7679 			fsize = ckatofs(&ftp_reply_str[4]);
7680 			gotsize = 1;
7681 		    }
7682 		}
7683 	    }
7684             if (gotsize) {
7685                 if (getsmaller >= (CK_OFF_T)0 && fsize >= getsmaller)
7686                   skipthis++;
7687                 if (getlarger >= (CK_OFF_T)0 && fsize <= getlarger)
7688                   skipthis++;
7689                 if (skipthis) {
7690                     debug(F111,"ftp get skip size",s,fsize);
7691                     tlog(F100," refused: size","",0);
7692                     msg = "Refused: Size";
7693                 }
7694 #ifdef COMMENT
7695             } else if (getone) {
7696                 /* SIZE can fail for many reasons.  Does the file exist? */
7697                 x = ftpcmd("NLST",s,x_csl,x_csr,ftp_vbm);
7698                 if (x != REPLY_COMPLETE) {
7699                     printf(">>> FILE NOT FOUND: %s\n",s);
7700                     break;
7701                 }
7702 #endif /* COMMENT */
7703             }
7704         }
7705         if (skipthis) {                 /* Skipping this file? */
7706             ftscreen(SCR_FN,'F',(CK_OFF_T)0,s);
7707             if (msg)
7708               ftscreen(SCR_ST,ST_ERR,(CK_OFF_T)0,msg);
7709             else
7710               ftscreen(SCR_ST,ST_SKIP,(CK_OFF_T)0,s);
7711             continue;
7712         }
7713         if (fp_nml) {                   /* /NAMELIST only - no transfer */
7714             fprintf(fp_nml,"%s\n",s);
7715             continue;
7716         }
7717         if (recursive && haspath && !pipesend
7718 #ifdef PIPESEND
7719             && !rcvfilter
7720 #endif /* PIPESEND */
7721             ) {
7722 	    int x;
7723 
7724 #ifdef NOMKDIR
7725 	    x = -1;
7726 #else
7727             x = zmkdir(s);		/* Try to make the directory */
7728 #endif /* NOMKDIR */
7729 
7730             if (x < 0) {
7731                 rc = -1;                /* Failure is fatal */
7732                 if (geterror) {
7733                     status = 0;
7734                     ftscreen(SCR_EM,0,(CK_OFF_T)0,
7735 			     "Directory creation failure");
7736                     break;
7737                 }
7738             }
7739         }
7740 
7741         /* Not skipping */
7742 
7743 	selected++;			/* Count this file as selected */
7744         pn = NULL;
7745 
7746 	if (!gotsize && !mdel) {	/* Didn't get size yet */
7747 	    if (havesize > (CK_OFF_T)-1) { /* Already have file size? */
7748 		fsize = havesize;
7749 		gotsize = 1;
7750 	    } else {			/* No - must ask server */
7751 		fsize = (CK_OFF_T)-1;
7752 		if (sizeok) {
7753 		    x = ftpcmd("SIZE",s,x_csl,x_csr,ftp_vbm);
7754 		    if (x == REPLY_COMPLETE) {
7755 			fsize = ckatofs(&ftp_reply_str[4]);
7756 			gotsize = 1;
7757 		    }
7758 		}
7759 	    }
7760 	}
7761         if (mdel) {                     /* [M]DELETE */
7762             if (displa && !ftp_vbm)
7763               printf(" %s...",s);
7764             rc =
7765              (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE) ? 1 : -1;
7766             if (rc > -1) {
7767                 tlog(F110,"ftp mdelete",s,0);
7768                 if (displa && !ftp_vbm)
7769                   printf("OK\n");
7770             } else {
7771                 tlog(F110,"ftp mdelete failed:",s,0);
7772                 if (displa)
7773                   printf("Failed\n");
7774             }
7775 #ifndef NOSPL
7776 #ifdef PIPESEND
7777         } else if (rcvfilter) {         /* [M]GET with filter */
7778             int n; char * p;
7779             n = CKMAXPATH;
7780             p = tmpbuf;                 /* Safe - no asname with filter */
7781             zzstring(rcvfilter,&p,&n);
7782             if (n > -1)
7783               pn = tmpbuf;
7784             debug(F111,"ftp get rcvfilter",pn,n);
7785 #endif /* PIPESEND */
7786 #endif /* NOSPL */
7787             if (toscreen) s2 = "-";
7788         } else if (pipesend) {          /* [M]GET /COMMAND */
7789             int n; char * p;
7790             n = CKMAXPATH;
7791             p = tmpbuf;                 /* Safe - no asname with filter */
7792             zzstring(pipename,&p,&n);
7793             if (n > -1)
7794               pn = tmpbuf;
7795             debug(F111,"ftp get pipename",pipename,n);
7796             if (toscreen) s2 = "-";
7797         } else {                        /* [M]GET with no pipes or filters */
7798             debug(F111,"ftp get s2 A",s2,x_cnv);
7799             if (toscreen) {
7800                 s2 = "-";               /* (hokey convention for stdout) */
7801             } else if (!*s2) {          /* No asname? */
7802                 if (x_cnv) {            /* If converting */
7803                     nzrtol(s,tmpbuf,x_cnv,1,CKMAXPATH); /* convert */
7804                     s2 = tmpbuf;
7805                     debug(F110,"ftp get nzrtol",s2,0);
7806                 } else                  /* otherwise */
7807                   s2 = s;               /* use incoming file's name */
7808             }
7809             debug(F110,"ftp get s2 B",s2,0);
7810 
7811             /* If local file already exists, take collision action */
7812 
7813             if (!pipesend &&
7814 #ifdef PIPESEND
7815                 !rcvfilter &&
7816 #endif /* PIPESEND */
7817                 !toscreen) {
7818 		CK_OFF_T x;
7819                 x = zchki(s2);
7820                 debug(F111,"ftp get zchki",s2,x);
7821                 debug(F111,"ftp get x_fnc",s2,x_fnc);
7822 
7823                 if (x > (CK_OFF_T)-1 && !restart) {
7824 		    int x = -1;
7825 		    char * newname = NULL;
7826 
7827                     switch (x_fnc) {
7828                       case XYFX_A:      /* Append */
7829                         append = 1;
7830                         break;
7831                       case XYFX_R:      /* Rename */
7832                       case XYFX_B:	/* Backup */
7833 			znewn(s2,&newname); /* Make unique name */
7834 			debug(F110,"ftp get znewn",newname,0);
7835 			if (x_fnc == XYFX_B) { /* Backup existing file */
7836 			    x = zrename(s2,newname);
7837 			    debug(F111,"ftp get backup zrename",newname,x);
7838 			} else {      /* Rename incoming file */
7839 			    x = ckstrncpy(tmpbuf,newname,CKMAXPATH+1);
7840 			    s2 = tmpbuf;
7841 			    debug(F111,"ftp get rename incoming",newname,x);
7842 			}
7843 			if (x < 0) {
7844 			    ftscreen(SCR_EM,0,(CK_OFF_T)0,
7845 				     "Backup/Rename failed");
7846 			    x = 0;
7847 			    goto xgetx;
7848 			}
7849 			break;
7850                       case XYFX_D:      /* Discard (already handled above) */
7851                       case XYFX_U:      /* Update (ditto) */
7852                       case XYFX_M:      /* Update (ditto) */
7853                       case XYFX_X:      /* Overwrite */
7854                         break;
7855                     }
7856                 }
7857             }
7858         }
7859         if (!mdel) {
7860 #ifdef PIPESEND
7861             debug(F111,"ftp get pn",pn,rcvfilter ? 1 : 0);
7862 #endif /* PIPESEND */
7863             if (pipesend && !toscreen)
7864               s2 = NULL;
7865 #ifdef DEBUG
7866             if (deblog) {
7867                 debug(F101,"ftp get x_xla","",x_xla);
7868                 debug(F101,"ftp get x_csl","",x_csl);
7869                 debug(F101,"ftp get x_csr","",x_csr);
7870                 debug(F101,"ftp get append","",append);
7871             }
7872 #endif /* DEBUG */
7873 
7874             rc = getfile(s,s2,restart,append,pn,x_xla,x_csl,x_csr);
7875 
7876 #ifdef DEBUG
7877             if (deblog) {
7878                 debug(F111,"ftp get rc",s,rc);
7879                 debug(F111,"ftp get ftp_timed_out",s,ftp_timed_out);
7880                 debug(F111,"ftp get cancelfile",s,cancelfile);
7881                 debug(F111,"ftp get cancelgroup",s,cancelgroup);
7882                 debug(F111,"ftp get renaming",s,renaming);
7883                 debug(F111,"ftp get moving",s,moving);
7884             }
7885 #endif /* DEBUG */
7886         }
7887         if (rc > -1) {
7888             good++;
7889             status = 1;
7890             if (!cancelfile) {
7891                 if (deleting) {         /* GET /DELETE (source file) */
7892                     rc =
7893                       (ftpcmd("DELE",s,x_csl,x_csr,ftp_vbm) == REPLY_COMPLETE)
7894                         ? 1 : -1;
7895                     tlog(F110, (rc > -1) ?
7896                          " deleted" : " failed to delete", s, 0);
7897                 }
7898 		if (renaming && rcv_rename && !toscreen) {
7899                     char *p;            /* Rename downloaded file */
7900 #ifndef NOSPL
7901                     char tmpbuf[CKMAXPATH+1];
7902                     int n;
7903                     n = CKMAXPATH;
7904                     p = tmpbuf;
7905                     debug(F111,"ftp get /rename",rcv_rename,0);
7906                     zzstring(rcv_rename,&p,&n);
7907                     debug(F111,"ftp get /rename",rcv_rename,0);
7908                     p = tmpbuf;
7909 #else
7910                     p = rcv_rename;
7911 #endif /* NOSPL */
7912                     rc = (zrename(s2,p) < 0) ? -1 : 1;
7913                     debug(F111,"doftpget /RENAME zrename",p,rc);
7914                     tlog(F110, (rc > -1) ?
7915                          " renamed to" :
7916                          " failed to rename to",
7917                          p,
7918                          0
7919                          );
7920                 } else if (moving && rcv_move && !toscreen) {
7921                     char *p;            /* Move downloaded file */
7922 #ifndef NOSPL
7923                     char tmpbuf[CKMAXPATH+1];
7924                     int n;
7925                     n = TMPBUFSIZ;
7926                     p = tmpbuf;
7927                     debug(F111,"ftp get /move-to",rcv_move,0);
7928                     zzstring(rcv_move,&p,&n);
7929                     p = tmpbuf;
7930 #else
7931                     p = rcv_move;
7932 #endif /* NOSPL */
7933                     debug(F111,"ftp get /move-to",p,0);
7934                     rc = (zrename(s2,p) < 0) ? -1 : 1;
7935                     debug(F111,"doftpget /MOVE zrename",p,rc);
7936                     tlog(F110, (rc > -1) ?
7937                          " moved to" : " failed to move to", p, 0);
7938                 }
7939                 if (pv[SND_SRN].ival > 0 && pv[SND_SRN].sval) {
7940                     char * s = pv[SND_SRN].sval;
7941                     char * srvrn = pv[SND_SRN].sval;
7942                     char tmpbuf[CKMAXPATH+1];
7943 #ifndef NOSPL
7944                     int y;              /* Pass it thru the evaluator */
7945                     extern int cmd_quoting; /* for \v(filename) */
7946                     debug(F111,"ftp get srv_renam",s,1);
7947 
7948                     if (cmd_quoting) {
7949                         y = CKMAXPATH;
7950                         s = (char *)tmpbuf;
7951                         zzstring(srvrn,&s,&y);
7952                         s = (char *)tmpbuf;
7953                     }
7954 #endif /* NOSPL */
7955                     debug(F111,"ftp get srv_renam",s,1);
7956                     if (s) if (*s) {
7957                         int x;
7958                         x = ftp_rename(s2,s);
7959                         debug(F111,"ftp get ftp_rename",s2,x);
7960                         tlog(F110, (x > 0) ?
7961                              " renamed source file to" :
7962                              " failed to rename source file to",
7963                              s,
7964                              0
7965                              );
7966                         if (x < 1)
7967 			  return(-1);
7968                     }
7969                 }
7970             }
7971         }
7972         if (cancelfile)
7973           continue;
7974         if (rc < 0) {
7975             ftp_fai++;
7976 #ifdef FTP_TIMEOUT
7977 	    debug(F101,"ftp get ftp_timed_out","",ftp_timed_out);
7978 	    if (ftp_timed_out) {
7979 		status = 0;
7980                 ftscreen(SCR_EM,0,(CK_OFF_T)0,"GET timed out");
7981 	    }
7982 #endif	/* FTP_TIMEOUT */
7983             if (geterror) {
7984                 status = 0;
7985                 ftscreen(SCR_EM,0,(CK_OFF_T)0,"Fatal download error");
7986                 done++;
7987             }
7988         }
7989     }
7990 #ifdef DEBUG
7991     if (deblog) {
7992 	debug(F101,"ftp get status","",status);
7993 	debug(F101,"ftp get cancelgroup","",cancelgroup);
7994 	debug(F101,"ftp get cancelfile","",cancelfile);
7995 	debug(F101,"ftp get selected","",selected);
7996 	debug(F101,"ftp get good","",good);
7997     }
7998 #endif /* DEBUG */
7999 
8000     if (selected == 0) {		/* No files met selection criteria */
8001 	status = 1;			/* which is a kind of success. */
8002     } else if (status > 0) {		/* Some files were selected */
8003         if (cancelgroup)		/* but MGET was canceled */
8004           status = 0;			/* so MGET failed */
8005         else if (cancelfile && good < 1) /* If file was canceled */
8006           status = 0;			/* MGET failed if it got no files */
8007     }
8008     success = status;
8009     x = success;
8010     debug(F101,"ftp get success","",success);
8011 
8012   xgetx:
8013     pipesend = pipesave;                /* Restore global pipe selection */
8014     if (fp_nml) {                       /* Close /NAMELIST */
8015         if (fp_nml != stdout)
8016           fclose(fp_nml);
8017         fp_nml = NULL;
8018     }
8019     if (
8020 #ifdef COMMENT
8021 	x > -1
8022 #else
8023 	success
8024 #endif	/* COMMENT */
8025 	) {				/* Download successful */
8026 #ifdef GFTIMER
8027         t1 = gmstimer();                /* End time */
8028         sec = (CKFLOAT)((CKFLOAT)(t1 - t0) / 1000.0); /* Stats */
8029         if (!sec) sec = 0.001;
8030         fptsecs = sec;
8031 #else
8032         sec = (t1 - t0) / 1000;
8033         if (!sec) sec = 1;
8034 #endif /* GFTIMER */
8035         tfcps = (long) (tfc / sec);
8036         tsecs = (int)sec;
8037         lastxfer = W_FTP|W_RECV;
8038         xferstat = success;
8039     }
8040     if (dpyactive)
8041       ftscreen(success > 0 ? SCR_TC : SCR_CW, 0, (CK_OFF_T)0, "");
8042 #ifdef CK_TMPDIR
8043     if (f_tmpdir) {                     /* If we changed to download dir */
8044         zchdir((char *) savdir);        /* Go back where we came from */
8045         f_tmpdir = 0;
8046     }
8047 #endif /* CK_TMPDIR */
8048 
8049     for (i = 0; i <= SND_MAX; i++) {    /* Free malloc'd memory */
8050         if (pv[i].sval)
8051           free(pv[i].sval);
8052     }
8053     for (i = 0; i < mgetn; i++)         /* MGET list too */
8054       makestr(&(mgetlist[i]),NULL);
8055 
8056     if (cancelgroup)			/* Clear temp-file stack */
8057       mlsreset();
8058 
8059     ftreset();                          /* Undo switch effects */
8060     dpyactive = 0;
8061     return(x);
8062 }
8063 
8064 static struct keytab ftprmt[] = {
8065     { "cd",        XZCWD, 0 },
8066     { "cdup",      XZCDU, 0 },
8067     { "cwd",       XZCWD, CM_INV },
8068     { "delete",    XZDEL, 0 },
8069     { "directory", XZDIR, 0 },
8070     { "exit",      XZXIT, 0 },
8071     { "help",      XZHLP, 0 },
8072     { "login",     XZLGI, 0 },
8073     { "logout",    XZLGO, 0 },
8074     { "mkdir",     XZMKD, 0 },
8075     { "pwd",       XZPWD, 0 },
8076     { "rename",    XZREN, 0 },
8077     { "rmdir",     XZRMD, 0 },
8078     { "type",      XZTYP, 0 },
8079     { "", 0, 0 }
8080 };
8081 static int nftprmt = (sizeof(ftprmt) / sizeof(struct keytab)) - 1;
8082 
8083 int
doftpsite()8084 doftpsite() {				/* Send a SITE command */
8085     int reply;
8086     char * s;
8087     int lcs = -1, rcs = -1;
8088     int save_vbm = ftp_vbm;
8089 
8090 #ifndef NOCSETS
8091     if (ftp_xla) {
8092         lcs = ftp_csl;
8093         if (lcs < 0) lcs = fcharset;
8094         rcs = ftp_csx;
8095         if (rcs < 0) rcs = ftp_csr;
8096     }
8097 #endif /* NOCSETS */
8098     if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8099       return(x);
8100     CHECKCONN();
8101     ckstrncpy(line,s,LINBUFSIZ);
8102     if (testing) printf(" ftp site \"%s\"...\n",line);
8103     if (!ftp_vbm)
8104         ftp_vbm = !ckstrcmp("HELP",line,4,0);
8105     if ((reply = ftpcmd("SITE",line,lcs,rcs,ftp_vbm)) == REPLY_PRELIM) {
8106 	do {
8107 	    reply = getreply(0,lcs,rcs,ftp_vbm,0);
8108 	} while (reply == REPLY_PRELIM);
8109     }
8110     ftp_vbm = save_vbm;
8111     return(success = (reply == REPLY_COMPLETE));
8112 }
8113 
8114 
8115 int
dosetftppsv()8116 dosetftppsv() {				/* Passive mode */
8117     x = seton(&ftp_psv);
8118     if (x > 0) passivemode = ftp_psv;
8119     return(x);
8120 }
8121 
8122 /*  d o f t p r m t  --  Parse and execute REMOTE commands  */
8123 
8124 int
doftprmt(cx,who)8125 doftprmt(cx,who) int cx, who; {         /* who == 1 for ftp, 0 for kermit */
8126     /* cx == 0 means REMOTE */
8127     /* cx != 0 is a XZxxx value */
8128     char * s;
8129 
8130     if (who != 0)
8131       return(0);
8132 
8133     if (cx == 0) {
8134         if ((x = cmkey(ftprmt,nftprmt,"","",xxstring)) < 0)
8135           return(x);
8136         cx = x;
8137     }
8138     switch (cx) {
8139       case XZCDU:                       /* CDUP */
8140         if ((x = cmcfm()) < 0) return(x);
8141         return(doftpcdup());
8142 
8143       case XZCWD:                       /* RCD */
8144         if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8145           return(x);
8146         ckstrncpy(line,s,LINBUFSIZ);
8147 	s = brstrip(line);
8148         return(doftpcwd(s,1));
8149       case XZPWD:                       /* RPWD */
8150         return(doftppwd());
8151       case XZDEL:                       /* RDEL */
8152         return(doftpget(FTP_MDE,1));
8153       case XZDIR:                       /* RDIR */
8154         return(doftpdir(FTP_DIR));
8155       case XZHLP:                       /* RHELP */
8156         return(doftpxhlp());
8157       case XZMKD:                       /* RMKDIR */
8158         return(doftpmkd());
8159       case XZREN:                       /* RRENAME */
8160         return(doftpren());
8161       case XZRMD:                       /* RRMDIR */
8162         return(doftprmd());
8163       case XZLGO:                       /* LOGOUT */
8164         return(doftpres());
8165       case XZXIT:                       /* EXIT */
8166         return(ftpbye());
8167     }
8168     printf("?Not usable with FTP - \"%s\"\n", atmbuf);
8169     return(-9);
8170 }
8171 
8172 int
doxftp()8173 doxftp() {                              /* Command parser for built-in FTP */
8174     int cx, n;
8175     struct FDB kw, fl;
8176     char * s;
8177     int usetls = 0;
8178     int lcs = -1, rcs = -1;
8179 
8180 #ifndef NOCSETS
8181     if (ftp_xla) {
8182         lcs = ftp_csl;
8183         if (lcs < 0) lcs = fcharset;
8184         rcs = ftp_csx;
8185         if (rcs < 0) rcs = ftp_csr;
8186     }
8187 #endif /* NOCSETS */
8188 
8189     if (inserver)                       /* FTP not allowed in IKSD. */
8190       return(-2);
8191 
8192     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
8193         ftp_typ = g_ftp_typ;
8194         /* g_ftp_typ = -1; */
8195     }
8196 #ifdef COMMENT
8197 /*
8198   We'll set the collision action locally in doftpget() based on whether
8199   ftp_fnc was ever set to a value.  if not, we'll use the fncact value.
8200 */
8201     if (ftp_fnc < 0)                    /* Inherit global collision action */
8202       ftp_fnc = fncact;                 /* if none specified for FTP */
8203 #endif /* COMMENT */
8204 
8205     /* Restore global verbose mode */
8206     if (ftp_deb)
8207       ftp_vbm = 1;
8208     else if (quiet)
8209       ftp_vbm = 0;
8210     else
8211       ftp_vbm = ftp_vbx;
8212 
8213     ftp_dates &= 1;			/* Undo any previous /UPDATE switch */
8214 
8215     dpyactive = 0;                      /* Reset global transfer-active flag */
8216     printlines = 0;                     /* Reset printlines */
8217 
8218     if (fp_nml) {                       /* Reset /NAMELIST */
8219         if (fp_nml != stdout)
8220           fclose(fp_nml);
8221         fp_nml = NULL;
8222     }
8223     makestr(&ftp_nml,NULL);
8224 
8225     cmfdbi(&kw,                         /* First FDB - commands */
8226            _CMKEY,                      /* fcode */
8227            "Hostname; or FTP command",  /* help */
8228            "",                          /* default */
8229            "",                          /* addtl string data */
8230            nftpcmd,                     /* addtl numeric data 1: tbl size */
8231            0,                           /* addtl numeric data 2: none */
8232            xxstring,                    /* Processing function */
8233            ftpcmdtab,                   /* Keyword table */
8234            &fl                          /* Pointer to next FDB */
8235            );
8236     cmfdbi(&fl,                         /* A host name or address */
8237            _CMFLD,                      /* fcode */
8238            "Hostname or address",       /* help */
8239            "",                          /* default */
8240            "",                          /* addtl string data */
8241            0,                           /* addtl numeric data 1 */
8242            0,                           /* addtl numeric data 2 */
8243            xxstring,
8244            NULL,
8245            NULL
8246            );
8247     x = cmfdb(&kw);                     /* Parse a hostname or a keyword */
8248     if (x == -3) {
8249         printf("?ftp what? \"help ftp\" for hints\n");
8250         return(-9);
8251     }
8252     if (x < 0)
8253       return(x);
8254     if (cmresult.fcode == _CMFLD) {     /* If hostname */
8255         return(openftp(cmresult.sresult,0)); /* go open the connection */
8256     } else {
8257         cx = cmresult.nresult;
8258     }
8259     switch (cx) {
8260       case FTP_ACC:                     /* ACCOUNT */
8261         if ((x = cmtxt("Remote account", "", &s, xxstring)) < 0)
8262           return(x);
8263         CHECKCONN();
8264         makestr(&ftp_acc,s);
8265         if (testing)
8266           printf(" ftp account: \"%s\"\n",ftp_acc);
8267         success = (ftpcmd("ACCT",ftp_acc,-1,-1,ftp_vbm) == REPLY_COMPLETE);
8268         return(success);
8269 
8270       case FTP_GUP:                     /* Go UP */
8271         if ((x = cmcfm()) < 0) return(x);
8272         CHECKCONN();
8273         if (testing) printf(" ftp cd: \"(up)\"\n");
8274         return(success = doftpcdup());
8275 
8276       case FTP_CWD:                     /* CD */
8277         if ((x = cmtxt("Remote directory", "", &s, xxstring)) < 0)
8278           return(x);
8279         CHECKCONN();
8280         ckstrncpy(line,s,LINBUFSIZ);
8281         if (testing)
8282           printf(" ftp cd: \"%s\"\n", line);
8283         return(success = doftpcwd(line,1));
8284 
8285       case FTP_CHM:                     /* CHMOD */
8286         if ((x = cmfld("Permissions or protection code","",&s,xxstring)) < 0)
8287           return(x);
8288         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8289         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8290           return(x);
8291         CHECKCONN();
8292         ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,tmpbuf," ",s,NULL);
8293         if (testing)
8294           printf(" ftp chmod: %s\n",ftpcmdbuf);
8295         success =
8296           (ftpcmd("SITE CHMOD",ftpcmdbuf,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8297         return(success);
8298 
8299       case FTP_CLS:                     /* CLOSE FTP connection */
8300         if ((y = cmcfm()) < 0)
8301           return(y);
8302         CHECKCONN();
8303         if (testing)
8304           printf(" ftp closing...\n");
8305         ftpclose();
8306         return(success = 1);
8307 
8308       case FTP_DIR:                     /* DIRECTORY of remote files */
8309       case FTP_VDI:
8310         return(doftpdir(cx));
8311 
8312       case FTP_GET:                     /* GET a remote file */
8313       case FTP_RGE:                     /* REGET */
8314       case FTP_MGE:                     /* MGET */
8315       case FTP_MDE:                     /* MDELETE */
8316         return(doftpget(cx,1));
8317 
8318       case FTP_IDL:                     /* IDLE */
8319         if ((x = cmnum("Number of seconds","-1",10,&z,xxstring)) < 0)
8320           return(x);
8321         if ((y = cmcfm()) < 0)
8322           return(y);
8323         CHECKCONN();
8324         if (z < 0)  {                   /* Display idle timeout */
8325             if (testing)
8326               printf(" ftp query idle timeout...\n");
8327             success = (ftpcmd("SITE IDLE",NULL,0,0,1) == REPLY_COMPLETE);
8328         } else {                        /* Set idle timeout */
8329             if (testing)
8330               printf(" ftp idle timeout set: %d...\n",z);
8331             success =
8332               (ftpcmd("SITE IDLE",ckitoa(z),0,0,1) == REPLY_COMPLETE);
8333         }
8334         return(success);
8335 
8336       case FTP_MKD:                     /* MKDIR */
8337         return(doftpmkd());
8338 
8339       case FTP_MOD:                     /* MODTIME */
8340         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8341           return(x);
8342         CHECKCONN();
8343         ckstrncpy(line,s,LINBUFSIZ);
8344         if (testing)
8345           printf(" ftp modtime \"%s\"...\n",line);
8346         success = 0;
8347         if (ftpcmd("MDTM",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE) {
8348 	    success = 1;
8349 	    mdtmok = 1;
8350 	    if (!quiet) {
8351 		int flag = 0;
8352 		char c, * s;
8353 		struct tm tmremote;
8354 
8355 		bzero((char *)&tmremote, sizeof(struct tm));
8356 		s = ftp_reply_str;
8357 		while ((c = *s++)) {
8358 		    if (c == SP) {
8359 			flag++;
8360 			break;
8361 		    }
8362 		}
8363 		if (flag) {
8364 		    if (sscanf(s, "%04d%02d%02d%02d%02d%02d",
8365 			       &tmremote.tm_year,
8366 			       &tmremote.tm_mon,
8367 			       &tmremote.tm_mday,
8368 			       &tmremote.tm_hour,
8369 			       &tmremote.tm_min,
8370 			       &tmremote.tm_sec
8371 			       ) == 6) {
8372 			printf(" %s %04d-%02d-%02d %02d:%02d:%02d GMT\n",
8373 			       line,
8374 			       tmremote.tm_year,
8375 			       tmremote.tm_mon,
8376 			       tmremote.tm_mday,
8377 			       tmremote.tm_hour,
8378 			       tmremote.tm_min,
8379 			       tmremote.tm_sec
8380 			       );
8381 		    } else {
8382 			success = 0;
8383 		    }
8384 		}
8385 	    }
8386         }
8387         return(success);
8388 
8389       case FTP_OPN:                     /* OPEN connection */
8390 #ifdef COMMENT
8391         x = cmfld("IP hostname or address","",&s,xxstring);
8392         if (x < 0) {
8393             success = 0;
8394             return(x);
8395         }
8396         ckstrncpy(line,s,LINBUFSIZ);
8397         s = line;
8398         return(openftp(s,0));
8399 #else
8400         {                               /* OPEN connection */
8401             char name[TTNAMLEN+1], *p;
8402             extern int network;
8403             extern char ttname[];
8404             if (network)                /* If we have a current connection */
8405               ckstrncpy(name,ttname,LINBUFSIZ); /* get the host name */
8406             else
8407               *name = '\0';             /* as default host */
8408             for (p = name; *p; p++)     /* Remove ":service" from end. */
8409               if (*p == ':') { *p = '\0'; break; }
8410 #ifndef USETLSTAB
8411             x = cmfld("IP hostname or address",name,&s,xxstring);
8412 #else
8413             cmfdbi(&kw,                 /* First FDB - commands */
8414                    _CMKEY,              /* fcode */
8415                    "Hostname or switch", /* help */
8416                    "",                  /* default */
8417                    "",                  /* addtl string data */
8418                    ntlstab,             /* addtl numeric data 1: tbl size */
8419                    0,                   /* addtl numeric data 2: none */
8420                    xxstring,            /* Processing function */
8421                    tlstab,              /* Keyword table */
8422                    &fl                  /* Pointer to next FDB */
8423                    );
8424             cmfdbi(&fl,                 /* A host name or address */
8425                    _CMFLD,              /* fcode */
8426                    "Hostname or address", /* help */
8427                    "",                  /* default */
8428                    "",                  /* addtl string data */
8429                    0,                   /* addtl numeric data 1 */
8430                    0,                   /* addtl numeric data 2 */
8431                    xxstring,
8432                    NULL,
8433                    NULL
8434                    );
8435 
8436             for (n = 0;; n++) {
8437                 x = cmfdb(&kw);         /* Parse a hostname or a keyword */
8438                 if (x == -3) {
8439                   printf("?ftp open what? \"help ftp\" for hints\n");
8440                   return(-9);
8441                 }
8442                 if (x < 0)
8443                   break;
8444                 if (cmresult.fcode == _CMFLD) { /* Hostname */
8445                     s = cmresult.sresult;
8446                     break;
8447                 } else if (cmresult.nresult == OPN_TLS) {
8448                     usetls = 1;
8449                 }
8450             }
8451 #endif /* USETLSTAB */
8452             if (x < 0) {
8453                 success = 0;
8454                 return(x);
8455             }
8456             ckstrncpy(line,s,LINBUFSIZ);
8457             s = line;
8458             return(openftp(s,usetls));
8459         }
8460 #endif /* COMMENT */
8461 
8462       case FTP_PUT:                     /* PUT */
8463       case FTP_MPU:                     /* MPUT */
8464       case FTP_APP:                     /* APPEND */
8465       case FTP_REP:			/* REPUT */
8466         return(doftpput(cx,1));
8467 
8468       case FTP_PWD:                     /* PWD */
8469         x = doftppwd();
8470         if (x > -1) success = x;
8471         return(x);
8472 
8473       case FTP_REN:                     /* RENAME */
8474         return(doftpren());
8475 
8476       case FTP_RES:                     /* RESET */
8477         return(doftpres());
8478 
8479       case FTP_HLP:                     /* (remote) HELP */
8480         return(doftpxhlp());
8481 
8482       case FTP_RMD:                     /* RMDIR */
8483         return(doftprmd());
8484 
8485       case FTP_STA:                     /* STATUS */
8486         if ((x = cmtxt("Command", "", &s, xxstring)) < 0)
8487           return(x);
8488         CHECKCONN();
8489         ckstrncpy(line,s,LINBUFSIZ);
8490         if (testing) printf(" ftp status \"%s\"...\n",line);
8491         success = (ftpcmd("STAT",line,lcs,rcs,1) == REPLY_COMPLETE);
8492         return(success);
8493 
8494       case FTP_SIT: {                   /* SITE */
8495 	  return(doftpsite());
8496       }
8497 
8498       case FTP_SIZ:                     /* (ask for) SIZE */
8499         if ((x = cmtxt("Remote filename", "", &s, xxstring)) < 0)
8500           return(x);
8501         CHECKCONN();
8502         ckstrncpy(line,s,LINBUFSIZ);
8503         if (testing)
8504           printf(" ftp size \"%s\"...\n",line);
8505         success = (ftpcmd("SIZE",line,lcs,rcs,1) == REPLY_COMPLETE);
8506 	if (success)
8507 	  sizeok = 1;
8508         return(success);
8509 
8510       case FTP_SYS:                     /* Ask for server's SYSTEM type */
8511         if ((x = cmcfm()) < 0) return(x);
8512         CHECKCONN();
8513         if (testing)
8514           printf(" ftp system...\n");
8515         success = (ftpcmd("SYST",NULL,0,0,1) == REPLY_COMPLETE);
8516         return(success);
8517 
8518       case FTP_UMA:                     /* Set/query UMASK */
8519         if ((x = cmfld("Umask to set or nothing to query","",&s,xxstring)) < 0)
8520           if (x != -3)
8521             return(x);
8522         ckstrncpy(tmpbuf,s,TMPBUFSIZ);
8523         if ((x = cmcfm()) < 0) return(x);
8524         CHECKCONN();
8525         if (testing) {
8526             if (tmpbuf[0])
8527               printf(" ftp umask \"%s\"...\n",tmpbuf);
8528             else
8529               printf(" ftp query umask...\n");
8530         }
8531         success = ftp_umask(tmpbuf);
8532         return(success);
8533 
8534       case FTP_USR:
8535         return(doftpusr());
8536 
8537       case FTP_QUO:
8538         if ((x = cmtxt("FTP protocol command", "", &s, xxstring)) < 0)
8539           return(x);
8540         CHECKCONN();
8541         success = (ftpcmd(s,NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
8542         return(success);
8543 
8544       case FTP_TYP:                     /* Type */
8545         if ((x = cmkey(ftptyp,nftptyp,"","",xxstring)) < 0)
8546           return(x);
8547         if ((y = cmcfm()) < 0) return(y);
8548         CHECKCONN();
8549         ftp_typ = x;
8550         g_ftp_typ = x;
8551         tenex = (ftp_typ == FTT_TEN);
8552         changetype(ftp_typ,ftp_vbm);
8553         return(1);
8554 
8555       case FTP_CHK:                     /* Check if remote file(s) exist(s) */
8556         if ((x = cmtxt("remote filename", "", &s, xxstring)) < 0)
8557           return(x);
8558         CHECKCONN();
8559         success = remote_files(1,(CHAR *)s,(CHAR *)s,0) ? 1 : 0;
8560         return(success);
8561 
8562       case FTP_FEA:                     /* RFC2389 */
8563         if ((y = cmcfm()) < 0)
8564           return(y);
8565         CHECKCONN();
8566 	success = (ftpcmd("FEAT",NULL,0,0,1) == REPLY_COMPLETE);
8567 	if (success) {
8568 	    if (sfttab[0] > 0) {
8569 		ftp_aut = sfttab[SFT_AUTH];
8570 		sizeok  = sfttab[SFT_SIZE];
8571 		mdtmok  = sfttab[SFT_MDTM];
8572 		mlstok  = sfttab[SFT_MLST];
8573 	    }
8574 	}
8575 	return(success);
8576 
8577       case FTP_OPT:                     /* RFC2389 */
8578         /* Perhaps this should be a keyword list... */
8579         if ((x = cmfld("FTP command","",&s,xxstring)) < 0)
8580           return(x);
8581         CHECKCONN();
8582         ckstrncpy(line,s,LINBUFSIZ);
8583         if ((x = cmtxt("Options for this command", "", &s, xxstring)) < 0)
8584           return(x);
8585         success = (ftpcmd("OPTS",line,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
8586         return(success);
8587 
8588       case FTP_ENA:			/* FTP ENABLE */
8589       case FTP_DIS:			/* FTP DISABLE */
8590         if ((x = cmkey(ftpenatab,nftpena,"","",xxstring)) < 0)
8591           return(x);
8592         if ((y = cmcfm()) < 0) return(y);
8593 	switch (x) {
8594 	  case ENA_AUTH:		/* OK to use autoauthentication */
8595 	    ftp_aut = (cx == FTP_ENA) ? 1 : 0;
8596 	    sfttab[SFT_AUTH] = ftp_aut;
8597 	    break;
8598 	  case ENA_FEAT:		/* OK to send FEAT command */
8599 	    featok = (cx == FTP_ENA) ? 1 : 0;
8600 	    break;
8601 	  case ENA_MLST:		/* OK to use MLST/MLSD */
8602 	    mlstok = (cx == FTP_ENA) ? 1 : 0;
8603 	    sfttab[SFT_MLST] = mlstok;
8604 	    break;
8605 	  case ENA_MDTM:		/* OK to use MDTM */
8606 	    mdtmok = (cx == FTP_ENA) ? 1 : 0;
8607 	    sfttab[SFT_MDTM] = mdtmok;
8608 	    break;
8609 	  case ENA_SIZE:		/* OK to use SIZE */
8610 	    sizeok = (cx == FTP_ENA) ? 1 : 0;
8611 	    sfttab[SFT_SIZE] = sizeok;
8612 	    break;
8613 	}
8614 	return(success = 1);
8615     }
8616     return(-2);
8617 }
8618 
8619 #ifndef NOSHOW
8620 static char *
shopl(x)8621 shopl(x) int x; {
8622     switch (x) {
8623       case FPL_CLR: return("clear");
8624       case FPL_PRV: return("private");
8625       case FPL_SAF: return("safe");
8626       case 0:  return("(not set)");
8627       default: return("(unknown)");
8628     }
8629 }
8630 
8631 int
shoftp(brief)8632 shoftp(brief) int brief; {
8633     char * s = "?";
8634     int n, x;
8635 
8636     if (g_ftp_typ > -1) {               /* Restore TYPE if saved */
8637         ftp_typ = g_ftp_typ;
8638         /* g_ftp_typ = -1; */
8639     }
8640     printf("\n");
8641     printf("FTP connection:                 %s\n",connected ?
8642            ftp_host :
8643            "(none)"
8644            );
8645     n = 2;
8646     if (connected) {
8647         n++;
8648         printf("FTP server type:                %s\n",
8649                ftp_srvtyp[0] ? ftp_srvtyp : "(unknown)");
8650     }
8651     if (loggedin)
8652       printf("Logged in as:                   %s\n",
8653              strval(ftp_logname,"(unknown)"));
8654     else
8655       printf("Not logged in\n");
8656     n++;
8657     if (brief) return(0);
8658 
8659     printf("\nSET FTP values:\n\n");
8660     n += 3;
8661 
8662     printf(" ftp anonymous-password:        %s\n",
8663 	   ftp_apw ? ftp_apw : "(default)"
8664 	   );
8665     printf(" ftp auto-login:                %s\n",showoff(ftp_log));
8666     printf(" ftp auto-authentication:       %s\n",showoff(ftp_aut));
8667     switch (ftp_typ) {
8668       case FTT_ASC: s = "text"; break;
8669       case FTT_BIN: s = "binary"; break;
8670       case FTT_TEN: s = "tenex"; break;
8671     }
8672 #ifdef FTP_TIMEOUT
8673     printf(" ftp timeout:                   %ld\n",ftp_timeout);
8674 #endif	/* FTP_TIMEOUT */
8675     printf(" ftp type:                      %s\n",s);
8676     printf(" ftp get-filetype-switching:    %s\n",showoff(get_auto));
8677     printf(" ftp dates:                     %s\n",showoff(ftp_dates));
8678     printf(" ftp error-action:              %s\n",ftp_err ? "quit":"proceed");
8679     printf(" ftp filenames:                 %s\n",
8680            ftp_cnv == CNV_AUTO ? "auto" : (ftp_cnv ? "converted" : "literal")
8681            );
8682     printf(" ftp debug                      %s\n",showoff(ftp_deb));
8683 
8684     printf(" ftp passive-mode:              %s\n",showoff(ftp_psv));
8685     printf(" ftp permissions:               %s\n",showooa(ftp_prm));
8686     printf(" ftp verbose-mode:              %s\n",showoff(ftp_vbx));
8687     printf(" ftp send-port-commands:        %s\n",showoff(ftp_psv));
8688     printf(" ftp unique-server-names:       %s\n",showoff(ftp_usn));
8689 #ifdef COMMENT
8690     /* See note in doxftp() */
8691     if (ftp_fnc < 0)
8692       ftp_fnc = fncact;
8693 #endif /* COMMENT */
8694     printf(" ftp collision:                 %s\n",
8695 	   fncnam[ftp_fnc > -1 ? ftp_fnc : fncact]);
8696     printf(" ftp server-time-offset:        %s\n",
8697 	   fts_sto ? fts_sto : "(none)");
8698     n += 15;
8699 
8700 #ifndef NOCSETS
8701     printf(" ftp character-set-translation: %s\n",showoff(ftp_xla));
8702     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8703 
8704     printf(" ftp server-character-set:      %s\n",fcsinfo[ftp_csr].keyword);
8705     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8706 
8707     printf(" file character-set:            %s\n",fcsinfo[fcharset].keyword);
8708     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8709 #endif /* NOCSETS */
8710 
8711     x = ftp_dis;
8712     if (x < 0)
8713       x = fdispla;
8714     switch (x) {
8715       case XYFD_N: s = "none"; break;
8716       case XYFD_R: s = "serial"; break;
8717       case XYFD_C: s = "fullscreen"; break;
8718       case XYFD_S: s = "crt"; break;
8719       case XYFD_B: s = "brief"; break;
8720     }
8721     printf(" ftp display:                   %s\n",s);
8722     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8723 
8724     if (mlstok || featok || mdtmok || sizeok || ftp_aut) {
8725 	printf(" enabled:                      ");
8726 	if (ftp_aut) printf(" AUTH");
8727 	if (featok)  printf(" FEAT");
8728 	if (mdtmok)  printf(" MDTM");
8729 	if (mlstok)  printf(" MLST");
8730 	if (sizeok)  printf(" SIZE");
8731 	printf("\n");
8732 	if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8733     }
8734     if (!mlstok || !featok || !mdtmok || !sizeok || !ftp_aut) {
8735 	printf(" disabled:                     ");
8736 	if (!ftp_aut) printf(" AUTH");
8737 	if (!featok)  printf(" FEAT");
8738 	if (!mdtmok)  printf(" MDTM");
8739 	if (!mlstok)  printf(" MLST");
8740 	if (!sizeok)  printf(" SIZE");
8741 	printf("\n");
8742 	if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8743     }
8744     switch (ftpget) {
8745       case 0: s = "kermit"; break;
8746       case 1: s = "ftp"; break;
8747       case 2: s = "auto"; break;
8748       default: s = "?";
8749     }
8750     printf(" get-put-remote:                %s\n",s);
8751     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8752 
8753     printf("\n");
8754     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8755 
8756 #ifdef FTP_SECURITY
8757     printf("Available security methods:    ");
8758 #ifdef FTP_GSSAPI
8759     printf("GSSAPI ");
8760 #endif /* FTP_GSSAPI */
8761 #ifdef FTP_KRB4
8762     printf("Kerberos4 ");
8763 #endif /* FTP_KRB4 */
8764 #ifdef FTP_SRP
8765     printf("SRP ");
8766 #endif /* FTP_SRP */
8767 #ifdef FTP_SSL
8768     printf("SSL ");
8769 #endif /* FTP_SSL */
8770 
8771     n++;
8772     printf("\n\n");
8773     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8774     printf(" ftp authtype:                  %s\n",strval(auth_type,NULL));
8775     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8776     printf(" ftp auto-encryption:           %s\n",showoff(ftp_cry));
8777     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8778     printf(" ftp credential-forwarding:     %s\n",showoff(ftp_cfw));
8779     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8780     printf(" ftp command-protection-level:  %s\n",shopl(ftp_cpl));
8781     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8782     printf(" ftp data-protection-level:     %s\n",shopl(ftp_dpl));
8783     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8784     printf(" ftp secure proxy:              %s\n",shopl(ssl_ftp_proxy));
8785     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8786 #else
8787     printf("Available security methods:     (none)\n");
8788     if (++ n > cmd_rows-3) { if (!askmore()) return 0; else n = 0; }
8789 #endif /* FTP_SECURITY */
8790 
8791     if (n <= cmd_rows - 3)
8792       printf("\n");
8793     return(0);
8794 }
8795 #endif /* NOSHOW */
8796 
8797 #ifndef NOHELP
8798 /* FTP HELP text strings */
8799 
8800 static char * fhs_ftp[] = {
8801     "Syntax: FTP subcommand [ operands ]",
8802     "  Makes an FTP connection, or sends a command to the FTP server.",
8803     "  To see a list of available FTP subcommands, type \"ftp ?\".",
8804     "  and then use HELP FTP xxx to get help about subcommand xxx.",
8805     "  Also see HELP SET FTP, HELP SET GET-PUT-REMOTE, and HELP FIREWALL.",
8806     ""
8807 };
8808 
8809 static char * fhs_acc[] = {             /* ACCOUNT */
8810     "Syntax: FTP ACCOUNT text",
8811     "  Sends an account designator to an FTP server that needs one.",
8812     "  Most FTP servers do not use accounts; some use them for other",
8813     "  other purposes, such as disk-access passwords.",
8814     ""
8815 };
8816 static char * fhs_app[] = {             /* APPEND */
8817     "Syntax: FTP APPEND filname",
8818     "  Equivalent to [ FTP ] PUT /APPEND.  See HELP FTP PUT.",
8819     ""
8820 };
8821 static char * fhs_cls[] = {             /* BYE, CLOSE */
8822     "Syntax: [ FTP ] BYE",
8823     "  Logs out from the FTP server and closes the FTP connection.",
8824     "  Also see HELP SET GET-PUT-REMOTE.  Synonym: [ FTP ] CLOSE.",
8825     ""
8826 };
8827 static char * fhs_cwd[] = {             /* CD, CWD */
8828     "Syntax: [ FTP ] CD directory",
8829     "  Asks the FTP server to change to the given directory.",
8830     "  Also see HELP SET GET-PUT-REMOTE.  Synonyms: [ FTP ] CWD, RCD, RCWD.",
8831     ""
8832 };
8833 static char * fhs_gup[] = {             /* CDUP, UP */
8834     "Syntax: FTP CDUP",
8835     "  Asks the FTP server to change to the parent directory of its current",
8836     "  directory.  Also see HELP SET GET-PUT-REMOTE.  Synonym: FTP UP.",
8837     ""
8838 };
8839 static char * fhs_chm[] = {             /* CHMOD */
8840     "Syntax: FTP CHMOD filename permissions",
8841     "  Asks the FTP server to change the permissions, protection, or mode of",
8842     "  the given file.  The given permissions must be in the syntax of the",
8843     "  the server's file system, e.g. an octal number for UNIX.  Also see",
8844     "  FTP PUT /PERMISSIONS",
8845     ""
8846 };
8847 static char * fhs_mde[] = {             /* DELETE */
8848     "Syntax: FTP DELETE [ switches ] filespec",
8849     "  Asks the FTP server to delete the given file or files.",
8850     "  Synonym: MDELETE (Kermit makes no distinction between single and",
8851     "  multiple file deletion).  Optional switches:",
8852     " ",
8853     "  /ERROR-ACTION:{PROCEED,QUIT}",
8854     "  /EXCEPT:pattern",
8855     "  /FILENAMES:{AUTO,CONVERTED,LITERAL}",
8856     "  /LARGER-THAN:number",
8857 #ifdef UNIXOROSK
8858     "  /NODOTFILES",
8859 #endif /* UNIXOROSK */
8860     "  /QUIET",
8861 #ifdef RECURSIVE
8862     "  /RECURSIVE (depends on server)",
8863     "  /SUBDIRECTORIES",
8864 #endif /* RECURSIVE */
8865     "  /SMALLER-THAN:number",
8866     ""
8867 };
8868 static char * fhs_dir[] = {             /* DIRECTORY */
8869     "Syntax: FTP DIRECTORY [ filespec ]",
8870     "  Asks the server to send a directory listing of the files that match",
8871     "  the given filespec, or if none is given, all the files in its current",
8872     "  directory.  The filespec, including any wildcards, must be in the",
8873     "  syntax of the server's file system.  Also see HELP SET GET-PUT-REMOTE.",
8874     "  Synonym: RDIRECTORY.",
8875     ""
8876 };
8877 static char * fhs_vdi[] = {             /* VDIRECTORY */
8878     "Syntax: FTP VDIRECTORY [ filespec ]",
8879     "  Asks the server to send a directory listing of the files that match",
8880     "  the given filespec, or if none is given, all the files in its current",
8881     "  directory.  VDIRECTORY is needed for getting verbose directory",
8882     "  listings from certain FTP servers, such as on TOPS-20.  Try it if",
8883     "  FTP DIRECTORY lists only filenames without details.",
8884     ""
8885 };
8886 static char * fhs_fea[] = {             /* FEATURES */
8887     "Syntax: FTP FEATURES",
8888     "  Asks the FTP server to list its special features.  Most FTP servers",
8889     "  do not recognize this command.",
8890     ""
8891 };
8892 static char * fhs_mge[] = {             /* MGET */
8893     "Syntax: [ FTP ] MGET [ options ] filespec [ filespec [ filespec ... ] ]",
8894     "  Download a single file or multiple files.  Asks the FTP server to send",
8895     "  the given file or files.  Also see FTP GET.  Optional switches:",
8896     " ",
8897     "  /AS-NAME:text",
8898     "    Name under which to store incoming file.",
8899     "    Pattern required for for multiple files.",
8900     "  /BINARY",                        /* /IMAGE */
8901     "    Force binary mode.  Synonym: /IMAGE.",
8902     "  /COLLISION:{BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE}",
8903    "    What to do if an incoming file has the same name as an existing file.",
8904 
8905 #ifdef PUTPIPE
8906     "  /COMMAND",
8907     "    Specifies that the as-name is a command to which the incoming file",
8908     "    is to be piped as standard input.",
8909 #endif /* PUTPIPE */
8910 
8911 #ifdef DOUPDATE
8912     "  /DATES-DIFFER",
8913     "    Download only those files whose modification date-times differ from",
8914     "    those of the corresponding local files, or that do not already",
8915     "    exist on the local computer.",
8916 #endif /* DOUPDATE */
8917 
8918     "  /DELETE",
8919     "    Specifies that each file is to be deleted from the server after,",
8920     "    and only if, it is successfully downloaded.",
8921     "  /ERROR-ACTION:{PROCEED,QUIT}",
8922     "    When downloading a group of files, what to do upon failure to",
8923     "    transfer a file: quit or proceed to the next one.",
8924     "  /EXCEPT:pattern",
8925     "    Exception list: don't download any files that match this pattern.",
8926     "    See HELP WILDCARD for pattern syntax.",
8927     "  /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
8928     "    Whether to convert incoming filenames to local syntax.",
8929 #ifdef PIPESEND
8930 #ifndef NOSPL
8931     "  /FILTER:command",
8932     "    Pass incoming files through the given command.",
8933 #endif /* NOSPL */
8934 #endif /* PIPESEND */
8935     "  /LARGER-THAN:number",
8936     "    Only download files that are larger than the given number of bytes.",
8937     "  /LISTFILE:filename",
8938     "    Obtain the list of files to download from the given file.",
8939 #ifndef NOCSETS
8940     "  /LOCAL-CHARACTER-SET:name",
8941     "    When downloading in text mode and character-set conversion is",
8942     "    desired, this specifies the target set.",
8943 #endif /* NOCSETS */
8944     "  /MATCH:pattern",
8945     "    Specifies a pattern to be used to select filenames locally from the",
8946     "    server's list.",
8947     "  /MLSD",
8948     "    Forces sending of MLSD (rather than NLST) to get the file list.",
8949 #ifdef CK_TMPDIR
8950     "  /MOVE-TO:directory",
8951     "    Each file that is downloaded is to be moved to the given local",
8952     "    directory immediately after, and only if, it has been received",
8953     "    successfully.",
8954 #endif /* CK_TMPDIR */
8955     "  /NAMELIST:filename",
8956     "    Instead of downloading the files, stores the list of files that",
8957     "    would be downloaded in the given local file, one filename per line.",
8958     "  /NLST",
8959     "    Forces sending of NLST (rather than MLSD) to get the file list.",
8960     "  /NOBACKUPFILES",
8961     "    Don't download any files whose names end with .~<number>~.",
8962     "  /NODOTFILES",
8963     "    Don't download any files whose names begin with period (.).",
8964     "  /QUIET",
8965     "    Suppress the file-transfer display.",
8966 #ifdef FTP_RESTART
8967     "  /RECOVER",                       /* /RESTART */
8968     "    Resume a download that was previously interrupted from the point of",
8969     "    failure.  Works only in binary mode.  Not supported by all servers.",
8970     "    Synonym: /RESTART.",
8971 #endif /* FTP_RESTART */
8972 #ifdef RECURSIVE
8973     "  /RECURSIVE",                     /* /SUBDIRECTORIES */
8974     "    Create subdirectories automatically if the server sends files",
8975     "    recursively and includes pathnames (most don't).",
8976 #endif /* RECURSIVE */
8977     "  /RENAME-TO:text",
8978     "    Each file that is downloaded is to be renamed as indicated just,",
8979     "    after, and only if, it has arrived successfully.",
8980 #ifndef NOCSETS
8981     "  /SERVER-CHARACTER-SET:name",
8982     "    When downloading in text mode and character-set conversion is desired"
8983 ,   "    this specifies the original file's character set on the server.",
8984 #endif /* NOCSETS */
8985     "  /SERVER-RENAME:text",
8986     "    Each server source file is to be renamed on the server as indicated",
8987     "    immediately after, but only if, it has arrived successfully.",
8988     "  /SMALLER-THAN:number",
8989     "    Download only those files smaller than the given number of bytes.",
8990     "  /TEXT",                          /* /ASCII */
8991     "    Force text mode.  Synonym: /ASCII.",
8992     "  /TENEX",
8993     "    Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
8994 #ifndef NOCSETS
8995     "  /TRANSPARENT",
8996     "    When downloading in text mode, do not convert chracter-sets.",
8997 #endif /* NOCSETS */
8998     "  /TO-SCREEN",
8999     "    The downloaded file is to be displayed on the screen.",
9000 #ifdef DOUPDATE
9001     "  /UPDATE",
9002     "    Equivalent to /COLLISION:UPDATE.  Download only those files that are",
9003     "    newer than than their local counterparts, or that do not exist on",
9004     "    the local computer.",
9005 #endif /* DOUPDATE */
9006     ""
9007 };
9008 static char * fhs_hlp[] = {             /* HELP */
9009     "Syntax: FTP HELP [ command [ subcommand... ] ]",
9010     "  Asks the FTP server for help about the given command.  First use",
9011     "  FTP HELP by itself to get a list of commands, then use HELP FTP xxx",
9012     "  to get help for command \"xxx\".  Synonyms: REMOTE HELP, RHELP.",
9013     ""
9014 };
9015 static char * fhs_idl[] = {             /* IDLE */
9016     "Syntax: FTP IDLE [ number ]",
9017     "  If given without a number, this asks the FTP server to tell its",
9018     "  current idle-time limit.  If given with a number, it asks the server",
9019     "  to change its idle-time limit to the given number of seconds.",
9020     ""
9021 };
9022 static char * fhs_usr[] = {             /* USER, LOGIN */
9023     "Syntax: FTP USER username [ password [ account ] ]",
9024     "  Log in to the FTP server.  To be used when connected but not yet",
9025     "  logged in, e.g. when SET FTP AUTOLOGIN is OFF or autologin failed.",
9026     "  If you omit the password, and one is required by the server, you are",
9027     "  prompted for it.  If you omit the account, no account is sent.",
9028     "  Synonym: FTP LOGIN.",
9029     ""
9030 };
9031 static char * fhs_get[] = {             /* GET */
9032     "Syntax: [ FTP ] GET [ options ] filename [ as-name ]",
9033     "  Download a single file.  Asks the FTP server to send the given file.",
9034     "  The optional as-name is the name to store it under when it arrives;",
9035     "  if omitted, the file is stored with the name it arrived with, as",
9036     "  modified according to the FTP FILENAMES setting or /FILENAMES: switch",
9037     "  value.  Aside from the file list and as-name, syntax and options are",
9038     "  the same as for FTP MGET, which is used for downloading multiple files."
9039 ,   ""
9040 };
9041 static char * fhs_mkd[] = {             /* MKDIR */
9042     "Syntax: FTP MKDIR directory",
9043     "  Asks the FTP server to create a directory with the given name,",
9044     "  which must be in the syntax of the server's file system.  Synonyms:",
9045     "  REMOTE MKDIR, RMKDIR.",
9046     ""
9047 };
9048 static char * fhs_mod[] = {             /* MODTIME */
9049     "Syntax: FTP MODTIME filename",
9050     "  Asks the FTP server to send the modification time of the given file,",
9051     "  to be displayed on the screen.  The date-time format is all numeric:",
9052     "  yyyymmddhhmmssxxx... (where xxx... is 0 or more digits indicating",
9053     "  fractions of seconds).",
9054     ""
9055 };
9056 static char * fhs_mpu[] = {             /* MPUT */
9057     "Syntax: [ FTP ] MPUT [ switches ] filespec [ filespec [ filespec ... ] ]",
9058     "  Uploads files.  Sends the given file or files to the FTP server.",
9059     "  Also see FTP PUT.  Optional switches are:",
9060     " ",
9061     "  /AFTER:date-time",
9062     "    Uploads only those files newer than the given date-time.",
9063     "    HELP DATE for info about date-time formats.  Synonym: /SINCE.",
9064 #ifdef PUTARRAY
9065     "  /ARRAY:array-designator",
9066     "    Tells Kermit to upload the contents of the given array, rather than",
9067     "    a file.",
9068 #endif /* PUTARRAY */
9069     "  /AS-NAME:text",
9070     "    Name under which to send files.",
9071     "    Pattern required for for multiple files.",
9072     "  /BEFORE:date-time",
9073     "    Upload only those files older than the given date-time.",
9074     "  /BINARY",
9075     "    Force binary mode.  Synonym: /IMAGE.",
9076 #ifdef PUTPIPE
9077     "  /COMMAND",
9078     "    Specifies that the filespec is a command whose standard output is",
9079     "    to be sent.",
9080 #endif /* PUTPIPE */
9081 
9082 #ifdef COMMENT
9083 #ifdef DOUPDATE
9084     "  /DATES-DIFFER",
9085     "    Upload only those files whose modification date-times differ from",
9086     "    those on the server, or that don't exist on the server at all.",
9087 #endif /* DOUPDATE */
9088 #endif /* COMMENT */
9089 
9090     "  /DELETE",
9091     "    Specifies that each source file is to be deleted after, and only if,",
9092     "    it is successfully uploaded.",
9093     "  /DOTFILES",
9094     "    Include files whose names begin with period (.).",
9095     "  /ERROR-ACTION:{PROCEED,QUIT}",
9096     "    When uploading a group of files, what to do upon failure to",
9097     "    transfer a file: quit or proceed to the next one.",
9098     "  /EXCEPT:pattern",
9099     "    Exception list: don't upload any files that match this pattern.",
9100     "    See HELP WILDCARD for pattern syntax.",
9101     "  /FILENAMES:{AUTOMATIC,CONVERTED,LITERAL}",
9102     "    Whether to convert outbound filenames to common syntax.",
9103 #ifdef PIPESEND
9104 #ifndef NOSPL
9105     "  /FILTER:command",
9106     "    Pass outbound files through the given command.",
9107 #endif /* NOSPL */
9108 #endif /* PIPESEND */
9109 #ifdef CKSYMLINK
9110     "  /FOLLOWINKS",
9111     "    Send files that are pointed to by symbolic links.",
9112     "  /NOFOLLOWINKS",
9113     "    Skip over symbolic links (default).",
9114 #endif /* CKSYMLINK */
9115     "  /LARGER-THAN:number",
9116     "    Only upload files that are larger than the given number of bytes.",
9117     "  /LISTFILE:filename",
9118     "    Obtain the list of files to upload from the given file.",
9119 #ifndef NOCSETS
9120     "  /LOCAL-CHARACTER-SET:name",
9121     "    When uploading in text mode and character-set conversion is",
9122     "    desired, this specifies the source-file character set.",
9123 #endif /* NOCSETS */
9124 #ifdef CK_TMPDIR
9125     "  /MOVE-TO:directory",
9126     "    Each source file that is uploaded is to be moved to the given local",
9127     "    directory when, and only if, the transfer is successful.",
9128 #endif /* CK_TMPDIR */
9129     "  /NOBACKUPFILES",
9130     "    Don't upload any files whose names end with .~<number>~.",
9131 #ifdef UNIXOROSK
9132     "  /NODOTFILES",
9133     "    Don't upload any files whose names begin with period (.).",
9134 #endif /* UNIXOROSK */
9135     "  /NOT-AFTER:date-time",
9136     "    Upload only files that are not newer than the given date-time",
9137     "  /NOT-BEFORE:date-time",
9138     "    Upload only files that are not older than the given date-time",
9139 #ifdef UNIX
9140     "  /PERMISSIONS",
9141     "    Ask the server to set the permissions of each file it receives",
9142     "    according to the source file's permissions.",
9143 #endif /* UNIX */
9144     "  /QUIET",
9145     "    Suppress the file-transfer display.",
9146 #ifdef FTP_RESTART
9147     "  /RECOVER",
9148     "    Resume an upload that was previously interrupted from the point of",
9149     "    failure.  Synonym: /RESTART.",
9150 #endif /* FTP_RESTART */
9151 #ifdef RECURSIVE
9152     "  /RECURSIVE",
9153     "    Send files from the given directory and all the directories beneath",
9154     "    it.  Synonym: /SUBDIRECTORIES.",
9155 #endif /* RECURSIVE */
9156     "  /RENAME-TO:text",
9157     "    Each source file that is uploaded is to be renamed on the local",
9158     "    local computer as indicated when and only if, the transfer completes",
9159     "    successfully.",
9160 #ifndef NOCSETS
9161     "  /SERVER-CHARACTER-SET:name",
9162     "    When uploading in text mode and character-set conversion is desired,",
9163     "    this specifies the character set to which the file should be",
9164     "    converted for storage on the server.",
9165 #endif /* NOCSETS */
9166     "  /SERVER-RENAME:text",
9167     "    Each file that is uploaded is to be renamed as indicated on the",
9168     "    server after, and only if, if arrives successfully.",
9169     "  /SIMULATE",
9170     "    Show which files would be sent without actually sending them.",
9171     "  /SMALLER-THAN:number",
9172     "    Upload only those files smaller than the given number of bytes.",
9173     "  /TEXT",
9174     "    Force text mode.  Synonym: /ASCII.",
9175     "  /TENEX",
9176     "    Force TENEX (TOPS-20) mode (see HELP SET FTP TYPE).",
9177 #ifndef NOCSETS
9178     "  /TRANSPARENT",
9179     "    When uploading in text mode, do not convert chracter-sets.",
9180 #endif /* NOCSETS */
9181     "  /TYPE:{TEXT,BINARY}",
9182     "    Upload only files of the given type.",
9183 #ifdef DOUPDATE
9184     "  /UPDATE",
9185     "    If a file of the same name exists on the server, upload only if",
9186     "    the local file is newer.",
9187 #endif /* DOUPDATE */
9188     "  /UNIQUE-SERVER-NAMES",
9189     "    Ask the server to compute new names for any incoming file that has",
9190     "    the same name as an existing file.",
9191     ""
9192 };
9193 static char * fhs_opn[] = {             /* OPEN */
9194 #ifdef CK_SSL
9195     "Syntax: FTP [ OPEN ] [ { /SSL, /TLS } ] hostname [ port ] [ switches ]",
9196     "  Opens a connection to the FTP server on the given host.  The default",
9197     "  TCP port is 21 (990 if SSL/TLS is used), but a different port number",
9198     "  can be supplied if necessary.  Optional switches are:",
9199 #else /* CK_SSL */
9200     "Syntax: FTP [ OPEN ] hostname [ port ] [ switches ]",
9201     "  Opens a connection to the FTP server on the given host.  The default",
9202     "  TCP port is 21, but a different port number can be supplied if",
9203     "  necessary.  Optional switches are:",
9204 #endif /* CK_SSL */
9205     " ",
9206     "  /ANONYMOUS",
9207     "    Logs you in anonymously.",
9208     "  /USER:text",
9209     "    Supplies the given text as your username.",
9210     "  /PASSWORD:text",
9211     "    Supplies the given text as your password.  If you include a username",
9212     "    but omit this switch and the server requires a password, you are",
9213     "    prompted for it.",
9214     "  /ACCOUNT:text",
9215     "    Supplies the given text as your account, if required by the server.",
9216     "  /ACTIVE",
9217     "    Forces an active (rather than passive) connection.",
9218     "  /PASSIVE",
9219     "    Forces a passive (rather than active) connection.",
9220     "  /NOINIT",
9221     "    Inhibits sending initial REST, STRU, and MODE commands, which are",
9222     "    well-known standard commands, but to which some servers react badly.",
9223     "  /NOLOGIN",
9224     "    Inhibits autologin for this connection only.",
9225     ""
9226 };
9227 static char * fhs_opt[] = {             /* OPTS, OPTIONS */
9228     "Syntax: FTP OPTIONS",
9229     "  Asks the FTP server to list its current options.  Advanced, new,",
9230     "  not supported by most FTP servers.",
9231     ""
9232 };
9233 static char * fhs_put[] = {             /* PUT, SEND */
9234     "Syntax: [ FTP ] PUT [ switches ] filespec [ as-name ]",
9235     "  Like FTP MPUT, but only one filespec is allowed, and if it is followed",
9236     "  by an additional field, this is interpreted as the name under which",
9237     "  to send the file or files.  See HELP FTP MPUT.",
9238     ""
9239 };
9240 static char * fhs_reput[] = {		/* REPUT, RESEND */
9241     "Syntax: [ FTP ] REPUT [ switches ] filespec [ as-name ]",
9242     "  Synonym for FTP PUT /RECOVER.  Recovers an interrupted binary-mode",
9243     "  upload from the point of failure if the FTP server supports recovery.",
9244     "  Synonym: [ FTP ] RESEND.  For details see HELP FTP MPUT.",
9245     ""
9246 };
9247 static char * fhs_pwd[] = {             /* PWD */
9248     "Syntax: FTP PWD",
9249     "  Asks the FTP server to reveal its current working directory.",
9250     "  Synonyms: REMOTE PWD, RPWD.",
9251     ""
9252 };
9253 static char * fhs_quo[] = {             /* QUOTE */
9254     "Syntax: FTP QUOTE text",
9255     "  Sends an FTP protocol command to the FTP server.  Use this command",
9256     "  for sending commands that Kermit might not support.",
9257     ""
9258 };
9259 static char * fhs_rge[] = {             /* REGET */
9260     "Syntax: FTP REGET",
9261     "  Synonym for FTP GET /RECOVER.",
9262     ""
9263 };
9264 static char * fhs_ren[] = {             /* RENAME */
9265     "Syntax: FTP RENAME name1 name1",
9266     "  Asks the FTP server to change the name of the file whose name is name1",
9267     "  and which resides in the FTP server's file system, to name2.  Works",
9268     "  only for single files; wildcards are not accepted.",
9269     ""
9270 };
9271 static char * fhs_res[] = {             /* RESET */
9272     "Syntax: FTP RESET",
9273     "  Asks the server to log out your session, terminating your access",
9274     "  rights, without closing the connection.",
9275     ""
9276 };
9277 static char * fhs_rmd[] = {             /* RMDIR */
9278     "Syntax: FTP RMDIR directory",
9279     "  Asks the FTP server to remove the directory whose name is given.",
9280     "  This usually requires the directory to be empty.  Synonyms: REMOTE",
9281     "  RMDIR, RRMDIR.",
9282     ""
9283 };
9284 static char * fhs_sit[] = {             /* SITE */
9285     "Syntax: FTP SITE text",
9286     "  Sends a site-specific command to the FTP server.",
9287     ""
9288 };
9289 static char * fhs_siz[] = {             /* SIZE */
9290     "Syntax: FTP SIZE filename",
9291     "  Asks the FTP server to send a numeric string representing the size",
9292     "  of the given file.",
9293     ""
9294 };
9295 static char * fhs_sta[] = {             /* STATUS */
9296     "Syntax: FTP STATUS [ filename ]",
9297     "  Asks the FTP server to report its status.  If a filename is given,",
9298     "  the FTP server should report details about the file.",
9299     ""
9300 };
9301 static char * fhs_sys[] = {             /* SYSTEM */
9302     "Syntax: FTP SYSTEM",
9303     "  Asks the FTP server to report its operating system type.",
9304     ""
9305 };
9306 static char * fhs_typ[] = {             /* TYPE */
9307     "Syntax: FTP TYPE { TEXT, BINARY, TENEX }",
9308     "  Puts the client and server in the indicated transfer mode.",
9309     "  ASCII is a synonym for TEXT.  TENEX is used only for uploading 8-bit",
9310     "  binary files to a 36-bit platforms such as TENEX or TOPS-20 and/or",
9311     "  downloading files from TENEX or TOPS-20 that have been uploaded in",
9312     "  TENEX mode.",
9313     ""
9314 };
9315 static char * fhs_uma[] = {             /* UMASK */
9316     "Syntax: FTP UMASK number",
9317     "  Asks the FTP server to set its file creation mode mask.  Applies",
9318     "  only (or mainly) to UNIX-based FTP servers.",
9319     ""
9320 };
9321 static char * fhs_chk[] = {             /* CHECK */
9322     "Syntax: FTP CHECK remote-filespec",
9323     "  Asks the FTP server if the given file or files exist.  If the",
9324     "  remote-filespec contains wildcards, this command fails if no server",
9325     "  files match, and succeeds if at least one file matches.  If the",
9326     "  remote-filespec does not contain wildcards, this command succeeds if",
9327     "  the given file exists and fails if it does not.",
9328     ""
9329 };
9330 static char * fhs_ena[] = {		/* ENABLE */
9331     "Syntax: FTP ENABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9332     "  Enables the use of the given FTP protocol command in case it has been",
9333     "  disabled (but this is no guarantee that the FTP server understands it)."
9334 ,
9335     "  Use SHOW FTP to see which of these commands is enabled and disabled.",
9336     "  Also see FTP DISABLE.",
9337     ""
9338 };
9339 static char * fhs_dis[] = {		/* DISABLE */
9340     "Syntax: FTP DISABLE { AUTH, FEAT, MDTM, MLST, SIZE }",
9341     "  Disables the use of the given FTP protocol command.",
9342     "  Also see FTP ENABLE.",
9343     ""
9344 };
9345 
9346 #endif /* NOHELP */
9347 
9348 int
doftphlp()9349 doftphlp() {
9350     int cx;
9351     if ((cx = cmkey(ftpcmdtab,nftpcmd,"","",xxstring)) < 0)
9352       if (cx != -3)
9353         return(cx);
9354     if ((x = cmcfm()) < 0)
9355       return(x);
9356 
9357 #ifdef NOHELP
9358     printf("Sorry, no help available\n");
9359 #else
9360     switch (cx) {
9361       case -3:
9362         return(hmsga(fhs_ftp));
9363       case FTP_ACC:                     /* ACCOUNT */
9364         return(hmsga(fhs_acc));
9365       case FTP_APP:                     /* APPEND */
9366         return(hmsga(fhs_app));
9367       case FTP_CLS:                     /* BYE, CLOSE */
9368         return(hmsga(fhs_cls));
9369       case FTP_CWD:                     /* CD, CWD */
9370         return(hmsga(fhs_cwd));
9371       case FTP_GUP:                     /* CDUP, UP */
9372         return(hmsga(fhs_gup));
9373       case FTP_CHM:                     /* CHMOD */
9374         return(hmsga(fhs_chm));
9375       case FTP_MDE:                     /* DELETE, MDELETE */
9376         return(hmsga(fhs_mde));
9377       case FTP_DIR:                     /* DIRECTORY */
9378         return(hmsga(fhs_dir));
9379       case FTP_VDI:                     /* VDIRECTORY */
9380         return(hmsga(fhs_vdi));
9381       case FTP_FEA:                     /* FEATURES */
9382         return(hmsga(fhs_fea));
9383       case FTP_GET:                     /* GET */
9384         return(hmsga(fhs_get));
9385       case FTP_HLP:                     /* HELP */
9386         return(hmsga(fhs_hlp));
9387       case FTP_IDL:                     /* IDLE */
9388         return(hmsga(fhs_idl));
9389       case FTP_USR:                     /* USER, LOGIN */
9390         return(hmsga(fhs_usr));
9391       case FTP_MGE:                     /* MGET */
9392         return(hmsga(fhs_mge));
9393       case FTP_MKD:                     /* MKDIR */
9394         return(hmsga(fhs_mkd));
9395       case FTP_MOD:                     /* MODTIME */
9396         return(hmsga(fhs_mod));
9397       case FTP_MPU:                     /* MPUT */
9398         return(hmsga(fhs_mpu));
9399       case FTP_OPN:                     /* OPEN */
9400         return(hmsga(fhs_opn));
9401       case FTP_OPT:                     /* OPTS, OPTIONS */
9402         return(hmsga(fhs_opt));
9403       case FTP_PUT:                     /* PUT, SEND */
9404         return(hmsga(fhs_put));
9405       case FTP_REP:                     /* REPUT, RESEND */
9406         return(hmsga(fhs_reput));
9407       case FTP_PWD:                     /* PWD */
9408         return(hmsga(fhs_pwd));
9409       case FTP_QUO:                     /* QUOTE */
9410         return(hmsga(fhs_quo));
9411       case FTP_RGE:                     /* REGET */
9412         return(hmsga(fhs_rge));
9413       case FTP_REN:                     /* RENAME */
9414         return(hmsga(fhs_ren));
9415       case FTP_RES:                     /* RESET */
9416         return(hmsga(fhs_res));
9417       case FTP_RMD:                     /* RMDIR */
9418         return(hmsga(fhs_rmd));
9419       case FTP_SIT:                     /* SITE */
9420         return(hmsga(fhs_sit));
9421       case FTP_SIZ:                     /* SIZE */
9422         return(hmsga(fhs_siz));
9423       case FTP_STA:                     /* STATUS */
9424         return(hmsga(fhs_sta));
9425       case FTP_SYS:                     /* SYSTEM */
9426         return(hmsga(fhs_sys));
9427       case FTP_TYP:                     /* TYPE */
9428         return(hmsga(fhs_typ));
9429       case FTP_UMA:                     /* UMASK */
9430         return(hmsga(fhs_uma));
9431       case FTP_CHK:                     /* CHECK */
9432         return(hmsga(fhs_chk));
9433       case FTP_ENA:
9434         return(hmsga(fhs_ena));
9435       case FTP_DIS:
9436         return(hmsga(fhs_dis));
9437       default:
9438         printf("Sorry, help available for this command.\n");
9439         break;
9440     }
9441 #endif /* NOHELP */
9442     return(success = 0);
9443 }
9444 
9445 int
dosetftphlp()9446 dosetftphlp() {
9447     int cx;
9448     if ((cx = cmkey(ftpset,nftpset,"","",xxstring)) < 0)
9449       if (cx != -3)
9450         return(cx);
9451     if (cx != -3)
9452       ckstrncpy(tmpbuf,atmbuf,TMPBUFSIZ);
9453     if ((x = cmcfm()) < 0)
9454       return(x);
9455 
9456 #ifdef NOHELP
9457     printf("Sorry, no help available\n");
9458 #else
9459     switch (cx) {
9460       case -3:
9461         printf("\nSyntax: SET FTP parameter value\n");
9462         printf("  Type \"help set ftp ?\" for a list of parameters.\n");
9463         printf("  Type \"help set ftp xxx\" for information about setting\n");
9464         printf("  parameter xxx.  Type \"show ftp\" for current values.\n\n");
9465         return(0);
9466 
9467       case FTS_BUG:
9468 	printf("\nSyntax: SET FTP BUG <name> {ON, OFF}\n");
9469 	printf(
9470 	    "  Activates a workaround for the named bug in the FTP server.\n");
9471 	printf("  Type SET FTP BUG ? for a list of names.\n");
9472 	printf("  For each bug, the default is OFF\n\n");
9473 	return(0);
9474 
9475 #ifdef FTP_SECURITY
9476       case FTS_ATP:                     /* "authtype" */
9477         printf("\nSyntax: SET FTP AUTHTYPE list\n");
9478         printf("  Specifies an ordered list of authentication methods to be\n"
9479                );
9480         printf("  when FTP AUTOAUTHENTICATION is ON.  The default list is:\n");
9481         printf("  GSSAPI-KRB5, SRP, KERBEROS_V4, TLS, SSL.\n\n");
9482         return(0);
9483 
9484       case FTS_AUT:                     /* "autoauthentication" */
9485         printf("\nSyntax:SET FTP AUTOAUTHENTICATION { ON, OFF }\n");
9486         printf("  Tells whether authentication should be negotiated by the\n");
9487         printf("  FTP OPEN command.  Default is ON.\n\n");
9488         break;
9489 
9490       case FTS_CRY:                     /* "autoencryption" */
9491         printf("\nSET FTP AUTOENCRYPTION { ON, OFF }\n");
9492         printf("  Tells whether encryption (privacy) should be negotiated\n");
9493         printf("  by the FTP OPEN command.  Default is ON.\n\n");
9494         break;
9495 #endif /* FTP_SECURITY */
9496 
9497       case FTS_LOG:                     /* "autologin" */
9498         printf("\nSET FTP AUTOLOGIN { ON, OFF }\n");
9499         printf("  Tells Kermit whether to try to log you in automatically\n");
9500         printf("  as part of the connection process.\n\n");
9501         break;
9502 
9503       case FTS_DIS:
9504         printf("\nSET FTP DISPLAY { BRIEF, FULLSCREEN, CRT, ... }\n");
9505 	printf("  Chooses the file-transfer display style for FTP.\n");
9506         printf("  Like SET TRANSFER DISPLAY but applies only to FTP.\n\n");
9507         break;
9508 
9509 #ifndef NOCSETS
9510       case FTS_XLA:                     /* "character-set-translation" */
9511         printf("\nSET FTP CHARACTER-SET-TRANSLATION { ON, OFF }\n");
9512         printf("  Whether to translate character sets when transferring\n");
9513         printf("  text files with FTP.  OFF by default.\n\n");
9514         break;
9515 
9516 #endif /* NOCSETS */
9517       case FTS_FNC:                     /* "collision" */
9518         printf("\n");
9519         printf(
9520 "Syntax: SET FTP COLLISION { BACKUP,RENAME,UPDATE,DISCARD,APPEND,OVERWRITE }\n"
9521                );
9522         printf("  Tells what do when an incoming file has the same name as\n");
9523         printf("  an existing file when downloading with FTP.\n\n");
9524         break;
9525 
9526 #ifdef FTP_SECURITY
9527       case FTS_CPL:                     /* "command-protection-level" */
9528         printf("\n");
9529         printf(
9530 "Syntax: SET FTP COMMAND-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9531                );
9532         printf("\n");
9533         printf(
9534 "  Tells what level of protection is applied to the FTP command channel.\n\n");
9535         break;
9536       case FTS_CFW:                     /* "credential-forwarding" */
9537         printf("\nSyntax: SET FTP CREDENTIAL-FORWARDING { ON, OFF }\n");
9538         printf("  Tells whether end-user credentials are to be forwarded\n");
9539         printf("  to the server if supported by the authentication method\n");
9540         printf("  (GSSAPI-KRB5 only).\n\n");
9541         break;
9542       case FTS_DPL:                     /* "data-protection-level" */
9543         printf("\n");
9544         printf(
9545 "Syntax: SET FTP DATA-PROTECTION-LEVEL { CLEAR,CONFIDENTIAL,PRIVATE,SAFE }"
9546                );
9547         printf("\n");
9548         printf(
9549 "  Tells what level of protection is applied to the FTP data channel.\n\n");
9550         break;
9551 #endif /* FTP_SECURITY */
9552 
9553       case FTS_DBG:                     /* "debug" */
9554         printf("\nSyntax: SET FTP DEBUG { ON, OFF }\n");
9555         printf("  Whether to print FTP protocol messages.\n\n");
9556         return(0);
9557 
9558       case FTS_ERR:                     /* "error-action" */
9559         printf("\nSyntax: SET FTP ERROR-ACTION { QUIT, PROCEED }\n");
9560         printf("  What to do when an error occurs when transferring a group\n")
9561           ;
9562         printf("  of files: quit and fail, or proceed to the next file.\n\n");
9563         return(0);
9564 
9565       case FTS_CNV:                     /* "filenames" */
9566         printf("\nSyntax: SET FTP FILENAMES { AUTO, CONVERTED, LITERAL }\n");
9567         printf("  What to do with filenames: convert them, take and use them\n"
9568                );
9569         printf("  literally; or choose what to do automatically based on the\n"
9570                );
9571         printf("  OS type of the server.  The default is AUTO.\n\n");
9572         return(0);
9573 
9574       case FTS_PSV:                     /* "passive-mode" */
9575         printf("\nSyntax: SET FTP PASSIVE-MODE { ON, OFF }\n");
9576         printf("  Whether to use passive mode, which helps to get through\n");
9577         printf("  firewalls.  ON by default.\n\n");
9578         return(0);
9579 
9580       case FTS_PRM:                     /* "permissions" */
9581         printf("\nSyntax: SET FTP PERMISSIONS { AUTO, ON, OFF }\n");
9582         printf("  Whether to try to send file permissions when uploading.\n");
9583         printf("  OFF by default.  AUTO means only if client and server\n");
9584         printf("  have the same OS type.\n\n");
9585         return(0);
9586 
9587       case FTS_TST:                     /* "progress-messages" */
9588         printf("\nSyntax: SET FTP PROGRESS-MESSAGES { ON, OFF }\n");
9589         printf("  Whether Kermit should print locally-generated feedback\n");
9590         printf("  messages for each non-file-transfer command.");
9591         printf("  ON by default.\n\n");
9592         return(0);
9593 
9594       case FTS_SPC:                     /* "send-port-commands" */
9595         printf("\nSyntax: SET FTP SEND-PORT-COMMANDS { ON, OFF }\n");
9596         printf("  Whether Kermit should send a new PORT command for each");
9597         printf("  task.\n\n");
9598         return(0);
9599 
9600 #ifndef NOCSETS
9601       case FTS_CSR:                     /* "server-character-set" */
9602         printf("\nSyntax: SET FTP SERVER-CHARACTER-SET name\n");
9603         printf("  The name of the character set used for text files on the\n");
9604         printf("  server.  Enter a name of '?' for a menu.\n\n");
9605         return(0);
9606 #endif /* NOCSETS */
9607 
9608       case FTS_STO:			/* "server-time-offset */
9609 	printf(
9610 "\nSyntax: SET FTP SERVER-TIME-OFFSET +hh[:mm[:ss]] or -hh[:mm[:ss]]\n");
9611         printf(
9612 "  Specifies an offset to apply to the server's file timestamps.\n");
9613         printf(
9614 "  Use this to correct for misconfigured server time or timezone.\n");
9615         printf(
9616 "  Format: must begin with + or - sign.  Hours must be given; minutes\n");
9617         printf(
9618 "  and seconds are optional: +4 = +4:00 = +4:00:00 (add 4 hours).\n\n");
9619         return(0);
9620 
9621       case FTS_TYP:                     /* "type" */
9622         printf("\nSyntax: SET FTP TYPE { TEXT, BINARY, TENEX }\n");
9623         printf("  Establishes the default transfer mode.\n");
9624         printf("  TENEX is used for uploading 8-bit binary files to 36-bit\n");
9625         printf("  platforms such as TENEX and TOPS-20 and for downloading\n");
9626         printf("  them again.  ASCII is a synonym for TEXT.  Normally each\n");
9627         printf("  file's type is determined automatically from its contents\n"
9628 	       );
9629         printf("  or its name; SET FTP TYPE does not prevent that, it only\n");
9630         printf("  tells which mode to use when the type can't be determined\n"
9631 	       );
9632         printf("  automatically.  To completely disable automatic transfer-\n"
9633 	       );
9634         printf("  mode switching and force either text or binary mode, give\n"
9635 	       );
9636         printf("  the top-level command ASCII or BINARY, as in traditional\n");
9637         printf("  FTP clients.\n\n");
9638         return(0);
9639 
9640 #ifdef FTP_TIMEOUT
9641       case FTS_TMO:
9642        printf("\nSyntax: SET FTP TIMEOUT number-of-seconds\n");
9643        printf("  Establishes a timeout for FTP transfers.\n");
9644        printf("  The timeout applies per network read or write on the data\n");
9645        printf("  connection, not to the whole transfer.  By default the\n");
9646        printf("  timeout value is 0, meaning no timeout.  Use a positive\n");
9647        printf("  number to escape gracefully from hung data connections or\n");
9648        printf("  directory listings.\n\n");
9649         return(0);
9650 #endif	/* FTP_TIMEOUT */
9651 
9652 #ifdef PATTERNS
9653       case FTS_GFT:
9654         printf("\nSyntax: SET FTP GET-FILETYPE-SWITCHING { ON, OFF }\n");
9655         printf("  Tells whether GET and MGET should automatically switch\n");
9656         printf("  the appropriate file type, TEXT, BINARY, or TENEX, by\n");
9657         printf("  matching the name of each incoming file with its list of\n");
9658         printf("  FILE TEXT-PATTERNS and FILE BINARY-PATTERNS.  ON by\n");
9659         printf("  default.  SHOW PATTERNS displays the current pattern\n");
9660         printf("  list.  HELP SET FILE to see how to change it.\n");
9661         break;
9662 #endif /* PATTERNS */
9663 
9664       case FTS_USN:                     /* "unique-server-names" */
9665         printf("\nSyntax: SET FTP UNIQUE-SERVER-NAMES { ON, OFF }\n");
9666         printf("  Tells whether to ask the server to create unique names\n");
9667         printf("  for any uploaded file that has the same name as an\n");
9668         printf("  existing file.  Default is OFF.\n\n");
9669         return(0);
9670 
9671       case FTS_VBM:                     /* "verbose-mode" */
9672         printf("\nSyntax: SET FTP VERBOSE-MODE { ON, OFF }\n");
9673         printf("  Whether to display all responses from the FTP server.\n");
9674         printf("  OFF by default.\n\n");
9675         return(0);
9676 
9677       case FTS_DAT:
9678         printf("\nSyntax: SET FTP DATES { ON, OFF }\n");
9679         printf("  Whether to set date of incoming files from the file date\n");
9680         printf("  on the server.  ON by default.  Note: there is no way to\n")
9681           ;
9682         printf("  set the date on files uploaded to the server.  Also note\n");
9683 	printf("  that not all servers support this feature.\n\n");
9684         return(0);
9685 
9686       case FTS_APW:
9687 	printf("\nSyntax: SET FTP ANONYMOUS-PASSWORD [ text ]\n");
9688 	printf("  Password to supply automatically on anonymous FTP\n");
9689 	printf("  connections instead of the default user@host.\n");
9690 	printf("  Omit optional text to restore default.\n\n");
9691 	return(0);
9692 
9693       default:
9694         printf("Sorry, help not available for \"set ftp %s\"\n",tmpbuf);
9695     }
9696 #endif /* NOHELP */
9697     return(0);
9698 }
9699 
9700 #ifndef L_SET
9701 #define L_SET 0
9702 #endif /* L_SET */
9703 #ifndef L_INCR
9704 #define L_INCR 1
9705 #endif /* L_INCR */
9706 
9707 #ifdef FTP_SRP
9708 char srp_user[BUFSIZ];                  /* where is BUFSIZ defined? */
9709 char *srp_pass;
9710 char *srp_acct;
9711 #endif /* FTP_SRP */
9712 
9713 static int kerror;                      /* Needed for all auth types */
9714 
9715 static struct   sockaddr_in hisctladdr;
9716 static struct   sockaddr_in hisdataaddr;
9717 static struct   sockaddr_in data_addr;
9718 static int      data = -1;
9719 static int      ptflag = 0;
9720 static struct   sockaddr_in myctladdr;
9721 
9722 #ifdef COMMENT
9723 #ifndef OS2
9724 UID_T getuid();
9725 #endif /* OS2 */
9726 #endif /* COMMENT */
9727 
9728 
9729 static int cpend = 0;                   /* No pending replies */
9730 
9731 #ifdef CK_SSL
9732 extern SSL *ssl_ftp_con;
9733 extern SSL_CTX *ssl_ftp_ctx;
9734 extern SSL *ssl_ftp_data_con;
9735 extern int ssl_ftp_active_flag;
9736 extern int ssl_ftp_data_active_flag;
9737 #endif /* CK_SSL */
9738 
9739 /*  f t p c m d  --  Send a command to the FTP server  */
9740 /*
9741   Call with:
9742     char * cmd: The command to send.
9743     char * arg: The argument (e.g. a filename).
9744     int lcs: The local character set index.
9745     int rcs: The remote (server) character set index.
9746     int vbm: Verbose mode:
9747       0 = force verbosity off
9748      >0 = force verbosity on
9749 
9750   If arg is given (not NULL or empty) and lcs != rcs and both are > -1,
9751   and neither lcs or rcs is UCS-2, the arg is translated from the local
9752   character set to the remote one before sending the result to the server.
9753 
9754    Returns:
9755     0 on failure with ftpcode = -1
9756     >= 0 on success (getreply() result) with ftpcode = 0.
9757 */
9758 static char xcmdbuf[RFNBUFSIZ];
9759 
9760 static int
ftpcmd(cmd,arg,lcs,rcs,vbm)9761 ftpcmd(cmd,arg,lcs,rcs,vbm) char * cmd, * arg; int lcs, rcs, vbm; {
9762     char * s = NULL;
9763     int r = 0, x = 0, fc = 0, len = 0, cmdlen = 0, q = -1;
9764     sig_t oldintr;
9765 
9766     if (ftp_deb)                        /* DEBUG */
9767       vbm = 1;
9768     else if (quiet || dpyactive)        /* QUIET or File Transfer Active */
9769       vbm = 0;
9770     else if (vbm < 0)                   /* VERBOSE */
9771       vbm = ftp_vbm;
9772 
9773     cancelfile = 0;
9774     if (!cmd) cmd = "";
9775     if (!arg) arg = "";
9776     cmdlen = (int)strlen(cmd);
9777     len = cmdlen + (int)strlen(arg) + 1;
9778 
9779     if (ftp_deb /* && !dpyactive */ ) {
9780 #ifdef FTP_PROXY
9781         if (ftp_prx) printf("%s ", ftp_host);
9782 #endif /* FTP_PROXY */
9783         printf("---> ");
9784         if (!anonymous && strcmp("PASS",cmd) == 0)
9785           printf("PASS XXXX");
9786         else
9787           printf("%s %s",cmd,arg);
9788         printf("\n");
9789     }
9790     /* bzero(xcmdbuf,RFNBUFSIZ); */
9791     ckmakmsg(xcmdbuf,RFNBUFSIZ, cmd, *arg ? " " : "", arg, NULL);
9792 
9793 #ifdef DEBUG
9794     if (deblog) {
9795         debug(F110,"ftpcmd cmd",cmd,0);
9796         debug(F110,"ftpcmd arg",arg,0);
9797         debug(F101,"ftpcmd lcs","",lcs);
9798         debug(F101,"ftpcmd rcs","",rcs);
9799     }
9800 #endif /* DEBUG */
9801 
9802     if (csocket == -1) {
9803         perror("No control connection for command");
9804         ftpcode = -1;
9805         return(0);
9806     }
9807     havesigint = 0;
9808     oldintr = signal(SIGINT, cmdcancel);
9809 
9810 #ifndef NOCSETS
9811     if (*arg &&                         /* If an arg was given */
9812         lcs > -1 &&                     /* and a local charset */
9813         rcs > -1 &&                     /* and a remote charset */
9814         lcs != rcs &&                   /* and the two are not the same */
9815         lcs != FC_UCS2 &&               /* and neither one is UCS-2 */
9816         rcs != FC_UCS2                  /* ... */
9817         ) {
9818         initxlate(lcs,rcs);             /* Translate arg from lcs to rcs */
9819         xgnbp = arg;                    /* Global pointer to input string */
9820         rfnptr = rfnbuf;                /* Global pointer to output buffer */
9821 
9822         while (1) {
9823             if ((c0 = xgnbyte(FC_UCS2,lcs,strgetc)) < 0) break;
9824             if (xpnbyte(c0,TC_UCS2,rcs,strputc) < 0) break;
9825         }
9826         /*
9827           We have to copy here instead of translating directly into
9828           xcmdbuf[] so strputc() can check length.  Alternatively we could
9829           write yet another xpnbyte() output function.
9830         */
9831         if ((int)strlen(rfnbuf) > (RFNBUFSIZ - (cmdlen+1))) {
9832             printf("?FTP command too long: %s + arg\n",cmd);
9833             ftpcode = -1;
9834             return(0);
9835         }
9836         x = ckstrncpy(&xcmdbuf[cmdlen+1], rfnbuf, RFNBUFSIZ - (cmdlen+1));
9837     }
9838 #endif /* NOCSETS */
9839 
9840     s = xcmdbuf;                        /* Command to send to server */
9841 
9842 #ifdef DEBUG
9843     if (deblog) {			/* Log it */
9844 	if (!anonymous && !ckstrcmp(s,"PASS ",5,0)) {
9845 	    /* But don't log passwords */
9846 	    debug(F110,"FTP SENT ","PASS XXXX",0);
9847 	} else {
9848 	    debug(F110,"FTP SENT ",s,0);
9849 	}
9850     }
9851 #endif /* DEBUG */
9852 
9853 #ifdef CK_ENCRYPTION
9854   again:
9855 #endif /* CK_ENCRYPTION */
9856     if (scommand(s) == 0) {              /* Send it. */
9857       signal(SIGINT, oldintr);
9858       return(0);
9859     }
9860     cpend = 1;
9861     x = !strcmp(cmd,"QUIT");		/* Is it the QUIT command? */
9862     if (x)				/* In case we're interrupted */
9863       connected = 0;			/* while waiting for the reply... */
9864 
9865     fc = 0;				/* Function code for getreply() */
9866     if (!strncmp(cmd,"AUTH ",5)		/* Must parse AUTH reply */
9867 #ifdef FTPHOST
9868 	&& strncmp(cmd, "HOST ",5)
9869 #endif /* FTPHOST */
9870 	) {
9871 	fc = GRF_AUTH;
9872     } else if (!ckstrcmp(cmd,"FEAT",-1,0)) { /* Must parse FEAT reply */
9873 	fc = GRF_FEAT;			/* But FEAT not widely understood */
9874 	if (!ftp_deb)			/* So suppress error messages */
9875 	  vbm = 9;
9876     }
9877     r = getreply(x,			/* Expect connection to close */
9878 		 lcs,rcs,		/* Charsets */
9879 		 vbm,			/* Verbosity */
9880 		 fc			/* Function code */
9881 		 );
9882     if (q > -1)
9883       quiet = q;
9884 
9885 #ifdef CK_ENCRYPTION
9886     if (ftpcode == 533 && ftp_cpl == FPL_PRV) {
9887         fprintf(stderr,
9888                "ENC command not supported at server; retrying under MIC...\n");
9889         ftp_cpl = FPL_SAF;
9890         goto again;
9891     }
9892 #endif /* CK_ENCRYPTION */
9893 #ifdef COMMENT
9894     if (cancelfile && oldintr != SIG_IGN)
9895       (*oldintr)(SIGINT);
9896 #endif /* COMMENT */
9897     signal(SIGINT, oldintr);
9898     return(r);
9899 }
9900 
9901 static VOID
lostpeer()9902 lostpeer() {
9903     debug(F100,"lostpeer","",0);
9904     if (connected) {
9905         if (csocket != -1) {
9906 #ifdef CK_SSL
9907             if (ssl_ftp_active_flag) {
9908                 SSL_shutdown(ssl_ftp_con);
9909                 SSL_free(ssl_ftp_con);
9910                 ssl_ftp_proxy = 0;
9911                 ssl_ftp_active_flag = 0;
9912                 ssl_ftp_con = NULL;
9913             }
9914 #endif /* CK_SSL */
9915 #ifdef TCPIPLIB
9916             socket_close(csocket);
9917 #else /* TCPIPLIB */
9918 #ifdef USE_SHUTDOWN
9919             shutdown(csocket, 1+1);
9920 #endif /* USE_SHUTDOWN */
9921             close(csocket);
9922 #endif /* TCPIPLIB */
9923             csocket = -1;
9924         }
9925         if (data != -1) {
9926 #ifdef CK_SSL
9927             if (ssl_ftp_data_active_flag) {
9928                 SSL_shutdown(ssl_ftp_data_con);
9929                 SSL_free(ssl_ftp_data_con);
9930                 ssl_ftp_data_active_flag = 0;
9931                 ssl_ftp_data_con = NULL;
9932             }
9933 #endif /* CK_SSL */
9934 #ifdef TCPIPLIB
9935             socket_close(data);
9936 #else /* TCPIPLIB */
9937 #ifdef USE_SHUTDOWN
9938             shutdown(data, 1+1);
9939 #endif /* USE_SHUTDOWN */
9940             close(data);
9941 #endif /* TCPIPLIB */
9942             data = -1;
9943             globaldin = -1;
9944         }
9945         connected = 0;
9946         anonymous = 0;
9947         loggedin = 0;
9948         auth_type = NULL;
9949         ftp_cpl = ftp_dpl = FPL_CLR;
9950 #ifdef CKLOGDIAL
9951         ftplogend();
9952 #endif /* CKLOGDIAL */
9953 
9954 #ifdef LOCUS
9955 	if (autolocus)			/* Auotomatic locus switching... */
9956 	  setlocus(1,1);		/* Switch locus to local. */
9957 #endif /* LOCUS */
9958 #ifdef OS2
9959         DialerSend(OPT_KERMIT_HANGUP, 0);
9960 #endif /* OS2 */
9961     }
9962 #ifdef FTP_PROXY
9963     pswitch(1);
9964     if (connected) {
9965         if (csocket != -1) {
9966 #ifdef TCPIPLIB
9967             socket_close(csocket);
9968 #else /* TCPIPLIB */
9969 #ifdef USE_SHUTDOWN
9970             shutdown(csocket, 1+1);
9971 #endif /* USE_SHUTDOWN */
9972             close(csocket);
9973 #endif /* TCPIPLIB */
9974             csocket = -1;
9975         }
9976         connected = 0;
9977         anonymous = 0;
9978         loggedin = 0;
9979         auth_type = NULL;
9980         ftp_cpl = ftp_dpl = FPL_CLR;
9981     }
9982     proxflag = 0;
9983     pswitch(0);
9984 #endif /* FTP_PROXY */
9985 }
9986 
9987 int
ftpisopen()9988 ftpisopen() {
9989     return(connected);
9990 }
9991 
9992 static int
ftpclose()9993 ftpclose() {
9994     extern int quitting;
9995     if (!connected)
9996       return(0);
9997     ftp_xfermode = xfermode;
9998     if (!ftp_vbm && !quiet)
9999       printlines = 1;
10000     ftpcmd("QUIT",NULL,0,0,ftp_vbm);
10001     if (csocket) {
10002 #ifdef CK_SSL
10003         if (ssl_ftp_active_flag) {
10004             SSL_shutdown(ssl_ftp_con);
10005             SSL_free(ssl_ftp_con);
10006             ssl_ftp_proxy = 0;
10007             ssl_ftp_active_flag = 0;
10008             ssl_ftp_con = NULL;
10009         }
10010 #endif /* CK_SSL */
10011 #ifdef TCPIPLIB
10012         socket_close(csocket);
10013 #else /* TCPIPLIB */
10014 #ifdef USE_SHUTDOWN
10015         shutdown(csocket, 1+1);
10016 #endif /* USE_SHUTDOWN */
10017         close(csocket);
10018 #endif /* TCPIPLIB */
10019     }
10020     csocket = -1;
10021     connected = 0;
10022     anonymous = 0;
10023     loggedin = 0;
10024     mdtmok = 1;
10025     sizeok = 1;
10026     featok = 1;
10027     stouarg = 1;
10028     typesent = 0;
10029     data = -1;
10030     globaldin = -1;
10031 #ifdef FTP_PROXY
10032     if (!proxy)
10033       macnum = 0;
10034 #endif /* FTP_PROXY */
10035     auth_type = NULL;
10036     ftp_dpl = FPL_CLR;
10037 #ifdef CKLOGDIAL
10038     ftplogend();
10039 #endif /* CKLOGDIAL */
10040 #ifdef LOCUS
10041     /* Unprefixed file management commands are executed locally */
10042     if (autolocus && !ftp_cmdlin && !quitting) {
10043         setlocus(1,1);
10044     }
10045 #endif /* LOCUS */
10046 #ifdef OS2
10047     DialerSend(OPT_KERMIT_HANGUP, 0);
10048 #endif /* OS2 */
10049     return(0);
10050 }
10051 
10052 int
ftpopen(remote,service,use_tls)10053 ftpopen(remote, service, use_tls) char * remote, * service; int use_tls; {
10054     char * host;
10055 
10056     if (connected) {
10057         printf("?Already connected to %s, use FTP CLOSE first.\n", ftp_host);
10058         ftpcode = -1;
10059         return(0);
10060     }
10061 #ifdef FTPHOST
10062     hostcmd = 0;
10063 #endif /* FTPHOST */
10064     alike = 0;
10065     ftp_srvtyp[0] = NUL;
10066     if (!service) service = "";
10067     if (!*service) service = use_tls ? "ftps" : "ftp";
10068 
10069     if (!isdigit(service[0])) {
10070         struct servent *destsp;
10071         destsp = getservbyname(service, "tcp");
10072         if (!destsp) {
10073             if (!ckstrcmp(service,"ftp",-1,0)) {
10074                 ftp_port = 21;
10075             } else if (!ckstrcmp(service,"ftps",-1,0)) {
10076                 ftp_port = 990;
10077             } else {
10078                 printf("?Bad port name - \"%s\"\n", service);
10079                 ftpcode = -1;
10080                 return(0);
10081             }
10082         } else {
10083             ftp_port = destsp->s_port;
10084             ftp_port = ntohs((unsigned short)ftp_port);	/* SMS 2007/02/15 */
10085         }
10086     } else
10087         ftp_port = atoi(service);
10088     if (ftp_port <= 0) {
10089         printf("?Bad port name - \"%s\"\n", service);
10090         ftpcode = -1;
10091         return(0);
10092     }
10093     host = ftp_hookup(remote, ftp_port, use_tls);
10094     if (host) {
10095         ckstrncpy(ftp_user_host,remote,MAX_DNS_NAMELEN);
10096         connected = 1;                  /* Set FTP defaults */
10097         ftp_cpl = ftp_dpl = FPL_CLR;
10098         curtype = FTT_ASC;              /* Server uses ASCII mode */
10099         form = FORM_N;
10100         mode = MODE_S;
10101         stru = STRU_F;
10102         strcpy(bytename, "8");
10103         bytesize = 8;
10104 
10105 #ifdef FTP_SECURITY
10106         if (ftp_aut) {
10107             if (ftp_auth()) {
10108                 if (ftp_cry
10109 #ifdef OS2
10110                      && ck_crypt_is_installed()
10111 #endif /* OS2 */
10112                      ) {
10113                     if (!quiet)
10114                       printf("FTP Command channel is Private (encrypted)\n");
10115                     ftp_cpl = FPL_PRV;
10116                     if (setpbsz(DEFAULT_PBSZ) < 0) {
10117                         /* a failure here is most likely caused by a mixup */
10118                         /* in the session key used by client and server    */
10119 			printf("?Protection buffer size negotiation failed\n");
10120                         return(0);
10121                     }
10122                     if (ftpcmd("PROT P",NULL,0,0,ftp_vbm) == REPLY_COMPLETE) {
10123                         if (!quiet)
10124                           printf("FTP Data channel is Private (encrypted)\n");
10125                         ftp_dpl = FPL_PRV;
10126                     } else
10127                       printf("?Unable to enable encryption on data channel\n");
10128                 } else {
10129                     ftp_cpl = FPL_SAF;
10130                 }
10131             }
10132             if (!connected)
10133 	      goto fail;
10134         }
10135 #endif /* FTP_SECURITY */
10136         if (ftp_log)			/* ^^^ */
10137           ftp_login(remote);
10138 
10139         if (!connected)
10140 	  goto fail;
10141 
10142 	ftp_xfermode = xfermode;
10143 
10144 #ifdef CKLOGDIAL
10145         dologftp();
10146 #endif /* CKLOGDIAL */
10147 #ifdef OS2
10148         DialerSend(OPT_KERMIT_CONNECT, 0);
10149 #endif /* OS2 */
10150         passivemode = ftp_psv;
10151         sendport = ftp_spc;
10152 	mdtmok = 1;
10153 	sizeok = 1;
10154 	stouarg = 1;
10155 	typesent = 0;
10156 
10157         if (ucbuf == NULL) {
10158             actualbuf = DEFAULT_PBSZ;
10159             while (actualbuf && (ucbuf = (CHAR *)malloc(actualbuf)) == NULL)
10160               actualbuf >>= 2;
10161         }
10162         if (!maxbuf)
10163           ucbufsiz = actualbuf - FUDGE_FACTOR;
10164 	debug(F101,"ftpopen ucbufsiz","",ucbufsiz);
10165         return(1);
10166     }
10167   fail:
10168     printf("?Can't FTP connect to %s:%s\n",remote,service);
10169     ftpcode = -1;
10170     return(0);
10171 }
10172 
10173 #ifdef CK_SSL
10174 int
ssl_auth()10175 ssl_auth() {
10176     int i;
10177     char* p;
10178     CONST SSL_METHOD *client_method;
10179 
10180     if (ssl_debug_flag) {
10181         fprintf(stderr,"SSL DEBUG ACTIVE\n");
10182         fflush(stderr);
10183         /* for the moment I want the output on screen */
10184     }
10185     if (ssl_ftp_data_con != NULL) {
10186         SSL_free(ssl_ftp_data_con);
10187         ssl_ftp_data_con = NULL;
10188     }
10189     if (ssl_ftp_con != NULL) {
10190         SSL_free(ssl_ftp_con);
10191         ssl_ftp_con=NULL;
10192     }
10193     if (ssl_ftp_ctx != NULL) {
10194         SSL_CTX_free(ssl_ftp_ctx);
10195         ssl_ftp_ctx = NULL;
10196     }
10197 
10198     /* The SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10199      * was added to OpenSSL 0.9.6e and 0.9.7.  It does not exist in previous
10200      * versions
10201      */
10202 #ifndef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
10203 #define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0L
10204 #endif
10205 /*
10206   Pick allowed SSL/TLS versions according to enabled bugs.
10207   Modified 5 Feb 2015 to default to TLS 1.0 if no bugs are enabled,
10208   instead of to SSL 3.0, which has the POODLE vulnerability.
10209 */
10210     if (ftp_bug_use_ssl_v2) {
10211         /* allow SSL 2.0 or later */
10212         client_method = SSLv23_client_method();
10213 #ifndef OPENSSL_NO_SSL3
10214     } else if (ftp_bug_use_ssl_v3) {
10215         /* allow SSL 3.0 ONLY - previous default */
10216         client_method = SSLv3_client_method();
10217 #endif /* OPENSSL_NO_SSL3 */
10218     } else {
10219         /* default - allow TLS 1.0 or later */
10220         client_method = TLSv1_client_method();
10221     }
10222     if (auth_type && !strcmp(auth_type,"TLS")) {
10223         ssl_ftp_ctx=SSL_CTX_new(client_method);
10224         if (!ssl_ftp_ctx)
10225           return(0);
10226         SSL_CTX_set_options(ssl_ftp_ctx,
10227                             SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10228                             );
10229     } else {
10230         ssl_ftp_ctx = SSL_CTX_new(client_method);
10231         if (!ssl_ftp_ctx)
10232           return(0);
10233         SSL_CTX_set_options(ssl_ftp_ctx,
10234                             (ftp_bug_use_ssl_v2 ? 0 : SSL_OP_NO_SSLv2)|
10235                             SSL_OP_SINGLE_DH_USE|SSL_OP_EPHEMERAL_RSA
10236                             );
10237     }
10238     SSL_CTX_set_default_passwd_cb(ssl_ftp_ctx,
10239                                   (pem_password_cb *)ssl_passwd_callback);
10240     SSL_CTX_set_info_callback(ssl_ftp_ctx,ssl_client_info_callback);
10241     SSL_CTX_set_session_cache_mode(ssl_ftp_ctx,SSL_SESS_CACHE_CLIENT);
10242 
10243 #ifdef OS2
10244 #ifdef NT
10245     /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10246     {
10247         char path[CKMAXPATH];
10248         extern char exedir[];
10249 
10250         ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10251         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
10252             debug(F110,"ftp ssl_auth unable to load path",path,0);
10253             if (ssl_debug_flag)
10254                 printf("?Unable to load verify-dir: %s\r\n",path);
10255         }
10256 
10257         ckmakmsg(path,CKMAXPATH,
10258                  (char *)GetAppData(1),"kermit 95/certs",NULL,NULL);
10259         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
10260             debug(F110,"ftp ssl_auth unable to load path",path,0);
10261             if (ssl_debug_flag)
10262                 printf("?Unable to load verify-dir: %s\r\n",path);
10263         }
10264 
10265         ckmakmsg(path,CKMAXPATH,
10266                  (char *)GetAppData(0),"kermit 95/certs",NULL,NULL);
10267         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
10268             debug(F110,"ftp ssl_auth unable to load path",path,0);
10269             if (ssl_debug_flag)
10270                 printf("?Unable to load verify-dir: %s\r\n",path);
10271         }
10272 
10273         ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10274         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10275             debug(F110,"ftp ssl_auth unable to load path",path,0);
10276             if (ssl_debug_flag)
10277                 printf("?Unable to load verify-file: %s\r\n",path);
10278         }
10279 
10280         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10281 		 "kermit 95/ca_certs.pem",NULL,NULL);
10282         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10283             debug(F110,"ftp ssl_auth unable to load path",path,0);
10284             if (ssl_debug_flag)
10285                 printf("?Unable to load verify-file: %s\r\n",path);
10286         }
10287 
10288         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10289 		 "kermit 95/ca_certs.pem",NULL,NULL);
10290         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10291             debug(F110,"ftp ssl_auth unable to load path",path,0);
10292             if (ssl_debug_flag)
10293                 printf("?Unable to load verify-file: %s\r\n",path);
10294         }
10295     }
10296 #else /* NT */
10297     /* The defaults in the SSL crypto library are not appropriate for OS/2 */
10298     {
10299 
10300         char path[CKMAXPATH];
10301         extern char exedir[];
10302 
10303         ckmakmsg(path,CKMAXPATH,exedir,"certs",NULL,NULL);
10304         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,path) == 0)  {
10305             debug(F110,"ftp ssl_auth unable to load path",path,0);
10306             if (ssl_debug_flag)
10307                 printf("?Unable to load verify-dir: %s\r\n",path);
10308         }
10309         ckmakmsg(path,CKMAXPATH,exedir,"ca_certs.pem",NULL,NULL);
10310         if (SSL_CTX_load_verify_locations(ssl_ftp_ctx,path,NULL) == 0) {
10311             debug(F110,"ftp ssl_auth unable to load path",path,0);
10312             if (ssl_debug_flag)
10313                 printf("?Unable to load verify-file: %s\r\n",path);
10314         }
10315     }
10316 #endif /* NT */
10317 #else /* OS2 */
10318     SSL_CTX_set_default_verify_paths(ssl_ftp_ctx);
10319 #endif /* OS2 */
10320 
10321     if (ssl_verify_file &&
10322         SSL_CTX_load_verify_locations(ssl_ftp_ctx,ssl_verify_file,NULL) == 0) {
10323         debug(F110,
10324               "ftp ssl auth unable to load ssl_verify_file",
10325               ssl_verify_file,
10326               0
10327               );
10328         if (ssl_debug_flag)
10329           printf("?Unable to load verify-file: %s\r\n",ssl_verify_file);
10330     }
10331     if (ssl_verify_dir &&
10332         SSL_CTX_load_verify_locations(ssl_ftp_ctx,NULL,ssl_verify_dir) == 0) {
10333         debug(F110,
10334               "ftp ssl auth unable to load ssl_verify_dir",
10335               ssl_verify_dir,
10336               0
10337               );
10338         if (ssl_debug_flag)
10339           printf("?Unable to load verify-dir: %s\r\n",ssl_verify_dir);
10340     }
10341 
10342     /* set up the new CRL Store */
10343     crl_store = (X509_STORE *)X509_STORE_new();
10344     if (crl_store) {
10345 #ifdef OS2
10346         char path[CKMAXPATH];
10347         extern char exedir[];
10348 
10349         ckmakmsg(path,CKMAXPATH,exedir,"crls",NULL,NULL);
10350         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10351             debug(F110,"ftp ssl auth unable to load dir",path,0);
10352             if (ssl_debug_flag)
10353                 printf("?Unable to load crl-dir: %s\r\n",path);
10354         }
10355 #ifdef NT
10356         ckmakmsg(path,CKMAXPATH,
10357 		 (char *)GetAppData(1),"kermit 95/crls",NULL,NULL);
10358         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10359             debug(F110,"ftp ssl auth unable to load dir",path,0);
10360             if (ssl_debug_flag)
10361                 printf("?Unable to load crl-dir: %s\r\n",path);
10362         }
10363         ckmakmsg(path,CKMAXPATH,
10364 		 (char *)GetAppData(0),"kermit 95/crls",NULL,NULL);
10365         if (X509_STORE_load_locations(crl_store,NULL,path) == 0) {
10366             debug(F110,"ftp ssl auth unable to load dir",path,0);
10367             if (ssl_debug_flag)
10368                 printf("?Unable to load crl-dir: %s\r\n",path);
10369         }
10370 #endif /* NT */
10371 
10372         ckmakmsg(path,CKMAXPATH,exedir,"ca_crls.pem",NULL,NULL);
10373         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10374             debug(F110,"ftp ssl auth unable to load file",path,0);
10375             if (ssl_debug_flag)
10376                 printf("?Unable to load crl-file: %s\r\n",path);
10377         }
10378 #ifdef NT
10379         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(1),
10380 		 "kermit 95/ca_crls.pem",NULL,NULL);
10381         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10382             debug(F110,"ftp ssl auth unable to load file",path,0);
10383             if (ssl_debug_flag)
10384                 printf("?Unable to load crl-file: %s\r\n",path);
10385         }
10386         ckmakmsg(path,CKMAXPATH,(char *)GetAppData(0),
10387 		 "kermit 95/ca_crls.pem",NULL,NULL);
10388         if (X509_STORE_load_locations(crl_store,path,NULL) == 0) {
10389             debug(F110,"ftp ssl auth unable to load file",path,0);
10390             if (ssl_debug_flag)
10391                 printf("?Unable to load crl-file: %s\r\n",path);
10392         }
10393 #endif /* NT */
10394 #endif /* OS2 */
10395 
10396         if (ssl_crl_file || ssl_crl_dir) {
10397             if (ssl_crl_file &&
10398                 X509_STORE_load_locations(crl_store,ssl_crl_file,NULL) == 0) {
10399                 debug(F110,
10400                       "ftp ssl auth unable to load ssl_crl_file",
10401                       ssl_crl_file,
10402                       0
10403                       );
10404                 if (ssl_debug_flag)
10405                   printf("?Unable to load crl-file: %s\r\n",ssl_crl_file);
10406             }
10407             if (ssl_crl_dir &&
10408                 X509_STORE_load_locations(crl_store,NULL,ssl_crl_dir) == 0) {
10409                 debug(F110,
10410                       "ftp ssl auth unable to load ssl_crl_dir",
10411                       ssl_crl_dir,
10412                       0
10413                       );
10414                 if (ssl_debug_flag)
10415                   printf("?Unable to load crl-dir: %s\r\n",ssl_crl_dir);
10416             }
10417         } else {
10418             X509_STORE_set_default_paths(crl_store);
10419         }
10420     }
10421     SSL_CTX_set_verify(ssl_ftp_ctx,ssl_verify_flag,
10422                        ssl_client_verify_callback);
10423     ssl_verify_depth = -1;
10424     ssl_ftp_con=(SSL *)SSL_new(ssl_ftp_ctx);
10425     tls_load_certs(ssl_ftp_ctx,ssl_ftp_con,0);
10426     SSL_set_fd(ssl_ftp_con,csocket);
10427     SSL_set_verify(ssl_ftp_con,ssl_verify_flag,NULL);
10428     if (ssl_cipher_list) {
10429         SSL_set_cipher_list(ssl_ftp_con,ssl_cipher_list);
10430     } else {
10431         char * p;
10432         if (p = getenv("SSL_CIPHER")) {
10433             SSL_set_cipher_list(ssl_ftp_con,p);
10434         } else {
10435             SSL_set_cipher_list(ssl_ftp_con,DEFAULT_CIPHER_LIST);
10436         }
10437     }
10438     if (ssl_debug_flag) {
10439         fprintf(stderr,"=>START SSL/TLS connect on COMMAND\n");
10440         fflush(stderr);
10441     }
10442     if (SSL_connect(ssl_ftp_con) <= 0) {
10443         static char errbuf[1024];
10444         ckmakmsg(errbuf,1024,"ftp: SSL/TLS connect COMMAND error: ",
10445                  ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
10446         fprintf(stderr,"%s\n", errbuf);
10447         fflush(stderr);
10448         ssl_ftp_active_flag=0;
10449         SSL_free(ssl_ftp_con);
10450         ssl_ftp_con = NULL;
10451     } else {
10452         ssl_ftp_active_flag = 1;
10453 
10454         if (!ssl_certsok_flag &&
10455 	    (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
10456 	    !tls_is_krb5(1)) {
10457             char *subject = ssl_get_subject_name(ssl_ftp_con);
10458 
10459             if (!subject) {
10460                 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
10461                     debug(F110,"ssl_auth","[SSL - FAILED]",0);
10462                     return(ssl_ftp_active_flag = 0);
10463                 } else {
10464                     if (uq_ok("Warning: Server didn't provide a certificate\n",
10465                                "Continue? (Y/N)",3,NULL,0) <= 0) {
10466                         debug(F110, "ssl_auth","[SSL - FAILED]",0);
10467                         return(ssl_ftp_active_flag = 0);
10468                     }
10469                 }
10470             } else if (ssl_check_server_name(ssl_ftp_con, ftp_user_host)) {
10471                 debug(F110,"ssl_auth","[SSL - FAILED]",0);
10472                 return(ssl_ftp_active_flag = 0);
10473             }
10474         }
10475         debug(F110,"ssl_auth","[SSL - OK]",0);
10476         ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
10477     }
10478     if (ssl_debug_flag) {
10479         fprintf(stderr,"=>DONE SSL/TLS connect on COMMAND\n");
10480         fflush(stderr);
10481     }
10482     return(ssl_ftp_active_flag);
10483 }
10484 #endif /* CK_SSL */
10485 
10486 static sigtype
cmdcancel(sig)10487 cmdcancel(sig) int sig; {
10488 #ifdef OS2
10489     /* In Unix we "chain" to trap(), which prints this */
10490     printf("^C...\n");
10491 #endif /* OS2 */
10492     debug(F100,"ftp cmdcancel caught SIGINT ","",0);
10493     fflush(stdout);
10494     secure_getc(0,1);			/* Initialize net input buffers */
10495     cancelfile++;
10496     cancelgroup++;
10497     mlsreset();
10498 #ifndef OS2
10499 #ifdef FTP_PROXY
10500     if (ptflag)                         /* proxy... */
10501       longjmp(ptcancel,1);
10502 #endif /* FTP_PROXY */
10503     debug(F100,"ftp cmdcancel chain to trap()...","",0);
10504     trap(SIGINT);
10505     /* NOTREACHED */
10506     debug(F100,"ftp cmdcancel return from trap()...","",0);
10507 #else
10508     debug(F100,"ftp cmdcancel PostCtrlCSem()...","",0);
10509     PostCtrlCSem();
10510 #endif /* OS2 */
10511 }
10512 
10513 static int
10514 #ifdef CK_ANSIC
scommand(char * s)10515 scommand(char * s)                      /* Was secure_command() */
10516 #else
10517 scommand(s) char * s;
10518 #endif /* CK_ANSIC */
10519 {
10520     int length = 0, len2;
10521     char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
10522 #ifdef CK_SSL
10523     if (ssl_ftp_active_flag) {
10524         int error, rc;
10525         length = strlen(s) + 2;
10526         length = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10527         rc = SSL_write(ssl_ftp_con,out,length);
10528         error = SSL_get_error(ssl_ftp_con,rc);
10529         switch (error) {
10530           case SSL_ERROR_NONE:
10531             return(1);
10532           case SSL_ERROR_WANT_WRITE:
10533           case SSL_ERROR_WANT_READ:
10534           case SSL_ERROR_SYSCALL:
10535 #ifdef NT
10536             {
10537                 int gle = GetLastError();
10538             }
10539 #endif /* NT */
10540           case SSL_ERROR_WANT_X509_LOOKUP:
10541           case SSL_ERROR_SSL:
10542           case SSL_ERROR_ZERO_RETURN:
10543           default:
10544             lostpeer();
10545         }
10546         return(0);
10547     }
10548 #endif /* CK_SSL */
10549 
10550     if (auth_type && ftp_cpl != FPL_CLR) {
10551 #ifdef FTP_SRP
10552         if (ck_srp_is_installed() && (strcmp(auth_type,"SRP") == 0))
10553           if ((length = srp_encode(ftp_cpl == FPL_PRV,
10554                                    (CHAR *)s,
10555                                    (CHAR *)out,
10556                                    strlen(s))) < 0) {
10557               fprintf(stderr, "SRP failed to encode message\n");
10558               return(0);
10559           }
10560 #endif /* FTP_SRP */
10561 #ifdef FTP_KRB4
10562         if (ck_krb4_is_installed() &&
10563             (strcmp(auth_type, "KERBEROS_V4") == 0)) {
10564             if (ftp_cpl == FPL_PRV) {
10565                 length =
10566                   krb_mk_priv((CHAR *)s, (CHAR *)out,
10567                               strlen(s), ftp_sched,
10568 #ifdef KRB524
10569                               ftp_cred.session,
10570 #else /* KRB524 */
10571                               &ftp_cred.session,
10572 #endif /* KRB524 */
10573                               &myctladdr, &hisctladdr);
10574             } else {
10575                 length =
10576                   krb_mk_safe((CHAR *)s,
10577                               (CHAR *)out,
10578                               strlen(s),
10579 #ifdef KRB524
10580                               ftp_cred.session,
10581 #else /* KRB524 */
10582                               &ftp_cred.session,
10583 #endif /* KRB524 */
10584                               &myctladdr, &hisctladdr);
10585             }
10586             if (length == -1) {
10587                 fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
10588                         ftp_cpl == FPL_PRV ? "priv" : "safe");
10589                 return(0);
10590             }
10591         }
10592 #endif /* FTP_KRB4 */
10593 #ifdef FTP_GSSAPI
10594         /* Scommand (based on level) */
10595         if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
10596             gss_buffer_desc in_buf, out_buf;
10597             OM_uint32 maj_stat, min_stat;
10598             int conf_state;
10599             in_buf.value = s;
10600             in_buf.length = strlen(s) + 1;
10601             maj_stat = gss_seal(&min_stat, gcontext,
10602                                 (ftp_cpl==FPL_PRV), /* private */
10603                                 GSS_C_QOP_DEFAULT,
10604                                 &in_buf, &conf_state,
10605                                 &out_buf);
10606             if (maj_stat != GSS_S_COMPLETE) { /* Generally need to deal */
10607                 user_gss_error(maj_stat, min_stat,
10608                                (ftp_cpl==FPL_PRV)?
10609                                "gss_seal ENC didn't complete":
10610                                "gss_seal MIC didn't complete");
10611             } else if ((ftp_cpl == FPL_PRV) && !conf_state) {
10612                 fprintf(stderr, "GSSAPI didn't encrypt message");
10613             } else {
10614                 if (ftp_deb)
10615                   fprintf(stderr, "sealed (%s) %d bytes\n",
10616                           ftp_cpl==FPL_PRV?"ENC":"MIC",
10617                           out_buf.length);
10618                 memcpy(out, out_buf.value,
10619                        length=out_buf.length);
10620                 gss_release_buffer(&min_stat, &out_buf);
10621             }
10622         }
10623 #endif /* FTP_GSSAPI */
10624         /* Other auth types go here ... */
10625 
10626         len2 = FTP_BUFSIZ;
10627         if ((kerror = radix_encode((CHAR *)out, (CHAR *)in,
10628                                    length, &len2, RADIX_ENCODE))
10629             ) {
10630             fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
10631                     radix_error(kerror));
10632             return(0);
10633         }
10634         if (ftp_deb)
10635           fprintf(stderr, "scommand(%s)\nencoding %d bytes\n", s, length);
10636         len2 = ckmakmsg(out,
10637 			FTP_BUFSIZ,
10638 			ftp_cpl == FPL_PRV ? "ENC " : "MIC ",
10639                         in,
10640 			"\r\n",
10641 			NULL
10642 			);
10643         send(csocket,(SENDARG2TYPE)out,len2,0);
10644     } else {
10645         char out[FTP_BUFSIZ];
10646         int len = ckmakmsg(out,FTP_BUFSIZ,s,"\r\n",NULL,NULL);
10647         send(csocket,(SENDARG2TYPE)out,len,0);
10648     }
10649     return(1);
10650 }
10651 
10652 static int
mygetc()10653 mygetc() {
10654     static char inbuf[4096];
10655     static int bp = 0, ep = 0;
10656     int rc;
10657 
10658     if (bp == ep) {
10659         bp = ep = 0;
10660 #ifdef CK_SSL
10661         if (ssl_ftp_active_flag) {
10662             int error;
10663             rc = SSL_read(ssl_ftp_con,inbuf,4096);
10664             error = SSL_get_error(ssl_ftp_con,rc);
10665             switch (error) {
10666               case SSL_ERROR_NONE:
10667                 break;
10668               case SSL_ERROR_WANT_WRITE:
10669               case SSL_ERROR_WANT_READ:
10670                 return(0);
10671               case SSL_ERROR_SYSCALL:
10672                 if (rc == 0) {          /* EOF */
10673                     break;
10674                 } else {
10675 #ifdef NT
10676                     int gle = GetLastError();
10677 #endif /* NT */
10678                     break;
10679                 }
10680               case SSL_ERROR_WANT_X509_LOOKUP:
10681               case SSL_ERROR_SSL:
10682               case SSL_ERROR_ZERO_RETURN:
10683               default:
10684                 break;
10685             }
10686         } else
10687 #endif /* CK_SSL */
10688           rc = recv(csocket,(char *)inbuf,4096,0);
10689         if (rc <= 0)
10690           return(EOF);
10691         ep = rc;
10692     }
10693     return(inbuf[bp++]);
10694 }
10695 
10696 /*  x l a t e c  --  Translate a character  */
10697 /*
10698     Call with:
10699       fc    = Function code: 0 = translate, 1 = initialize.
10700       c     = Character (as int).
10701       incs  = Index of charset to translate from.
10702       outcs = Index of charset to translate to.
10703 
10704     Returns:
10705       0: OK
10706      -1: Error
10707 */
10708 static int
xlatec(fc,c,incs,outcs)10709 xlatec(fc,c,incs,outcs) int fc, c, incs, outcs; {
10710 #ifdef NOCSETS
10711     return(c);
10712 #else
10713     static char buf[128];
10714     static int cx;
10715     int c0, c1;
10716 
10717     if (fc == 1) {                      /* Initialize */
10718         cx = 0;                         /* Catch-up buffer write index */
10719         xgnbp = buf;                    /* Catch-up buffer read pointer */
10720         buf[0] = NUL;                   /* Buffer is empty */
10721         return(0);
10722     }
10723     if (cx >= 127) {                    /* Catch-up buffer full */
10724         debug(F100,"xlatec overflow","",0); /* (shouldn't happen) */
10725         printf("?Translation buffer overflow\n");
10726         return(-1);
10727     }
10728     /* Add char to buffer. */
10729     /* The buffer won't grow unless incs is a multibyte set, e.g. UTF-8. */
10730 
10731     debug(F000,"xlatec buf",ckitoa(cx),c);
10732     buf[cx++] = c;
10733     buf[cx] = NUL;
10734 
10735     while ((c0 = xgnbyte(FC_UCS2,incs,strgetc)) > -1) {
10736         if (xpnbyte(c0,TC_UCS2,outcs,NULL) < 0)	/* (NULL was xprintc) */
10737           return(-1);
10738     }
10739     /* If we're caught up, reinitialize the buffer */
10740     return((cx == (xgnbp - buf)) ? xlatec(1,0,0,0) : 0);
10741 #endif /* NOCSETS */
10742 }
10743 
10744 
10745 /*  p a r s e f e a t  */
10746 
10747 /* Note: for convenience we align keyword values with table indices */
10748 /* If you need to insert a new keyword, adjust the SFT_xxx definitions */
10749 
10750 static struct keytab feattab[] = {
10751     { "$$$$", 0,        0 },		/* Dummy for sfttab[0] */
10752     { "AUTH", SFT_AUTH, 0 },
10753     { "LANG", SFT_LANG, 0 },
10754     { "MDTM", SFT_MDTM, 0 },
10755     { "MLST", SFT_MLST, 0 },
10756     { "PBSZ", SFT_PBSZ, 0 },
10757     { "PROT", SFT_PROT, 0 },
10758     { "REST", SFT_REST, 0 },
10759     { "SIZE", SFT_SIZE, 0 },
10760     { "TVFS", SFT_TVFS, 0 },
10761     { "UTF8", SFT_UTF8, 0 }
10762 };
10763 static int nfeattab = (sizeof(feattab) / sizeof(struct keytab));
10764 
10765 #define FACT_CSET  1
10766 #define FACT_CREA  2
10767 #define FACT_LANG  3
10768 #define FACT_MTYP  4
10769 #define FACT_MDTM  5
10770 #define FACT_PERM  6
10771 #define FACT_SIZE  7
10772 #define FACT_TYPE  8
10773 #define FACT_UNIQ  9
10774 
10775 static struct keytab facttab[] = {
10776     { "CHARSET",    FACT_CSET, 0 },
10777     { "CREATE",     FACT_CREA, 0 },
10778     { "LANG",       FACT_LANG, 0 },
10779     { "MEDIA-TYPE", FACT_MTYP, 0 },
10780     { "MODIFY",     FACT_MDTM, 0 },
10781     { "PERM",       FACT_PERM, 0 },
10782     { "SIZE",       FACT_SIZE, 0 },
10783     { "TYPE",       FACT_TYPE, 0 },
10784     { "UNIQUE",     FACT_UNIQ, 0 }
10785 };
10786 static int nfacttab = (sizeof(facttab) / sizeof(struct keytab));
10787 
10788 static struct keytab ftyptab[] = {
10789     { "CDIR", FTYP_CDIR, 0 },
10790     { "DIR",  FTYP_DIR,  0 },
10791     { "FILE", FTYP_FILE, 0 },
10792     { "PDIR", FTYP_PDIR, 0 }
10793 };
10794 static int nftyptab = (sizeof(ftyptab) / sizeof(struct keytab));
10795 
10796 static VOID
parsefeat(s)10797 parsefeat(s) char * s; {		/* Parse a FEATURE response */
10798     char kwbuf[8];
10799     int i, x;
10800     if (!s) return;
10801     if (!*s) return;
10802     while (*s < '!')
10803       s++;
10804     for (i = 0; i < 4; i++) {
10805 	if (s[i] < '!')
10806 	  break;
10807 	kwbuf[i] = s[i];
10808     }
10809     if (s[i] && s[i] != SP && s[i] != CR && s[i] != LF)
10810       return;
10811     kwbuf[i] = NUL;
10812     /* xlookup requires a full (but case independent) match */
10813     i = xlookup(feattab,kwbuf,nfeattab,&x);
10814     debug(F111,"ftp parsefeat",s,i);
10815     if (i < 0 || i > 15)
10816       return;
10817 
10818     switch (i) {
10819       case SFT_MDTM:			/* Controlled by ENABLE/DISABLE */
10820 	sfttab[i] = mdtmok;
10821 	if (mdtmok) sfttab[0]++;
10822 	break;
10823       case SFT_MLST:			/* ditto */
10824 	sfttab[i] = mlstok;
10825 	if (mlstok) sfttab[0]++;
10826 	break;
10827       case SFT_SIZE:			/* ditto */
10828 	sfttab[i] = sizeok;
10829 	if (sizeok) sfttab[0]++;
10830 	break;
10831       case SFT_AUTH:			/* ditto */
10832 	sfttab[i] = ftp_aut;
10833 	if (ftp_aut) sfttab[0]++;
10834 	break;
10835       default:				/* Others */
10836 	sfttab[0]++;
10837 	sfttab[i]++;
10838     }
10839 }
10840 
10841 static char *
parsefacts(s)10842 parsefacts(s) char * s; {		/* Parse MLS[DT] File Facts */
10843     char * p;
10844     int i, j, x;
10845     if (!s) return(NULL);
10846     if (!*s) return(NULL);
10847 
10848     /* Maybe we should make a copy of s so we can poke it... */
10849 
10850     while ((p = ckstrchr(s,'='))) {
10851 	*p = NUL;			/* s points to fact */
10852 	i = xlookup(facttab,s,nfacttab,&x);
10853 	debug(F111,"ftp parsefact fact",s,i);
10854 	*p = '=';
10855 	s = p+1;			/* Now s points to arg */
10856 	p = ckstrchr(s,';');
10857         if (!p)
10858 	  p = ckstrchr(s,SP);
10859 	if (!p) {
10860 	    debug(F110,"ftp parsefact end-of-val search fail",s,0);
10861 	    break;
10862 	}
10863 	*p = NUL;
10864 	debug(F110,"ftp parsefact valu",s,0);
10865 	switch (i) {
10866 	  case FACT_CSET:		/* Ignore these for now */
10867 	  case FACT_CREA:
10868 	  case FACT_LANG:
10869 	  case FACT_PERM:
10870 	  case FACT_MTYP:
10871 	  case FACT_UNIQ:
10872 	    break;
10873 	  case FACT_MDTM:		/* Modtime */
10874 	    makestr(&havemdtm,s);
10875 	    debug(F110,"ftp parsefact mdtm",havemdtm,0);
10876 	    break;
10877 	  case FACT_SIZE:		/* Size */
10878 	    havesize = ckatofs(s);
10879 	    debug(F101,"ftp parsefact size","",havesize);
10880 	    break;
10881 	  case FACT_TYPE:		/* Type */
10882 	    j = xlookup(ftyptab,s,nftyptab,NULL);
10883 	    debug(F111,"ftp parsefact type",s,j);
10884 	    havetype = (j < 1) ? 0 : j;
10885 	    break;
10886 	}
10887 	*p = ';';
10888 	s = p+1;			/* s points next fact or name */
10889     }
10890     while (*s == SP)			/* Skip past spaces. */
10891       s++;
10892     if (!*s)				/* Make sure we still have a name */
10893       s = NULL;
10894     debug(F110,"ftp parsefact name",s,0);
10895     return(s);
10896 }
10897 
10898 /*  g e t r e p l y  --  (to an FTP command sent to server)  */
10899 
10900 /* vbm = 1 (verbose); 0 (quiet except for error messages); 9 (super quiet) */
10901 
10902 static int
getreply(expecteof,lcs,rcs,vbm,fc)10903 getreply(expecteof,lcs,rcs,vbm,fc) int expecteof, lcs, rcs, vbm, fc; {
10904     /* lcs, rcs, vbm parameters as in ftpcmd() */
10905     register int i, c, n;
10906     register int dig;
10907     register char *cp;
10908     int xlate = 0;
10909     int count = 0;
10910     int auth = 0;
10911     int originalcode = 0, continuation = 0;
10912     sig_t oldintr;
10913     int pflag = 0;
10914     char *pt = pasv;
10915     char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ]; /* (these are pretty big...) */
10916     int safe = 0;
10917     int xquiet = 0;
10918 
10919     auth = (fc == GRF_AUTH);
10920 
10921 #ifndef NOCSETS
10922     debug(F101,"ftp getreply lcs","",lcs);
10923     debug(F101,"ftp getreply rcs","",rcs);
10924     if (lcs > -1 && rcs > -1 && lcs != rcs) {
10925         xlate = 1;
10926         initxlate(rcs,lcs);
10927         xlatec(1,0,rcs,lcs);
10928     }
10929 #endif /* NOCSETS */
10930     debug(F101,"ftp getreply fc","",fc);
10931 
10932     if (quiet)
10933       xquiet = 1;
10934     if (vbm == 9) {
10935         xquiet = 1;
10936         vbm = 0;
10937     }
10938     if (ftp_deb)                        /* DEBUG */
10939       vbm = 1;
10940     else if (quiet || dpyactive)        /* QUIET or File Transfer Active */
10941       vbm = 0;
10942     else if (vbm < 0)                   /* VERBOSE */
10943       vbm = ftp_vbm;
10944 
10945     ibuf[0] = '\0';
10946     if (reply_parse)
10947       reply_ptr = reply_buf;
10948     havesigint = 0;
10949     oldintr = signal(SIGINT, cmdcancel);
10950     for (count = 0;; count++) {
10951         obuf[0] = '\0';
10952         dig = n = ftpcode = i = 0;
10953         cp = ftp_reply_str;
10954         while ((c = ibuf[0] ? ibuf[i++] : mygetc()) != '\n') {
10955             if (c == IAC) {             /* Handle telnet commands */
10956                 switch (c = mygetc()) {
10957                   case WILL:
10958                   case WONT:
10959                     c = mygetc();
10960                     obuf[0] = IAC;
10961                     obuf[1] = DONT;
10962                     obuf[2] = c;
10963                     obuf[3] = NUL;
10964 #ifdef CK_SSL
10965                     if (ssl_ftp_active_flag) {
10966                         int error, rc;
10967                         rc = SSL_write(ssl_ftp_con,obuf,3);
10968                         error = SSL_get_error(ssl_ftp_con,rc);
10969                         switch (error) {
10970                           case SSL_ERROR_NONE:
10971                             break;
10972                           case SSL_ERROR_WANT_WRITE:
10973                           case SSL_ERROR_WANT_READ:
10974                             return(0);
10975                           case SSL_ERROR_SYSCALL:
10976                             if (rc == 0) { /* EOF */
10977                                 break;
10978                             } else {
10979 #ifdef NT
10980                                 int gle = GetLastError();
10981 #endif /* NT */
10982                                 break;
10983                             }
10984                           case SSL_ERROR_WANT_X509_LOOKUP:
10985                           case SSL_ERROR_SSL:
10986                           case SSL_ERROR_ZERO_RETURN:
10987                           default:
10988                             break;
10989                         }
10990                     } else
10991 #endif /* CK_SSL */
10992                       send(csocket,(SENDARG2TYPE)obuf,3,0);
10993                     break;
10994                   case DO:
10995                   case DONT:
10996                     c = mygetc();
10997                     obuf[0] = IAC;
10998                     obuf[1] = WONT;
10999                     obuf[2] = c;
11000                     obuf[3] = NUL;
11001 #ifdef CK_SSL
11002                     if (ssl_ftp_active_flag) {
11003                         int error, rc;
11004                         rc = SSL_write(ssl_ftp_con,obuf,3);
11005                         error = SSL_get_error(ssl_ftp_con,rc);
11006                         switch (error) {
11007                           case SSL_ERROR_NONE:
11008                             break;
11009                           case SSL_ERROR_WANT_WRITE:
11010                           case SSL_ERROR_WANT_READ:
11011                               signal(SIGINT,oldintr);
11012                               return(0);
11013                           case SSL_ERROR_SYSCALL:
11014                             if (rc == 0) { /* EOF */
11015                                 break;
11016                             } else {
11017 #ifdef NT
11018                                 int gle = GetLastError();
11019 #endif /* NT */
11020                                 break;
11021                             }
11022                           case SSL_ERROR_WANT_X509_LOOKUP:
11023                           case SSL_ERROR_SSL:
11024                           case SSL_ERROR_ZERO_RETURN:
11025                           default:
11026                             break;
11027                         }
11028                     } else
11029 #endif /* CK_SSL */
11030                       send(csocket,(SENDARG2TYPE)obuf,3,0);
11031                     break;
11032                   default:
11033                     break;
11034                 }
11035                 continue;
11036             }
11037             dig++;
11038             if (c == EOF) {
11039                 if (expecteof) {
11040                     signal(SIGINT,oldintr);
11041                     ftpcode = 221;
11042                     debug(F101,"ftp getreply EOF","",ftpcode);
11043                     return(0);
11044                 }
11045                 lostpeer();
11046                 if (!xquiet) {
11047                     if (ftp_deb)
11048                       printf("421 ");
11049                     printf(
11050                       "Service not available, connection closed by server\n");
11051                     fflush(stdout);
11052                 }
11053                 signal(SIGINT,oldintr);
11054                 ftpcode = 421;
11055                 debug(F101,"ftp getreply EOF","",ftpcode);
11056                 return(4);
11057             }
11058             if (n == 0) {		/* First digit */
11059 		n = c;			/* Save it */
11060 	    }
11061             if (auth_type &&
11062 #ifdef CK_SSL
11063                 !ssl_ftp_active_flag &&
11064 #endif /* CK_SSL */
11065                 !ibuf[0] && (n == '6' || continuation)) {
11066                 if (c != '\r' && dig > 4)
11067                   obuf[i++] = c;
11068             } else {
11069                 if (auth_type &&
11070 #ifdef CK_SSL
11071                     !ssl_ftp_active_flag &&
11072 #endif /* CK_SSL */
11073                     !ibuf[0] && dig == 1 && vbm)
11074                   printf("Unauthenticated reply received from server:\n");
11075                 if (reply_parse) {
11076                     *reply_ptr++ = c;
11077                     *reply_ptr = NUL;
11078                 }
11079                 if ((!dpyactive || ftp_deb) && /* Don't mess up xfer display */
11080                     ftp_cmdlin < 2) {
11081                     if ((c != '\r') &&
11082                         (ftp_deb || ((vbm || (!auth && n == '5')) &&
11083                         (dig > 4 || ( dig <= 4 && !isdigit(c) && ftpcode == 0
11084                         )))))
11085                     {
11086 #ifdef FTP_PROXY
11087                         if (ftp_prx && (dig == 1 || (dig == 5 && vbm == 0)))
11088                           printf("%s:",ftp_host);
11089 #endif /* FTP_PROXY */
11090 
11091                         if (!xquiet) {
11092 #ifdef NOCSETS
11093                             printf("%c",c);
11094 #else
11095                             if (xlate) {
11096                                 xlatec(0,c,rcs,lcs);
11097                             } else {
11098                                 printf("%c",c);
11099                             }
11100 #endif /* NOCSETS */
11101                         }
11102                     }
11103                 }
11104             }
11105             if (auth_type &&
11106 #ifdef CK_SSL
11107                 !ssl_ftp_active_flag &&
11108 #endif /* CK_SSL */
11109                 !ibuf[0] && n != '6')
11110               continue;
11111             if (dig < 4 && isdigit(c))
11112               ftpcode = ftpcode * 10 + (c - '0');
11113             if (!pflag && ftpcode == 227)
11114               pflag = 1;
11115             if (dig > 4 && pflag == 1 && isdigit(c))
11116               pflag = 2;
11117             if (pflag == 2) {
11118                 if (c != '\r' && c != ')')
11119                   *pt++ = c;
11120                 else {
11121                     *pt = '\0';
11122                     pflag = 3;
11123                 }
11124             }
11125             if (dig == 4 && c == '-' && n != '6') {
11126                 if (continuation)
11127                   ftpcode = 0;
11128                 continuation++;
11129             }
11130             if (cp < &ftp_reply_str[FTP_BUFSIZ - 1]) {
11131                 *cp++ = c;
11132                 *cp = NUL;
11133             }
11134         }
11135         if (deblog ||
11136 #ifdef COMMENT
11137 /*
11138   Sometimes we need to print the server reply.  printlines is nonzero for any
11139   command where the results are sent back on the control connection rather
11140   than the data connection, e.g. STAT.  In the TOPS-20 case, each file line
11141   has ftpcode 213.  But if you do this with a UNIX server, it sends "213-Start
11142   STAT", <line with ftpcode == 0>, "213-End" or somesuch.  So when printlines
11143   is nonzero, we want the 213 lines from TOPS-20 and we DON'T want the 213
11144   lines from UNIX.  Further experimentation needed with other servers.  Of
11145   course RFC959 is mute as to the format of the server reply.
11146 
11147   'printlines' is also true for PWD and BYE.
11148 */
11149 	    (printlines && ((ftpcode == 0) || (servertype == SYS_TOPS20)))
11150 #else
11151 /* No, we can't be that clever -- it breaks other things like RPWD... */
11152             (printlines &&
11153              (ftpcode != 631 && ftpcode != 632 && ftpcode != 633))
11154 #endif /* COMMENT */
11155             ) {
11156             char * q = cp;
11157             char *r = ftp_reply_str;
11158             *q-- = NUL;                 /* NUL-terminate */
11159             while (*q < '!' && q > r)   /* Strip CR, etc */
11160               *q-- = NUL;
11161             if (!ftp_deb && printlines) { /* If printing */
11162                 if (ftpcode != 0)       /* strip ftpcode if any */
11163                   r += 4;
11164 #ifdef NOCSETS
11165                 printf("%s\n",r);       /* and print */
11166 #else
11167                 if (!xlate) {
11168                     printf("%s\n",r);
11169                 } else {		/* Translating */
11170                     xgnbp = r;		/* Set up strgetc() */
11171                     while ((c0 = xgnbyte(FC_UCS2,rcs,strgetc)) > -1) {
11172                         if (xpnbyte(c0,TC_UCS2,lcs,NULL) < 0) {	/* (xprintc) */
11173                             signal(SIGINT,oldintr);
11174                             return(-1);
11175                         }
11176                     }
11177                     printf("\n");
11178                 }
11179 #endif /* NOCSETS */
11180             }
11181         }
11182 	debug(F110,"FTP RCVD ",ftp_reply_str,0);
11183 
11184 	if (fc == GRF_FEAT) {		/* Parsing FEAT command response? */
11185 	    if (count == 0 && n == '2') {
11186 		int i;			/* (Re)-init server FEATure table */
11187 		debug(F100,"ftp getreply clearing feature table","",0);
11188 		for (i = 0; i < 16; i++)
11189 		  sfttab[i] = 0;
11190 	    } else {
11191 		parsefeat((char *)ftp_reply_str);
11192 	    }
11193 	}
11194         if (auth_type &&
11195 #ifdef CK_SSL
11196             !ssl_ftp_active_flag &&
11197 #endif /* CK_SSL */
11198              !ibuf[0] && n != '6') {
11199             signal(SIGINT,oldintr);
11200             return(getreply(expecteof,lcs,rcs,vbm,auth));
11201         }
11202         ibuf[0] = obuf[i] = '\0';
11203         if (ftpcode && n == '6')
11204           if (ftpcode != 631 && ftpcode != 632 && ftpcode != 633) {
11205               printf("Unknown reply: %d %s\n", ftpcode, obuf);
11206               n = '5';
11207           } else safe = (ftpcode == 631);
11208         if (obuf[0]                     /* if there is a string to decode */
11209 #ifdef CK_SSL
11210             && !ssl_ftp_active_flag     /* and not SSL/TLS */
11211 #endif /* CK_SSL */
11212             ) {
11213             if (!auth_type) {
11214                 printf("Cannot decode reply:\n%d %s\n", ftpcode, obuf);
11215                 n = '5';
11216             }
11217 #ifndef CK_ENCRYPTION
11218             else if (ftpcode == 632) {
11219                 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11220                 n = '5';
11221             }
11222 #endif /* CK_ENCRYPTION */
11223 #ifdef NOCONFIDENTIAL
11224             else if (ftpcode == 633) {
11225                 printf("Cannot decrypt %d reply: %s\n", ftpcode, obuf);
11226                 n = '5';
11227             }
11228 #endif /* NOCONFIDENTIAL */
11229             else {
11230                 int len = FTP_BUFSIZ;
11231                 if ((kerror = radix_encode((CHAR *)obuf,
11232                                            (CHAR *)ibuf,
11233                                            0,
11234                                            &len,
11235                                            RADIX_DECODE))
11236                     ) {
11237                     printf("Can't decode base 64 reply %d (%s)\n\"%s\"\n",
11238                            ftpcode, radix_error(kerror), obuf);
11239                     n = '5';
11240                 }
11241 #ifdef FTP_SRP
11242                 else if (strcmp(auth_type, "SRP") == 0) {
11243                     int outlen;
11244                     outlen = srp_decode(!safe, (CHAR *)ibuf,
11245                                         (CHAR *) ibuf, len);
11246                     if (outlen < 0) {
11247                         printf("Warning: %d reply %s!\n",
11248                                ftpcode, safe ? "modified" : "garbled");
11249                         n = '5';
11250                     } else {
11251                         ckstrncpy(&ibuf[outlen], "\r\n",FTP_BUFSIZ-outlen);
11252                         if (ftp_deb)
11253                           printf("%c:", safe ? 'S' : 'P');
11254                         continue;
11255                     }
11256                 }
11257 #endif /* FTP_SRP */
11258 #ifdef FTP_KRB4
11259                 else if (strcmp(auth_type, "KERBEROS_V4") == 0) {
11260                     if (safe) {
11261                         kerror = krb_rd_safe((CHAR *)ibuf, len,
11262 #ifdef KRB524
11263                                              ftp_cred.session,
11264 #else /* KRB524 */
11265                                              &ftp_cred.session,
11266 #endif /* KRB524 */
11267                                              &hisctladdr,
11268                                              &myctladdr,
11269                                              &ftp_msg_data
11270                                              );
11271                     } else {
11272                         kerror = krb_rd_priv((CHAR *)ibuf, len,
11273                                              ftp_sched,
11274 #ifdef KRB524
11275                                              ftp_cred.session,
11276 #else /* KRB524 */
11277                                              &ftp_cred.session,
11278 #endif /* KRB524 */
11279                                              &hisctladdr,
11280                                              &myctladdr,
11281                                              &ftp_msg_data
11282                                              );
11283                     }
11284                     if (kerror != KSUCCESS) {
11285                         printf("%d reply %s! (krb_rd_%s: %s)\n", ftpcode,
11286                                safe ? "modified" : "garbled",
11287                                safe ? "safe" : "priv",
11288                                krb_get_err_text(kerror));
11289                         n = '5';
11290                     } else if (ftp_msg_data.app_length >= FTP_BUFSIZ - 3) {
11291                         kerror = KFAILURE;
11292                         n = '5';
11293                         printf("reply data too large for buffer\n");
11294                     } else {
11295                         if (ftp_deb)
11296                           printf("%c:", safe ? 'S' : 'P');
11297                         memcpy(ibuf,ftp_msg_data.app_data,
11298                                ftp_msg_data.app_length);
11299                         ckstrncpy(&ibuf[ftp_msg_data.app_length], "\r\n",
11300                                   FTP_BUFSIZ - ftp_msg_data.app_length);
11301                         continue;
11302                     }
11303                 }
11304 #endif /* FTP_KRB4 */
11305 #ifdef FTP_GSSAPI
11306                 else if (strcmp(auth_type, "GSSAPI") == 0) {
11307                     gss_buffer_desc xmit_buf, msg_buf;
11308                     OM_uint32 maj_stat, min_stat;
11309                     int conf_state;
11310                     xmit_buf.value = ibuf;
11311                     xmit_buf.length = len;
11312                     /* decrypt/verify the message */
11313                     conf_state = safe;
11314                     maj_stat = gss_unseal(&min_stat, gcontext,
11315                                           &xmit_buf, &msg_buf,
11316                                           &conf_state, NULL);
11317                     if (maj_stat != GSS_S_COMPLETE) {
11318                         user_gss_error(maj_stat, min_stat,
11319                                        "failed unsealing reply");
11320                         n = '5';
11321                     } else {
11322                         memcpy(ibuf, msg_buf.value, msg_buf.length);
11323                         ckstrncpy(&ibuf[msg_buf.length], "\r\n",
11324                                   FTP_BUFSIZ-msg_buf.length);
11325                         gss_release_buffer(&min_stat,&msg_buf);
11326                         if (ftp_deb)
11327                           printf("%c:", safe ? 'S' : 'P');
11328                         continue;
11329                     }
11330                 }
11331 #endif /* FTP_GSSAPI */
11332                 /* Other auth types go here... */
11333             }
11334         } else if ((!dpyactive || ftp_deb) && ftp_cmdlin < 2 &&
11335                    !xquiet && (vbm || (!auth && (n == '4' || n == '5')))) {
11336 #ifdef NOCSETS
11337             printf("%c",c);
11338 #else
11339             if (xlate) {
11340                 xlatec(0,c,rcs,lcs);
11341             } else {
11342                 printf("%c",c);
11343             }
11344 #endif /* NOCSETS */
11345             fflush (stdout);
11346         }
11347         if (continuation && ftpcode != originalcode) {
11348             if (originalcode == 0)
11349               originalcode = ftpcode;
11350             continue;
11351         }
11352         *cp = '\0';
11353         if (n != '1')
11354           cpend = 0;
11355         signal(SIGINT,oldintr);
11356         if (ftpcode == 421 || originalcode == 421) {
11357 	    lostpeer();
11358 	    if (!xquiet && !ftp_deb)
11359 	      printf("%s\n",reply_buf);
11360         }
11361         if ((cancelfile != 0) &&
11362 #ifndef ULTRIX3
11363             /* Ultrix 3.0 cc objects violently to this clause */
11364             (oldintr != cmdcancel) &&
11365 #endif /* ULTRIX3 */
11366             (oldintr != SIG_IGN)) {
11367             if (oldintr)
11368               (*oldintr)(SIGINT);
11369         }
11370         if (reply_parse) {
11371             *reply_ptr = '\0';
11372             if ((reply_ptr = ckstrstr(reply_buf, reply_parse))) {
11373                 reply_parse = reply_ptr + strlen(reply_parse);
11374                 if ((reply_ptr = ckstrpbrk(reply_parse, " \r")))
11375                   *reply_ptr = '\0';
11376             } else
11377               reply_parse = reply_ptr;
11378         }
11379         while (*cp < '!' && cp > ftp_reply_str) /* Remove trailing junk */
11380           *cp-- = NUL;
11381         debug(F111,"ftp getreply",ftp_reply_str,n - '0');
11382         return(n - '0');
11383     } /* for (;;) */
11384 }
11385 
11386 #ifdef BSDSELECT
11387 static int
11388 #ifdef CK_ANSIC
empty(fd_set * mask,int sec)11389 empty(fd_set * mask, int sec)
11390 #else
11391 empty(mask, sec) fd_set * mask; int sec;
11392 #endif /* CK_ANSIC */
11393 {
11394     struct timeval t;
11395     t.tv_sec = (long) sec;
11396     t.tv_usec = 0L;
11397     debug(F100,"ftp empty calling select...","",0);
11398 #ifdef INTSELECT
11399     x = select(32, (int *)mask, NULL, NULL, &t);
11400 #else
11401     x = select(32, mask, (fd_set *) 0, (fd_set *) 0, &t);
11402 #endif /* INTSELECT */
11403     debug(F101,"ftp empty select","",x);
11404     return(x);
11405 }
11406 #else /* BSDSELECT */
11407 #ifdef IBMSELECT
11408 static int
empty(mask,cnt,sec)11409 empty(mask, cnt, sec) int * mask, sec;
11410                       int   cnt;
11411 {
11412     return(select(mask,cnt,0,0,sec*1000));
11413 }
11414 #endif /* IBMSELECT */
11415 #endif /* BSDSELECT */
11416 
11417 static sigtype
cancelsend(sig)11418 cancelsend(sig) int sig; {
11419     havesigint++;
11420     cancelgroup++;
11421     cancelfile = 0;
11422     printf(" Canceled...\n");
11423     secure_getc(0,1);			/* Initialize net input buffers */
11424     debug(F100,"ftp cancelsend caught SIGINT ","",0);
11425     fflush(stdout);
11426 #ifndef OS2
11427     longjmp(sendcancel, 1);
11428 #else
11429     PostCtrlCSem();
11430 #endif /* OS2 */
11431 }
11432 
11433 static VOID
11434 #ifdef CK_ANSIC
secure_error(char * fmt,...)11435 secure_error(char *fmt, ...)
11436 #else
11437 /* VARARGS1 */
11438 secure_error(fmt, p1, p2, p3, p4, p5)
11439    char *fmt; int p1, p2, p3, p4, p5;
11440 #endif /* CK_ANSIC */
11441 {
11442 #ifdef CK_ANSIC
11443     va_list ap;
11444 
11445     va_start(ap, fmt);
11446     vfprintf(stderr, fmt, ap);
11447     va_end(ap);
11448 #else
11449     fprintf(stderr, fmt, p1, p2, p3, p4, p5);
11450 #endif
11451     fprintf(stderr, "\n");
11452 }
11453 
11454 /*
11455  * Internal form of settype; changes current type in use with server
11456  * without changing our notion of the type for data transfers.
11457  * Used to change to and from ascii for listings.
11458  */
11459 static VOID
changetype(newtype,show)11460 changetype(newtype, show) int newtype, show; {
11461     int rc;
11462     char * s;
11463 
11464     if ((newtype == curtype) && typesent++)
11465       return;
11466     switch (newtype) {
11467       case FTT_ASC:
11468         s = "A";
11469         break;
11470       case FTT_BIN:
11471         s = "I";
11472         break;
11473       case FTT_TEN:
11474         s = "L 8";
11475         break;
11476       default:
11477         s = "I";
11478         break;
11479     }
11480     rc = ftpcmd("TYPE",s,-1,-1,show);
11481     if (rc == REPLY_COMPLETE)
11482       curtype = newtype;
11483 }
11484 
11485 /* PUT a file.  Returns -1 on error, 0 on success, 1 if file skipped */
11486 
11487 static VOID
11488 #ifdef CK_ANSIC
doftpsend(void * threadinfo)11489 doftpsend(void * threadinfo)
11490 #else
11491 doftpsend(threadinfo) VOID * threadinfo;
11492 #endif
11493 {
11494 #ifdef NTSIG
11495     if (threadinfo) {                   /* Thread local storage... */
11496         TlsSetValue(TlsIndex,threadinfo);
11497         debug(F100, "doftpsend called with threadinfo block","", 0);
11498     } else debug(F100, "doftpsend - threadinfo is NULL", "", 0);
11499 #endif /* NTSIG */
11500 #ifdef CK_LOGIN
11501 #ifdef IKSD
11502 #ifdef NT
11503     if (inserver)
11504       setntcreds();
11505 #endif /* NT */
11506 #endif /* IKSD */
11507 #endif /* CK_LOGIN */
11508 
11509     if (initconn()) {
11510 #ifndef NOHTTP
11511         int y = -1;
11512         /* debug(F101,"doftpsend","tcp_http_proxy",tcp_http_proxy); */
11513 
11514        /*  If the connection failed and we are using an HTTP Proxy
11515         *  and the reason for the failure was an authentication
11516         *  error, then we need to give the user to ability to
11517         *  enter a username and password, just like a browser.
11518         *
11519         *  I tried to do all of this within the netopen() call
11520         *  but it is much too much work.
11521         */
11522         while (y != 0 && tcp_http_proxy != NULL ) {
11523 
11524             if (tcp_http_proxy_errno == 401 ||
11525                  tcp_http_proxy_errno == 407 ) {
11526                 char uid[UIDBUFLEN];
11527                 char pwd[PWDSIZ];
11528                 struct txtbox tb[2];
11529                 int ok;
11530 
11531                 tb[0].t_buf = uid;
11532                 tb[0].t_len = UIDBUFLEN;
11533                 tb[0].t_lbl = "Proxy Userid: ";
11534                 tb[0].t_dflt = NULL;
11535                 tb[0].t_echo = 1;
11536                 tb[1].t_buf = pwd;
11537                 tb[1].t_len = 256;
11538                 tb[1].t_lbl = "Proxy Passphrase: ";
11539                 tb[1].t_dflt = NULL;
11540                 tb[1].t_echo = 2;
11541 
11542                 ok = uq_mtxt("Proxy Server Authentication Required\n",
11543                               NULL, 2, tb);
11544                 if (ok && uid[0]) {
11545                     char * proxy_user, * proxy_pwd;
11546 
11547                     proxy_user = tcp_http_proxy_user;
11548                     proxy_pwd  = tcp_http_proxy_pwd;
11549 
11550                     tcp_http_proxy_user = uid;
11551                     tcp_http_proxy_pwd = pwd;
11552 
11553                     y = initconn();
11554 
11555                     debug(F101,"doftpsend","initconn",y);
11556                     memset(pwd,0,PWDSIZ);
11557                     tcp_http_proxy_user = proxy_user;
11558                     tcp_http_proxy_pwd = proxy_pwd;
11559                 } else
11560                     break;
11561             } else
11562                 break;
11563         }
11564 
11565         if ( y != 0 ) {
11566 #endif /* NOHTTP */
11567             signal(SIGINT, ftpsnd.oldintr);
11568 #ifdef SIGPIPE
11569             if (ftpsnd.oldintp)
11570               signal(SIGPIPE, ftpsnd.oldintp);
11571 #endif /* SIGPIPE */
11572             ftpcode = -1;
11573             zclose(ZIFILE);
11574             ftpsndret = -1;
11575 #ifdef NTSIG
11576             ckThreadEnd(threadinfo);
11577 #endif /* NTSIG */
11578             return;
11579 #ifndef NOHTTP
11580         }
11581 #endif /* NOHTTP */
11582     }
11583     ftpsndret = 0;
11584 #ifdef NTSIG
11585      ckThreadEnd(threadinfo);
11586 #endif /* NTSIG */
11587 }
11588 
11589 static VOID
11590 #ifdef CK_ANSIC
failftpsend(void * threadinfo)11591 failftpsend(void * threadinfo)
11592 #else
11593 failftpsend(threadinfo) VOID * threadinfo;
11594 #endif /* CK_ANSIC */
11595 {
11596 #ifdef NTSIG
11597     if (threadinfo) {                   /* Thread local storage... */
11598         TlsSetValue(TlsIndex,threadinfo);
11599         debug(F100, "docmdfile called with threadinfo block","", 0);
11600     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11601 #endif /* NTSIG */
11602 #ifdef CK_LOGIN
11603 #ifdef IKSD
11604 #ifdef NT
11605     if (inserver)
11606       setntcreds();
11607 #endif /* NT */
11608 #endif /* IKSD */
11609 #endif /* CK_LOGIN */
11610 
11611     while (cpend) {
11612         ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11613         debug(F111,"ftp sendrequest getreply","null command",ftpsnd.reply);
11614     }
11615     if (data >= 0) {
11616 #ifdef CK_SSL
11617         if (ssl_ftp_data_active_flag) {
11618             SSL_shutdown(ssl_ftp_data_con);
11619             SSL_free(ssl_ftp_data_con);
11620             ssl_ftp_data_active_flag = 0;
11621             ssl_ftp_data_con = NULL;
11622         }
11623 #endif /* CK_SSL */
11624 #ifdef TCPIPLIB
11625         socket_close(data);
11626 #else /* TCPIPLIB */
11627 #ifdef USE_SHUTDOWN
11628         shutdown(data, 1+1);
11629 #endif /* USE_SHUTDOWN */
11630         close(data);
11631 #endif /* TCPIPLIB */
11632         data = -1;
11633         globaldin = -1;
11634     }
11635     if (ftpsnd.oldintr)
11636         signal(SIGINT,ftpsnd.oldintr);
11637 #ifdef SIGPIPE
11638     if (ftpsnd.oldintp)
11639         signal(SIGPIPE,ftpsnd.oldintp);
11640 #endif /* SIGPIPE */
11641     ftpcode = -1;
11642 #ifndef OS2
11643     /* TEST ME IN K95 */
11644     if (havesigint) {
11645 	havesigint = 0;
11646 	debug(F100,"ftp failftpsend chain to trap()...","",0);
11647 	if (ftpsnd.oldintr != SIG_IGN)
11648 	  (*ftpsnd.oldintr)(SIGINT);
11649 	/* NOTREACHED (I hope!) */
11650 	debug(F100,"ftp failftpsend return from trap()...","",0);
11651     }
11652 #endif /* OS2 */
11653 }
11654 
11655 static VOID
11656 #ifdef CK_ANSIC
failftpsend2(void * threadinfo)11657 failftpsend2(void * threadinfo)
11658 #else
11659 failftpsend2(threadinfo) VOID * threadinfo;
11660 #endif /* CK_ANSIC */
11661 {
11662 #ifdef NTSIG
11663     if (threadinfo) {                   /* Thread local storage... */
11664         TlsSetValue(TlsIndex,threadinfo);
11665         debug(F100, "docmdfile called with threadinfo block","", 0);
11666     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
11667 #endif /* NTSIG */
11668 #ifdef CK_LOGIN
11669 #ifdef IKSD
11670 #ifdef NT
11671     if (inserver)
11672       setntcreds();
11673 #endif /* NT */
11674 #endif /* IKSD */
11675 #endif /* CK_LOGIN */
11676 
11677     debug(F101,"ftp sendrequest canceled","",ftpsnd.bytes);
11678     tfc += ffc;
11679 #ifdef GFTIMER
11680     fpfsecs = gftimer();
11681 #endif /* GFTIMER */
11682     zclose(ZIFILE);
11683 #ifdef PIPESEND
11684     if (sndfilter)
11685       pipesend = 0;
11686 #endif /* PIPESEND */
11687     signal(SIGINT, ftpsnd.oldintr);
11688 #ifdef SIGPIPE
11689     if (ftpsnd.oldintp)
11690       signal(SIGPIPE, ftpsnd.oldintp);
11691 #endif /* SIGPIPE */
11692     if (!cpend) {
11693         ftpcode = -1;
11694         ftpsndret = -1;
11695 #ifdef NTSIG
11696         ckThreadEnd(threadinfo);
11697 #endif /* NTSIG */
11698         return;
11699     }
11700     if (data >= 0) {
11701 #ifdef CK_SSL
11702         if (ssl_ftp_data_active_flag) {
11703             SSL_shutdown(ssl_ftp_data_con);
11704             SSL_free(ssl_ftp_data_con);
11705             ssl_ftp_data_active_flag = 0;
11706             ssl_ftp_data_con = NULL;
11707         }
11708 #endif /* CK_SSL */
11709 #ifdef TCPIPLIB
11710         socket_close(data);
11711 #else /* TCPIPLIB */
11712 #ifdef USE_SHUTDOWN
11713         shutdown(data, 1+1);
11714 #endif /* USE_SHUTDOWN */
11715         close(data);
11716 #endif /* TCPIPLIB */
11717         data = -1;
11718         globaldin = -1;
11719     }
11720     if (dout) {
11721 #ifdef TCPIPLIB
11722         socket_close(dout);
11723 #else /* TCPIPLIB */
11724 #ifdef USE_SHUTDOWN
11725         shutdown(dout, 1+1);
11726 #endif /* USE_SHUTDOWN */
11727         close(dout);
11728 #endif /* TCPIPLIB */
11729     }
11730     ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
11731     ftpcode = -1;
11732     ftpsndret = -1;
11733 
11734 #ifndef OS2
11735     /* TEST ME IN K95 */
11736     if (havesigint) {
11737 	havesigint = 0;
11738 	debug(F100,"ftp failftpsend2 chain to trap()...","",0);
11739 	if (ftpsnd.oldintr != SIG_IGN)
11740 	  (*ftpsnd.oldintr)(SIGINT);
11741 	/* NOTREACHED (I hope!) */
11742 	debug(F100,"ftp failftpsend2 return from trap()...","",0);
11743     }
11744 #endif /* OS2 */
11745 }
11746 
11747 static VOID
11748 #ifdef CK_ANSIC
doftpsend2(void * threadinfo)11749 doftpsend2(void * threadinfo)
11750 #else
11751 doftpsend2(threadinfo) VOID * threadinfo;
11752 #endif
11753 {
11754     register int c, d = 0;
11755     int n, t, x, notafile, unique = 0;
11756     char *buf, *bufp;
11757 
11758 #ifdef NTSIG
11759     if (threadinfo) {                   /* Thread local storage... */
11760         TlsSetValue(TlsIndex,threadinfo);
11761         debug(F100, "doftpsend2 called with threadinfo block","", 0);
11762     } else debug(F100, "doftpsend2 - threadinfo is NULL", "", 0);
11763 #endif /* NTSIG */
11764 #ifdef CK_LOGIN
11765 #ifdef IKSD
11766 #ifdef NT
11767     if (inserver)
11768       setntcreds();
11769 #endif /* NT */
11770 #endif /* IKSD */
11771 #endif /* CK_LOGIN */
11772 
11773     buf = ftpsndbuf;			/* (not on stack) */
11774 
11775     unique = strcmp(ftpsnd.cmd,"STOU") ? 0 : 1;
11776     notafile = sndarray || pipesend;
11777 
11778 #ifdef FTP_RESTART
11779     if (ftpsnd.restart && ((curtype == FTT_BIN) || (alike > 0))) {
11780         char * p;
11781         changetype(FTT_BIN,0);          /* Change to binary */
11782 
11783         /* Ask for remote file's size */
11784         x = ftpcmd("SIZE",ftpsnd.remote,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11785 
11786         if (x == REPLY_COMPLETE) {      /* Have ftpsnd.reply */
11787             p = &ftp_reply_str[4];      /* Parse it */
11788             while (isdigit(*p)) {
11789                 sendstart = sendstart * 10 + (int)(*p - '0');
11790                 p++;
11791             }
11792             if (*p && *p != CR) {       /* Bad number */
11793                 debug(F110,"doftpsend2 bad size",ftp_reply_str,0);
11794                 sendstart = (CK_OFF_T)0;
11795             } else if (sendstart > fsize) { /* Remote file bigger than local */
11796                 debug(F110,"doftpsend2 big size",ckfstoa(fsize),sendstart);
11797                 sendstart = (CK_OFF_T)0;
11798             }
11799 	    /* Local is newer */
11800             debug(F111,"doftpsend2 size",ftpsnd.remote,sendstart);
11801             if (chkmodtime(ftpsnd.local,ftpsnd.remote,0) == 2) {
11802                 debug(F110,"doftpsend2 date mismatch",ftp_reply_str,0);
11803                 sendstart = (CK_OFF_T)0; /* Send the whole file */
11804             }
11805         }
11806         changetype(ftp_typ,0);          /* Change back to appropriate type */
11807         if (sendstart > (CK_OFF_T)0) {	/* Still restarting? */
11808             if (sendstart == fsize) {   /* Same size - no need to send */
11809                 debug(F111,"doftpsend2 /restart SKIP",
11810 		      ckfstoa(fsize),sendstart);
11811                 zclose(ZIFILE);
11812                 ftpsndret = SKP_RES;
11813 #ifdef NTSIG
11814                 ckThreadEnd(threadinfo);
11815 #endif /* NTSIG */
11816                 return;
11817             }
11818             errno = 0;                  /* Restart needed, seek to the spot */
11819             if (zfseek((long)sendstart) < 0) {
11820                 debug(F111,"doftpsend2 zfseek fails",
11821 		      ftpsnd.local,sendstart);
11822                 fprintf(stderr, "FSEEK: %s: %s\n", ftpsnd.local, ck_errstr());
11823                 sendstart = 0;
11824                 zclose(ZIFILE);
11825                 ftpsndret = -1;
11826 #ifdef NTSIG
11827                 ckThreadEnd(threadinfo);
11828 #endif /* NTSIG */
11829                 return;
11830             }
11831 #ifdef COMMENT
11832             debug(F111,"doftpsend2 zfseek ok",ftpsnd.local,sendstart);
11833             x = ftpcmd("REST",ckltoa(sendstart),-1,-1,ftp_vbm);
11834             if (x != REPLY_CONTINUE) {
11835                 sendstart = 0;
11836                 zclose(ZIFILE);
11837                 ftpsndret = -1;
11838 #ifdef NTSIG
11839                 ckThreadEnd(threadinfo);
11840 #endif /* NTSIG */
11841                 return;
11842             } else {
11843                 ftpsnd.cmd = "STOR";
11844             }
11845 #else
11846             sendmode = SM_RESEND;
11847             ftpsnd.cmd = "APPE";
11848 #endif /* COMMENT */
11849             /* sendstart = (CK_OFF_T)0; */
11850         }
11851     }
11852 #endif /* FTP_RESTART */
11853 
11854     if (unique && !stouarg)		/* If we know STOU accepts no arg */
11855       ftpsnd.remote = NULL;		/* don't include one. */
11856 
11857     x = ftpcmd(ftpsnd.cmd, ftpsnd.remote, ftpsnd.incs, ftpsnd.outcs, ftp_vbm);
11858     debug(F111,"doftpsend2 ftpcode",ftpsnd.cmd,ftpcode);
11859     debug(F101,"doftpsend2 ftpcmd","",x);
11860 
11861     if (x != REPLY_PRELIM && unique) {
11862 	/*
11863 	  RFC959 says STOU does not take an argument.  But every FTP server
11864 	  I've encountered but one accepts the arg and constructs the unique
11865 	  name from it, which is better than making up a totally random name
11866 	  for the file, which is what RFC959 calls for.  Especially because
11867 	  there is no way for the client to find out the name chosen by the
11868 	  server.  So we try STOU with the argument first, which works with
11869 	  most servers, and if it fails we retry it without the arg, for
11870 	  the benefit of the one picky server that is not "liberal in what
11871 	  it accepts" UNLESS the first STOU got a 502 code ("not implemented")
11872 	  which means STOU is not accepted, period.
11873 	*/
11874 	if ((x == 5) && stouarg && (ftpcode != 502)) {
11875 	    x = ftpcmd(ftpsnd.cmd,NULL,ftpsnd.incs,ftpsnd.outcs,ftp_vbm);
11876 	    if (x == REPLY_PRELIM)	/* If accepted */
11877 	      stouarg = 0;		/* flag no STOU arg for this server */
11878 	}
11879     }
11880     if (x != REPLY_PRELIM) {
11881         signal(SIGINT, ftpsnd.oldintr);
11882 #ifdef SIGPIPE
11883         if (ftpsnd.oldintp)
11884           signal(SIGPIPE, ftpsnd.oldintp);
11885 #endif /* SIGPIPE */
11886 	debug(F101,"doftpsend2 not REPLY_PRELIM","",x);
11887         zclose(ZIFILE);
11888 #ifdef PIPESEND
11889         if (sndfilter)
11890           pipesend = 0;
11891 #endif /* PIPESEND */
11892         ftpsndret = -1;
11893 #ifdef NTSIG
11894         ckThreadEnd(threadinfo);
11895 #endif /* NTSIG */
11896         return;
11897     }
11898     debug(F100,"doftpsend2 getting data connection...","",0);
11899     dout = dataconn(ftpsnd.lmode);             /* Get data connection */
11900     debug(F101,"doftpsend2 dataconn","",dout);
11901     if (dout == -1) {
11902         failftpsend2(threadinfo);
11903 #ifdef NTSIG
11904         ckThreadEnd(threadinfo);
11905 #endif /* NTSIG */
11906         return;
11907     }
11908     /* Initialize per-file stats */
11909     ffc = (CK_OFF_T)0;			/* Character counter */
11910     cps = oldcps = 0L;                  /* Thruput */
11911     n = 0;
11912 #ifdef GFTIMER
11913     rftimer();                          /* reset f.p. timer */
11914 #endif /* GFTIMER */
11915 
11916 #ifdef SIGPIPE
11917     ftpsnd.oldintp = signal(SIGPIPE, SIG_IGN);
11918 #endif /* SIGPIPE */
11919     debug(F101,"doftpsend2 curtype","",curtype);
11920     switch (curtype) {
11921       case FTT_BIN:                     /* Binary mode */
11922       case FTT_TEN:
11923         errno = d = 0;
11924 #ifdef VMS
11925 	/*
11926 	  This is because VMS zxin() is C-Library fread()
11927           but the file was opened with zopeni(), which is RMS.
11928 	*/
11929 	while (((c = zminchar()) > -1) && !cancelfile) {
11930 	    ffc++;
11931 	    if (zzout(dout,c) < 0)
11932 	      break;
11933 	}
11934 #else  /* VMS */
11935         while ((n = zxin(ZIFILE,buf,FTP_BUFSIZ - 1)) > 0 && !cancelfile) {
11936             ftpsnd.bytes += n;
11937             ffc += n;
11938             debug(F111,"doftpsend2 zxin",ckltoa(n),ffc);
11939             ckhexdump("doftpsend2 zxin",buf,16);
11940 #ifdef CK_SSL
11941             if (ssl_ftp_data_active_flag) {
11942                 for (bufp = buf; n > 0; n -= d, bufp += d) {
11943                     if ((d = SSL_write(ssl_ftp_data_con, bufp, n)) <= 0)
11944                       break;
11945                     spackets++;
11946                     pktnum++;
11947                     if (fdispla != XYFD_B) {
11948                         spktl = d;
11949                         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11950                     }
11951                 }
11952             } else {
11953 #endif /* CK_SSL */
11954                 for (bufp = buf; n > 0; n -= d, bufp += d) {
11955                     if (((d = secure_write(dout, (CHAR *)bufp, n)) <= 0)
11956                         || iscanceled())
11957                       break;
11958                     spackets++;
11959                     pktnum++;
11960                     if (fdispla != XYFD_B) {
11961                         spktl = d;
11962                         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
11963                     }
11964                 }
11965 #ifdef CK_SSL
11966             }
11967 #endif /* CK_SSL */
11968             if (d <= 0)
11969               break;
11970         }
11971 #endif	/* VMS */
11972 
11973 	debug(F111,"doftpsend2 XX zxin",ckltoa(n),ffc);
11974         if (n < 0)
11975           fprintf(stderr, "local: %s: %s\n", ftpsnd.local, ck_errstr());
11976         if (d < 0 || (d = secure_flush(dout)) < 0) {
11977             if (d == -1 && errno && errno != EPIPE)
11978               perror("netout");
11979             ftpsnd.bytes = -1;
11980         }
11981         break;
11982 
11983       case FTT_ASC:                     /* Text mode */
11984 #ifndef NOCSETS
11985         if (ftpsnd.xlate) {             /* With translation */
11986             initxlate(ftpsnd.incs,ftpsnd.outcs);
11987             while (!cancelfile) {
11988                 if ((c0 = xgnbyte(FC_UCS2,ftpsnd.incs,NULL)) < 0) break;
11989                 if ((x = xpnbyte(c0,TC_UCS2,ftpsnd.outcs,xxout)) < 0) break;
11990             }
11991         } else {
11992 #endif /* NOCSETS */
11993             /* Text mode, no translation */
11994             while (((c = zminchar()) > -1) && !cancelfile) {
11995                 ffc++;
11996 		if (xxout(c) < 0)
11997 		  break;
11998             }
11999             d = 0;
12000 #ifndef NOCSETS
12001         }
12002 #endif /* NOCSETS */
12003         if (dout == -1 || (d = secure_flush(dout)) < 0) {
12004             if (d == -1 && errno && errno != EPIPE)
12005               perror("netout");
12006             ftpsnd.bytes = -1;
12007         }
12008         break;
12009     }
12010     tfc += ffc;                         /* Total file chars */
12011 #ifdef GFTIMER
12012     fpfsecs = gftimer();
12013 #endif /* GFTIMER */
12014     zclose(ZIFILE);                     /* Close input file */
12015 #ifdef PIPESEND
12016     if (sndfilter)                      /* Undo this (it's per file) */
12017       pipesend = 0;
12018 #endif /* PIPESEND */
12019 
12020 #ifdef CK_SSL
12021         if (ssl_ftp_data_active_flag) {
12022             SSL_shutdown(ssl_ftp_data_con);
12023             SSL_free(ssl_ftp_data_con);
12024             ssl_ftp_data_active_flag = 0;
12025             ssl_ftp_data_con = NULL;
12026         }
12027 #endif /* CK_SSL */
12028 
12029 #ifdef TCPIPLIB
12030     socket_close(dout);                 /* Close data connection */
12031 #else /* TCPIPLIB */
12032 #ifdef USE_SHUTDOWN
12033     shutdown(dout, 1+1);
12034 #endif /* USE_SHUTDOWN */
12035     close(dout);
12036 #endif /* TCPIPLIB */
12037     ftpsnd.reply = getreply(0,ftpsnd.incs,ftpsnd.outcs,ftp_vbm,0);
12038     signal(SIGINT, ftpsnd.oldintr);            /* Put back interrupts */
12039 #ifdef SIGPIPE
12040     if (ftpsnd.oldintp)
12041       signal(SIGPIPE, ftpsnd.oldintp);
12042 #endif /* SIGPIPE */
12043     if (ftpsnd.reply == REPLY_TRANSIENT || ftpsnd.reply == REPLY_ERROR) {
12044         debug(F101,"doftpsend2 ftpsnd.reply","",ftpsnd.reply);
12045         ftpsndret = -1;
12046 #ifdef NTSIG
12047         ckThreadEnd(threadinfo);
12048 #endif /* NTSIG */
12049         return;
12050     } else if (cancelfile) {
12051         debug(F101,"doftpsend2 canceled","",ftpsnd.bytes);
12052         ftpsndret = -1;
12053 #ifdef NTSIG
12054         ckThreadEnd(threadinfo);
12055 #endif /* NTSIG */
12056         return;
12057     }
12058     debug(F101,"doftpsend2 ok","",ftpsnd.bytes);
12059     ftpsndret = 0;
12060 #ifdef NTSIG
12061      ckThreadEnd(threadinfo);
12062 #endif /* NTSIG */
12063 }
12064 
12065 static int
sendrequest(cmd,local,remote,xlate,incs,outcs,restart)12066 sendrequest(cmd, local, remote, xlate, incs, outcs, restart)
12067     char *cmd, *local, *remote; int xlate, incs, outcs, restart;
12068 {
12069     if (!remote) remote = "";           /* Check args */
12070     if (!*remote) remote = local;
12071     if (!local) local = "";
12072     if (!*local) return(-1);
12073     if (!cmd) cmd = "";
12074     if (!*cmd) cmd = "STOR";
12075 
12076     debug(F111,"ftp sendrequest restart",local,restart);
12077 
12078     nout = 0;                           /* Init output buffer count */
12079     ftpsnd.bytes = 0;                   /* File input byte count */
12080     dout = -1;
12081 
12082 #ifdef FTP_PROXY
12083     if (proxy) {
12084         proxtrans(cmd, local, remote, !strcmp(cmd,"STOU"));
12085         return(0);
12086     }
12087 #endif /* FTP_PROXY */
12088 
12089     changetype(ftp_typ,0);              /* Change type for this file */
12090 
12091     ftpsnd.oldintr = NULL;		/* Set up interrupt handler */
12092     ftpsnd.oldintp = NULL;
12093     ftpsnd.restart = restart;
12094     ftpsnd.xlate = xlate;
12095     ftpsnd.lmode = "wb";
12096 
12097 #ifdef PIPESEND                         /* Use Kermit API for file i/o... */
12098     if (sndfilter) {
12099         char * p = NULL, * q;
12100 #ifndef NOSPL
12101         int n = CKMAXPATH;
12102         if (cmd_quoting && (p = (char *) malloc(n + 1))) {
12103             q = p;
12104             debug(F110,"sendrequest pipesend filter",sndfilter,0);
12105             zzstring(sndfilter,&p,&n);
12106             debug(F111,"sendrequest pipename",q,n);
12107             if (n <= 0) {
12108                 printf("?Sorry, send filter + filename too long, %d max.\n",
12109                        CKMAXPATH
12110                        );
12111                 free(q);
12112                 return(-1);
12113             }
12114             ckstrncpy(filnam,q,CKMAXPATH+1);
12115             free(q);
12116             local = filnam;
12117         }
12118 #endif /* NOSPL */
12119     }
12120 
12121     if (sndfilter)                      /* If sending thru a filter */
12122       pipesend = 1;                     /* set this for open and i/o */
12123 #endif /* PIPESEND */
12124 
12125 #ifdef VMS
12126     debug(F101,"XXX before openi binary","",binary);
12127     debug(F101,"XXX before openi ftp_typ","",ftp_typ);
12128 #endif	/* VMS */
12129 
12130     if (openi(local) == 0)		/* Try to open the input file */
12131       return(-1);
12132 
12133 #ifdef VMS
12134     debug(F101,"XXX after openi binary","",binary);
12135     debug(F101,"XXX after openi ftp_typ","",ftp_typ);
12136     if (!forcetype) {
12137 	if (binary != ftp_typ) {	/* VMS zopeni() sets binary */
12138 	    debug(F101,"XXX changing type","",binary);
12139 	    doftptyp(binary);
12140 	    debug(F101,"XXX after doftptyp","",ftp_typ);
12141 
12142 	    /* **** */
12143 	    if (displa && fdispla) {	/* Update file type display */
12144 		ftscreen(SCR_FN,'F',(CK_OFF_T)0,local);
12145 	    }
12146 	}
12147     }
12148 #endif	/* VMS */
12149     ftpsndret = 0;
12150     ftpsnd.incs = incs;
12151     ftpsnd.outcs = outcs;
12152     ftpsnd.cmd = cmd;
12153     ftpsnd.local = local;
12154     ftpsnd.remote = remote;
12155     ftpsnd.oldintr = signal(SIGINT, cancelsend);
12156     havesigint = 0;
12157 
12158     if (cc_execute(ckjaddr(sendcancel), doftpsend, failftpsend) < 0)
12159       return(-1);
12160     if (ftpsndret < 0)
12161       return(-1);
12162     if (cc_execute(ckjaddr(sendcancel), doftpsend2, failftpsend2) < 0)
12163       return(-1);
12164 
12165     return(ftpsndret);
12166 }
12167 
12168 static sigtype
cancelrecv(sig)12169 cancelrecv(sig) int sig; {
12170     havesigint++;
12171     cancelfile = 0;
12172     cancelgroup++;
12173     secure_getc(0,1);			/* Initialize net input buffers */
12174     printf(" Canceling...\n");
12175     debug(F100,"ftp cancelrecv caught SIGINT","",0);
12176     fflush(stdout);
12177     if (fp_nml) {
12178         if (fp_nml != stdout)
12179           fclose(fp_nml);
12180         fp_nml = NULL;
12181     }
12182 #ifndef OS2
12183     longjmp(recvcancel, 1);
12184 #else
12185     PostCtrlCSem();
12186 #endif /* OS2 */
12187 }
12188 
12189 /* Argumentless front-end for secure_getc() */
12190 
12191 static int
netgetc()12192 netgetc() {
12193     return(secure_getc(globaldin,0));
12194 }
12195 
12196 /* Returns -1 on failure, 0 on success, 1 if file skipped */
12197 
12198 /*
12199   Sets ftpcode < 0 on failure if failure reason is not server reply code:
12200     -1: interrupted by user.
12201     -2: error opening or writing output file (reason in errno).
12202     -3: failure to make data connection.
12203     -4: network read error (reason in errno).
12204 */
12205 
12206 struct xx_ftprecv {
12207     int reply;
12208     int fcs;
12209     int rcs;
12210     int recover;
12211     int xlate;
12212     int din;
12213     int is_retr;
12214     sig_t oldintr, oldintp;
12215     char * cmd;
12216     char * local;
12217     char * remote;
12218     char * lmode;
12219     char * pipename;
12220     int    tcrflag;
12221     CK_OFF_T localsize;
12222 };
12223 static struct xx_ftprecv ftprecv;
12224 
12225 static int ftprecvret = 0;
12226 
12227 static VOID
12228 #ifdef CK_ANSIC
failftprecv(VOID * threadinfo)12229 failftprecv(VOID * threadinfo)
12230 #else
12231 failftprecv(threadinfo) VOID * threadinfo;
12232 #endif /* CK_ANSIC */
12233 {
12234 #ifdef NTSIG
12235     if (threadinfo) {                   /* Thread local storage... */
12236         TlsSetValue(TlsIndex,threadinfo);
12237         debug(F100, "docmdfile called with threadinfo block","", 0);
12238     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12239 #endif /* NTSIG */
12240 
12241 #ifdef CK_LOGIN
12242 #ifdef IKSD
12243 #ifdef NT
12244     if (inserver)
12245       setntcreds();
12246 #endif /* NT */
12247 #endif /* IKSD */
12248 #endif /* CK_LOGIN */
12249 
12250     while (cpend) {
12251         ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12252     }
12253     if (data >= 0) {
12254 #ifdef CK_SSL
12255         if (ssl_ftp_data_active_flag) {
12256             SSL_shutdown(ssl_ftp_data_con);
12257             SSL_free(ssl_ftp_data_con);
12258             ssl_ftp_data_active_flag = 0;
12259             ssl_ftp_data_con = NULL;
12260         }
12261 #endif /* CK_SSL */
12262 #ifdef TCPIPLIB
12263         socket_close(data);
12264 #else /* TCPIPLIB */
12265 #ifdef USE_SHUTDOWN
12266         shutdown(data, 1+1);
12267 #endif /* USE_SHUTDOWN */
12268         close(data);
12269 #endif /* TCPIPLIB */
12270         data = -1;
12271         globaldin = -1;
12272     }
12273     if (ftprecv.oldintr)
12274       signal(SIGINT, ftprecv.oldintr);
12275     ftpcode = -1;
12276     ftprecvret = -1;
12277 
12278 #ifndef OS2
12279     /* TEST ME IN K95 */
12280     if (havesigint) {
12281 	havesigint = 0;
12282 	debug(F100,"ftp failftprecv chain to trap()...","",0);
12283 	if (ftprecv.oldintr != SIG_IGN)
12284 	  (*ftprecv.oldintr)(SIGINT);
12285 	/* NOTREACHED (I hope!) */
12286 	debug(F100,"ftp failftprecv return from trap()...","",0);
12287     }
12288 #endif /* OS2 */
12289     return;
12290 }
12291 
12292 static VOID
12293 #ifdef CK_ANSIC
doftprecv(VOID * threadinfo)12294 doftprecv(VOID * threadinfo)
12295 #else
12296 doftprecv(threadinfo) VOID * threadinfo;
12297 #endif /* CK_ANSIC */
12298 {
12299 #ifdef NTSIG
12300     if (threadinfo) {                   /* Thread local storage... */
12301         TlsSetValue(TlsIndex,threadinfo);
12302         debug(F100, "docmdfile called with threadinfo block","", 0);
12303     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12304 #endif /* NTSIG */
12305 #ifdef CK_LOGIN
12306 #ifdef IKSD
12307 #ifdef NT
12308     if (inserver)
12309       setntcreds();
12310 #endif /* NT */
12311 #endif /* IKSD */
12312 #endif /* CK_LOGIN */
12313 
12314 #ifndef COMMENT
12315     if (!out2screen && !ftprecv.pipename) {
12316 	int x;
12317 	char * local;
12318 	local = ftprecv.local;
12319 	x = zchko(local);
12320         if (x < 0) {
12321             if ((!dpyactive || ftp_deb))
12322               fprintf(stderr,
12323 		      "Temporary file %s: %s\n", ftprecv.local, ck_errstr());
12324             signal(SIGINT, ftprecv.oldintr);
12325             ftpcode = -2;
12326             ftprecvret = -1;
12327 #ifdef NTSIG
12328             ckThreadEnd(threadinfo);
12329 #endif /* NTSIG */
12330             return;
12331         }
12332     }
12333 #endif /* COMMENT */
12334     changetype((!ftprecv.is_retr) ? FTT_ASC : ftp_typ, 0);
12335     if (initconn()) {                   /* Initialize the data connection */
12336         signal(SIGINT, ftprecv.oldintr);
12337         ftpcode = -1;
12338         ftprecvret = -3;
12339 #ifdef NTSIG
12340         ckThreadEnd(threadinfo);
12341 #endif /* NTSIG */
12342         return;
12343     }
12344     secure_getc(0,1);			/* Initialize net input buffers */
12345     ftprecvret = 0;
12346 
12347 #ifdef NTSIG
12348     ckThreadEnd(threadinfo);
12349 #endif /* NTSIG */
12350 }
12351 
12352 static VOID
12353 #ifdef CK_ANSIC
failftprecv2(VOID * threadinfo)12354 failftprecv2(VOID * threadinfo)
12355 #else
12356 failftprecv2(threadinfo) VOID * threadinfo;
12357 #endif /* CK_ANSIC */
12358 {
12359 #ifdef NTSIG
12360     if (threadinfo) {                   /* Thread local storage... */
12361         TlsSetValue(TlsIndex,threadinfo);
12362         debug(F100, "docmdfile called with threadinfo block","", 0);
12363     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12364 #endif /* NTSIG */
12365 #ifdef CK_LOGIN
12366 #ifdef IKSD
12367 #ifdef NT
12368     if (inserver)
12369       setntcreds();
12370 #endif /* NT */
12371 #endif /* IKSD */
12372 #endif /* CK_LOGIN */
12373 
12374     /* Cancel using RFC959 recommended IP,SYNC sequence  */
12375 
12376     debug(F100,"ftp recvrequest CANCEL","",0);
12377 #ifdef GFTIMER
12378     fpfsecs = gftimer();
12379 #endif /* GFTIMER */
12380 #ifdef SIGPIPE
12381     if (ftprecv.oldintp)
12382       signal(SIGPIPE, ftprecv.oldintr);
12383 #endif /* SIGPIPE */
12384     signal(SIGINT, SIG_IGN);
12385     if (!cpend) {
12386         ftpcode = -1;
12387         signal(SIGINT, ftprecv.oldintr);
12388         ftprecvret = -1;
12389 #ifdef NTSIG
12390         ckThreadEnd(threadinfo);
12391 #endif /* NTSIG */
12392         return;
12393     }
12394     cancel_remote(ftprecv.din);
12395 
12396 #ifdef FTP_TIMEOUT
12397     if (ftp_timed_out && out2screen && !quiet)
12398       printf("\n?Timed out.\n");
12399 #endif	/* FTP_TIMEOUT */
12400 
12401     if (ftpcode > -1)
12402       ftpcode = -1;
12403     if (data >= 0) {
12404 #ifdef CK_SSL
12405         if (ssl_ftp_data_active_flag) {
12406             SSL_shutdown(ssl_ftp_data_con);
12407             SSL_free(ssl_ftp_data_con);
12408             ssl_ftp_data_active_flag = 0;
12409             ssl_ftp_data_con = NULL;
12410         }
12411 #endif /* CK_SSL */
12412 #ifdef TCPIPLIB
12413         socket_close(data);
12414 #else /* TCPIPLIB */
12415 #ifdef USE_SHUTDOWN
12416         shutdown(data, 1+1);
12417 #endif /* USE_SHUTDOWN */
12418         close(data);
12419 #endif /* TCPIPLIB */
12420         data = -1;
12421         globaldin = -1;
12422     }
12423     if (!out2screen) {
12424 	int x = 0;
12425 	debug(F111,"ftp failrecv2 zclose",ftprecv.local,keep);
12426 	zclose(ZOFILE);
12427 	switch (keep) {			/* which is... */
12428 	  case SET_AUTO:		/* AUTO */
12429 	    if (curtype == FTT_ASC)	/* Delete file if TYPE A. */
12430 	      x = 1;
12431 	    break;
12432 	  case SET_OFF:			/* DISCARD */
12433 	    x = 1;			/* Delete file, period. */
12434 	    break;
12435 	  default:			/* KEEP */
12436 	    break;
12437 	}
12438 	if (x) {
12439 	    x = zdelet(ftprecv.local);
12440 	    debug(F111,"ftp failrecv2 delete incomplete",ftprecv.local,x);
12441 	}
12442     }
12443     if (ftprecv.din) {
12444 #ifdef TCPIPLIB
12445         socket_close(ftprecv.din);
12446 #else /* TCPIPLIB */
12447 #ifdef USE_SHUTDOWN
12448         shutdown(ftprecv.din, 1+1);
12449 #endif /* USE_SHUTDOWN */
12450         close(ftprecv.din);
12451 #endif /* TCPIPLIB */
12452     }
12453     signal(SIGINT, ftprecv.oldintr);
12454     ftprecvret = -1;
12455 
12456     if (havesigint) {
12457 	havesigint = 0;
12458 	debug(F100,"FTP failftprecv2 chain to trap()...","",0);
12459 #ifdef OS2
12460         debug(F100,"FTP failftprecv2 PostCtrlCSem()...","",0);
12461         PostCtrlCSem();
12462 #else /* OS2 */
12463 	if (ftprecv.oldintr != SIG_IGN)
12464 	  (*ftprecv.oldintr)(SIGINT);
12465 	/* NOTREACHED (I hope!) */
12466 	debug(F100,"ftp failftprecv2 return from trap()...","",0);
12467 #endif /* OS2 */
12468     }
12469 }
12470 
12471 static VOID
12472 #ifdef CK_ANSIC
doftprecv2(VOID * threadinfo)12473 doftprecv2(VOID * threadinfo)
12474 #else
12475 doftprecv2(threadinfo) VOID * threadinfo;
12476 #endif /* CK_ANSIC */
12477 {
12478     register int c, d;
12479     CK_OFF_T bytes = (CK_OFF_T)0;
12480     int bare_lfs = 0;
12481     int blksize = 0;
12482     ULONG start = 0L, stop;
12483     char * p;
12484     static char * rcvbuf = NULL;
12485     static int rcvbufsiz = 0;
12486 #ifdef CK_URL
12487     char newname[CKMAXPATH+1];		/* For file dialog */
12488 #endif /* CK_URL */
12489     extern int adl_ask;
12490 
12491 #ifdef FTP_TIMEOUT
12492     ftp_timed_out = 0;
12493 #endif	/* FTP_TIMEOUT */
12494 
12495     ftprecv.din = -1;
12496 #ifdef NTSIG
12497     if (threadinfo) {                   /* Thread local storage... */
12498         TlsSetValue(TlsIndex,threadinfo);
12499         debug(F100, "docmdfile called with threadinfo block","", 0);
12500     } else debug(F100, "docmdfile - threadinfo is NULL", "", 0);
12501 #endif /* NTSIG */
12502 #ifdef CK_LOGIN
12503 #ifdef IKSD
12504 #ifdef NT
12505     if (inserver)
12506       setntcreds();
12507 #endif /* NT */
12508 #endif /* IKSD */
12509 #endif /* CK_LOGIN */
12510 
12511     if (ftprecv.recover) {                      /* Initiate recovery */
12512         x = ftpcmd("REST",ckfstoa(ftprecv.localsize),-1,-1,ftp_vbm);
12513         debug(F111,"ftp reply","REST",x);
12514         if (x == REPLY_CONTINUE) {
12515             ftprecv.lmode = "ab";
12516             rs_len = ftprecv.localsize;
12517         } else {
12518             ftprecv.recover = 0;
12519         }
12520     }
12521     /* IMPORTANT: No FTP commands can come between REST and RETR! */
12522 
12523     debug(F111,"ftp recvrequest recover E",ftprecv.remote,ftprecv.recover);
12524 
12525     /* Send the command and get reply */
12526     debug(F110,"ftp recvrequest cmd",ftprecv.cmd,0);
12527     debug(F110,"ftp recvrequest remote",ftprecv.remote,0);
12528 
12529     if (ftpcmd(ftprecv.cmd,ftprecv.remote,ftprecv.fcs,ftprecv.rcs,ftp_vbm)
12530 	!= REPLY_PRELIM) {
12531         signal(SIGINT, ftprecv.oldintr); /* Bad reply, fail. */
12532         ftprecvret = -1;		/* ftpcode is set by ftpcmd() */
12533 #ifdef NTSIG
12534         ckThreadEnd(threadinfo);
12535 #endif /* NTSIG */
12536         return;
12537     }
12538     ftprecv.din = dataconn("r");        /* Good reply, open data connection */
12539     globaldin = ftprecv.din;            /* Global copy of file descriptor */
12540     if (ftprecv.din == -1) {            /* Check for failure */
12541         ftpcode = -3;                   /* Code for no data connection */
12542         ftprecvret = -1;
12543 #ifdef NTSIG
12544         ckThreadEnd(threadinfo);
12545 #endif /* NTSIG */
12546         return;
12547     }
12548 #ifdef CK_URL
12549     /* In K95 GUI put up a file box */
12550     if (haveurl && g_url.pth && adl_ask	) { /* Downloading from a URL */
12551 	int x;
12552 	char * preface =
12553 "\r\nIncoming file from FTP server...\r\n\
12554 Please confirm output file specification or supply an alternative:";
12555 
12556 	x = uq_file(preface,		/* K95 GUI: Put up file box. */
12557 		    NULL,
12558 		    4,
12559 		    NULL,
12560 		    ftprecv.local ? ftprecv.local : ftprecv.remote,
12561 		    newname,
12562 		    CKMAXPATH+1
12563 		    );
12564 	if (x > 0) {
12565 	    ftprecv.local = newname;	/* Substitute user's file name */
12566 	    if (x == 2)			/* And append if user said to */
12567 	      ftprecv.lmode = "ab";
12568 	}
12569     }
12570 #endif /* CK_URL */
12571     x = 1;                              /* Output file open OK? */
12572     if (ftprecv.pipename) {		/* Command */
12573         x = zxcmd(ZOFILE,ftprecv.pipename);
12574         debug(F111,"ftp recvrequest zxcmd",ftprecv.pipename,x);
12575     } else if (!out2screen) {           /* File */
12576         struct filinfo xx;
12577         xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12578         xx.typ = 0; xx.os_specific = NUL; xx.lblopts = 0;
12579 	/* Append or New */
12580         xx.dsp = !strcmp(ftprecv.lmode,"ab") ? XYFZ_A : XYFZ_N;
12581         x = zopeno(ZOFILE,ftprecv.local,NULL,&xx);
12582         debug(F111,"ftp recvrequest zopeno",ftprecv.local,x);
12583     }
12584     if (x < 1) {                        /* Failure to open output file */
12585         if ((!dpyactive || ftp_deb))
12586           fprintf(stderr, "local(2): %s: %s\n", ftprecv.local, ck_errstr());
12587         ftprecvret = -1;
12588 #ifdef NTSIG
12589         ckThreadEnd(threadinfo);
12590 #endif /* NTSIG */
12591         return;
12592     }
12593     blksize = FTP_BUFSIZ;               /* Allocate input buffer */
12594 
12595     debug(F101,"ftp recvrequest blksize","",blksize);
12596     debug(F101,"ftp recvrequest rcvbufsiz","",rcvbufsiz);
12597 
12598     if (rcvbufsiz < blksize) {          /* if necessary */
12599         if (rcvbuf) {
12600             free(rcvbuf);
12601             rcvbuf = NULL;
12602         }
12603         rcvbuf = (char *)malloc((unsigned)blksize);
12604         if (!rcvbuf) {
12605 	    debug(F100,"ftp get rcvbuf malloc failed","",0);
12606             ftpcode = -2;
12607 #ifdef ENOMEM
12608             errno = ENOMEM;
12609 #endif /* ENOMEM */
12610             if ((!dpyactive || ftp_deb))
12611               perror("malloc");
12612             rcvbufsiz = 0;
12613             ftprecvret = -1;
12614 #ifdef NTSIG
12615             ckThreadEnd(threadinfo);
12616 #endif /* NTSIG */
12617             return;
12618         }
12619 	debug(F101,"ftp get rcvbuf malloc ok","",blksize);
12620         rcvbufsiz = blksize;
12621     }
12622     debug(F111,"ftp get rcvbufsiz",ftprecv.local,rcvbufsiz);
12623 
12624     ffc = (CK_OFF_T)0;			/* Character counter */
12625     cps = oldcps = 0L;                  /* Thruput */
12626     start = gmstimer();                 /* Start time (msecs) */
12627 #ifdef GFTIMER
12628     rftimer();                          /* Start time (float) */
12629 #endif /* GFTIMER */
12630 
12631     debug(F111,"ftp get type",ftprecv.local,curtype);
12632     debug(F101,"ftp recvrequest ftp_dpl","",ftp_dpl);
12633     switch (curtype) {
12634       case FTT_BIN:                     /* Binary mode */
12635       case FTT_TEN:                     /* TENEX mode */
12636         d = 0;
12637         while (1) {
12638             errno = 0;
12639             c = secure_read(ftprecv.din, rcvbuf, rcvbufsiz);
12640             if (cancelfile) {
12641                 failftprecv2(threadinfo);
12642 #ifdef NTSIG
12643                 ckThreadEnd(threadinfo);
12644 #endif /* NTSIG */
12645                 return;
12646             }
12647             if (c < 1)
12648               break;
12649 #ifdef printf                           /* (What if it isn't?) */
12650             if (out2screen && !ftprecv.pipename) {
12651                 int i;
12652                 for (i = 0; i < c; i++)
12653                   printf("%c",rcvbuf[i]);
12654             } else
12655 #endif /* printf */
12656               {
12657                 register int i;
12658                 i = 0;
12659                 errno = 0;
12660                 while (i < c) {
12661                     if (zmchout(rcvbuf[i++]) < 0) {
12662                         d = i;
12663                         break;
12664                     }
12665                 }
12666             }
12667             bytes += c;
12668             ffc += c;
12669         }
12670 #ifdef FTP_TIMEOUT
12671 	if (c == -3) {
12672             debug(F100,"ftp recvrequest timeout","",0);
12673             bytes = (CK_OFF_T)-1;
12674 	    ftp_timed_out = 1;
12675 	    ftpcode = -3;
12676 	} else
12677 #endif	/* FTP_TIMEOUT */
12678         if (c < 0) {
12679             debug(F111,"ftp recvrequest errno",ckitoa(c),errno);
12680             if (c == -1 && errno != EPIPE)
12681               if ((!dpyactive || ftp_deb))
12682                 perror("netin");
12683             bytes = (CK_OFF_T)-1;
12684             ftpcode = -4;
12685         }
12686         if (d < c) {
12687             ftpcode = -2;
12688             if ((!dpyactive || ftp_deb)) {
12689                 char * p;
12690                 p = ftprecv.local ? ftprecv.local : ftprecv.pipename;
12691                 if (d < 0)
12692                   fprintf(stderr,
12693 			  "local(3): %s: %s\n", ftprecv.local, ck_errstr());
12694                 else
12695                   fprintf(stderr,
12696 			  "%s: short write\n", ftprecv.local);
12697             }
12698         }
12699         break;
12700 
12701       case FTT_ASC:                     /* Text mode */
12702 	debug(F101,"ftp recvrequest TYPE A xlate","",ftprecv.xlate);
12703 #ifndef NOCSETS
12704         if (ftprecv.xlate) {
12705             int t;
12706 #ifdef CK_ANSIC
12707             int (*fn)(char);
12708 #else
12709             int (*fn)();
12710 #endif /* CK_ANSIC */
12711             debug(F110,"ftp recvrequest (data)","initxlate",0);
12712             initxlate(ftprecv.rcs,ftprecv.fcs);         /* (From,To) */
12713             if (ftprecv.pipename) {
12714                 fn = pipeout;
12715                 debug(F110,"ftp recvrequest ASCII","pipeout",0);
12716             } else {
12717                 fn = out2screen ? scrnout : putfil;
12718                 debug(F110,"ftp recvrequest ASCII",
12719                       out2screen ? "scrnout" : "putfil",0);
12720             }
12721             while (1) {
12722 		/* Get byte from net */
12723                 c0 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12724                 if (cancelfile) {
12725                     failftprecv2(threadinfo);
12726 #ifdef NTSIG
12727                     ckThreadEnd(threadinfo);
12728 #endif /* NTSIG */
12729                     return;
12730                 }
12731                 if (c0 < 0)
12732                   break;
12733 		/* Second byte from net */
12734                 c1 = xgnbyte(FC_UCS2,ftprecv.rcs,netgetc);
12735                 if (cancelfile) {
12736                     failftprecv2(threadinfo);
12737 #ifdef NTSIG
12738                     ckThreadEnd(threadinfo);
12739 #endif /* NTSIG */
12740                     return;
12741                 }
12742                 if (c1 < 0)
12743                   break;
12744 #ifdef COMMENT
12745 		/* K95: Check whether we need this */
12746 		if (fileorder > 0)	/* Little Endian */
12747 		  bytswap(&c0,&c1);	/* swap bytes*/
12748 #endif /* COMMENT */
12749 
12750 #ifdef OS2
12751                 if ( out2screen &&            /* we're translating to UCS-2 */
12752                      !k95stdout && !inserver) /* for the real screen... */
12753                 {
12754                     union {
12755                         USHORT ucs2;
12756                         UCHAR  bytes[2];
12757                     } output;
12758 
12759                     output.bytes[0] = c1;
12760                     output.bytes[1] = c0;
12761 
12762                     VscrnWrtUCS2StrAtt(VCMD,
12763                                        &output.ucs2,
12764                                        1,
12765                                        wherey[VCMD],
12766                                        wherex[VCMD],
12767                                        &colorcmd
12768                                        );
12769 
12770                 } else
12771 #endif /* OS2 */
12772                 {
12773                     if ((x = xpnbyte(c0,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12774                     if ((x = xpnbyte(c1,TC_UCS2,ftprecv.fcs,fn)) < 0) break;
12775                 }
12776             }
12777         } else {
12778 #endif /* NOCSETS */
12779             while (1) {
12780                 c = secure_getc(ftprecv.din,0);
12781                 if (cancelfile
12782 #ifdef FTP_TIMEOUT
12783 		    || ftp_timed_out
12784 #endif	/* FTP_TIMEOUT */
12785 		    ) {
12786                     failftprecv2(threadinfo);
12787 #ifdef NTSIG
12788                     ckThreadEnd(threadinfo);
12789 #endif /* NTSIG */
12790                     return;
12791                 }
12792                 if (c < 0 || c == EOF)
12793                   break;
12794 #ifdef UNIX
12795 		/* Record format conversion for Unix */
12796 		/* SKIP THIS FOR WINDOWS! */
12797                 if (c == '\n')
12798                   bare_lfs++;
12799                 while (c == '\r') {
12800                     bytes++;
12801                     if ((c = secure_getc(ftprecv.din,0)) != '\n' ||
12802 			ftprecv.tcrflag) {
12803                         if (cancelfile) {
12804                             failftprecv2(threadinfo);
12805 #ifdef NTSIG
12806                             ckThreadEnd(threadinfo);
12807 #endif /* NTSIG */
12808                             return;
12809                         }
12810                         if (c < 0 || c == EOF)
12811                           goto break2;
12812                         if (c == '\0') {
12813                             bytes++;
12814                             goto contin2;
12815                         }
12816                     }
12817                 }
12818                 if (c < 0)
12819                   break;
12820 #endif /* UNX */
12821 
12822                 if (out2screen && !ftprecv.pipename)
12823 #ifdef printf
12824                   printf("%c",(char)c);
12825 #else
12826                   putchar((char)c);
12827 #endif /* printf */
12828                 else
12829                   if ((d = zmchout(c)) < 0)
12830                     break;
12831                 bytes++;
12832                 ffc++;
12833               contin2:
12834                 ;
12835             }
12836           break2:
12837             if (bare_lfs && (!dpyactive || ftp_deb)) {
12838                 printf("WARNING! %d bare linefeeds received in ASCII mode\n",
12839                        bare_lfs);
12840                 printf("File might not have transferred correctly.\n");
12841             }
12842             if (ftprecv.din == -1) {
12843                 bytes = (CK_OFF_T)-1;
12844             }
12845             if (c == -2)
12846               bytes = (CK_OFF_T)-1;
12847             break;
12848 #ifndef NOCSETS
12849         }
12850 #endif /* NOCSETS */
12851     }
12852     if (ftprecv.pipename || !out2screen) {
12853 	zclose(ZOFILE);			/* Close the file */
12854 	debug(F111,"doftprecv2 zclose ftpcode",ftprecv.local,ftpcode);
12855 	if (ftpcode < 0) {		/* If download failed */
12856 	    int x = 0;
12857 	    switch (keep) {		/* which is... */
12858 	      case SET_AUTO:		/* AUTO */
12859 		if (curtype == FTT_ASC) /* Delete file if TYPE A. */
12860 		  x = 1;
12861 		break;
12862 	      case SET_OFF:		/* DISCARD */
12863 		x = 1;			/* Delete file, period. */
12864 		break;
12865 	      default:			/* KEEP */
12866 		break;
12867 	    }
12868 	    if (x) {
12869 		x = zdelet(ftprecv.local);
12870 		debug(F111,"ftp get delete incomplete",ftprecv.local,x);
12871 	    }
12872 	}
12873     }
12874     signal(SIGINT, ftprecv.oldintr);
12875 #ifdef SIGPIPE
12876     if (ftprecv.oldintp)
12877       signal(SIGPIPE, ftprecv.oldintp);
12878 #endif /* SIGPIPE */
12879     stop = gmstimer();
12880 #ifdef GFTIMER
12881     fpfsecs = gftimer();
12882 #endif /* GFTIMER */
12883     tfc += ffc;
12884 
12885 #ifdef TCPIPLIB
12886     socket_close(ftprecv.din);
12887 #else /* TCPIPLIB */
12888 #ifdef USE_SHUTDOWN
12889     shutdown(ftprecv.din, 1+1);
12890 #endif /* USE_SHUTDOWN */
12891     close(ftprecv.din);
12892 #endif /* TCPIPLIB */
12893     ftprecv.reply = getreply(0,ftprecv.fcs,ftprecv.rcs,ftp_vbm,0);
12894     ftprecvret = ((ftpcode < 0 || ftprecv.reply == REPLY_TRANSIENT ||
12895                    ftprecv.reply == REPLY_ERROR) ? -1 : 0);
12896 #ifdef NTSIG
12897      ckThreadEnd(threadinfo);
12898 #endif /* NTSIG */
12899 }
12900 
12901 static int
recvrequest(cmd,local,remote,lmode,printnames,recover,pipename,xlate,fcs,rcs)12902 recvrequest(cmd, local, remote, lmode, printnames, recover, pipename,
12903             xlate, fcs, rcs)
12904     char *cmd, *local, *remote, *lmode, *pipename;
12905     int printnames, recover, xlate, fcs, rcs;
12906 {
12907 #ifdef NT
12908     struct _stat stbuf;
12909 #else /* NT */
12910     struct stat stbuf;
12911 #endif /* NT */
12912 
12913 #ifdef DEBUG
12914     if (deblog) {
12915         debug(F111,"ftp recvrequest cmd",cmd,recover);
12916         debug(F110,"ftp recvrequest local ",local,0);
12917         debug(F111,"ftp recvrequest remote",remote,ftp_typ);
12918         debug(F110,"ftp recvrequest pipename ",pipename,0);
12919         debug(F101,"ftp recvrequest xlate","",xlate);
12920         debug(F101,"ftp recvrequest fcs","",fcs);
12921         debug(F101,"ftp recvrequest rcs","",rcs);
12922     }
12923 #endif /* DEBUG */
12924 
12925     ftprecv.localsize = (CK_OFF_T)0;
12926 
12927     if (remfile) {                      /* See remcfm(), remtxt() */
12928         if (rempipe) {
12929             pipename = remdest;
12930         } else {
12931             local = remdest;
12932             if (remappd) lmode = "ab";
12933         }
12934     }
12935     out2screen = 0;
12936     if (!cmd) cmd = "";                 /* Core dump prevention */
12937     if (!remote) remote = "";
12938     if (!lmode) lmode = "";
12939 
12940     if (pipename) {                     /* No recovery for pipes. */
12941         recover = 0;
12942         if (!local)
12943           local = pipename;
12944     } else {
12945         if (!local)                     /* Output to screen? */
12946           local = "-";
12947         out2screen = !strcmp(local,"-");
12948     }
12949     debug(F101,"ftp recvrequest out2screen","",out2screen);
12950 
12951 #ifdef OS2
12952     if ( ftp_xla && out2screen && !k95stdout && !inserver )
12953         fcs = FC_UCS2;
12954 #endif /* OS2 */
12955 
12956     if (out2screen)                     /* No recovery to screen */
12957       recover = 0;
12958     if (!ftp_typ)                       /* No recovery in text mode */
12959       recover = 0;
12960     ftprecv.is_retr = (strcmp(cmd, "RETR") == 0);
12961 
12962     if (!ftprecv.is_retr)               /* No recovery except for RETRieve */
12963       recover = 0;
12964 
12965 #ifdef COMMENT
12966     if (!out2screen && !pipename && ftprecv.is_retr) { /* To real file */
12967         if (recursive && ckstrchr(local,'/')) {
12968 
12969         }
12970     }
12971 #endif /* COMMENT */
12972 
12973     ftprecv.localsize = (CK_OFF_T)0;	/* Local file size */
12974     rs_len = (CK_OFF_T)0;		/* Recovery point */
12975 
12976     debug(F101,"ftp recvrequest recover","",recover);
12977     if (recover) {                      /* Recovering... */
12978         if (stat(local, &stbuf) < 0) {  /* Can't stat local file */
12979 	    debug(F101,"ftp recvrequest recover stat failed","",errno);
12980             recover = 0;                /* So cancel recovery */
12981         } else {                        /* Have local file info */
12982             ftprecv.localsize = stbuf.st_size;  /* Get size */
12983 	    /* Remote file smaller than local */
12984             if (fsize < ftprecv.localsize) {
12985 		debug(F101,"ftp recvrequest recover remote smaller","",fsize);
12986                 recover = 0;            /* Recovery can't work */
12987             } else if (fsize == ftprecv.localsize) { /* Sizes are equal */
12988                 debug(F111,"ftp recvrequest recover equal size",
12989 		      remote,ftprecv.localsize);
12990                 return(1);
12991             }
12992 #ifdef COMMENT
12993 /*
12994   The problem here is that the original partial file never got its date
12995   set, either because FTP DATES was OFF, or because the partial file was
12996   downloaded by some other program that doesn't set local file dates, or
12997   because Kermit only sets the file's date when the download was complete
12998   and successful.  In all these cases, the local file has a later time
12999   than the remote.
13000 */
13001             if (recover) {              /* Remote is bigger */
13002                 x = chkmodtime(local,remote,0); /* Check file dates */
13003                 debug(F111,"ftp recvrequest chkmodtime",remote,x);
13004                 if (x != 1)		/* Dates must be equal! */
13005                   recover = 0;          /* If not, get whole file */
13006             }
13007 #endif /* COMMENT */
13008         }
13009         debug(F111,"ftp recvrequest recover",remote,recover);
13010     }
13011 
13012 #ifdef FTP_PROXY
13013     if (proxy && ftprecv.is_retr)
13014       return(proxtrans(cmd, local ? local : remote, remote));
13015 #endif /* FTP_PROXY */
13016 
13017     ftprecv.tcrflag = (feol != CR) && ftprecv.is_retr;
13018 
13019     ftprecv.reply = 0;
13020     ftprecv.fcs = fcs;
13021     ftprecv.rcs = rcs;
13022     ftprecv.recover = recover;
13023     ftprecv.xlate = xlate;
13024     ftprecv.cmd = cmd;
13025     ftprecv.local = local;
13026     ftprecv.remote = remote;
13027     ftprecv.lmode = lmode;
13028     ftprecv.pipename = pipename;
13029     ftprecv.oldintp = NULL;
13030     ftpcode = 0;
13031 
13032     havesigint = 0;
13033     ftprecv.oldintr = signal(SIGINT, cancelrecv);
13034     if (cc_execute(ckjaddr(recvcancel), doftprecv, failftprecv) < 0)
13035       return -1;
13036 
13037 #ifdef FTP_TIMEOUT
13038     debug(F111,"ftp recvrequest ftprecvret",remote,ftprecvret);
13039     debug(F111,"ftp recvrequest ftp_timed_out",remote,ftp_timed_out);
13040     if (ftp_timed_out)
13041       ftprecvret = -1;
13042 #endif	/* FTP_TIMEOUT */
13043 
13044     if (ftprecvret < 0)
13045       return -1;
13046 
13047     if (cc_execute(ckjaddr(recvcancel), doftprecv2, failftprecv2) < 0)
13048       return -1;
13049     return ftprecvret;
13050 }
13051 
13052 /*
13053  * Need to start a listen on the data channel before we send the command,
13054  * otherwise the server's connect may fail.
13055  */
13056 static int
initconn()13057 initconn() {
13058     register char *p, *a;
13059     int result, tmpno = 0;
13060     int on = 1;
13061     GSOCKNAME_T len;
13062 
13063 #ifndef NO_PASSIVE_MODE
13064     int a1,a2,a3,a4,p1,p2;
13065 
13066     if (passivemode) {
13067         data = socket(AF_INET, SOCK_STREAM, 0);
13068         globaldin = data;
13069         if (data < 0) {
13070             perror("ftp: socket");
13071             return(-1);
13072         }
13073         if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13074             printf("Passive mode refused\n");
13075             passivemode = 0;
13076             return(initconn());
13077         }
13078 /*
13079   Now we have a string of comma-separated one-byte unsigned integer values,
13080   The first four are the an IP address.  The fifth is the MSB of the port
13081   number, the sixth is the LSB.  From that we can make a sockaddr_in.
13082 */
13083         if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
13084             printf("Passive mode address scan failure\n");
13085             return(-1);
13086         };
13087 #ifndef NOHTTP
13088         if (tcp_http_proxy) {
13089 #ifdef OS2
13090             char * agent = "Kermit 95"; /* Default user agent */
13091 #else
13092             char * agent = "C-Kermit";
13093 #endif /* OS2 */
13094             register struct hostent *hp = 0;
13095             struct servent *destsp;
13096             char host[512], *p, *q;
13097 #ifdef IP_TOS
13098 #ifdef IPTOS_THROUGHPUT
13099             int tos;
13100 #endif /* IPTOS_THROUGHPUT */
13101 #endif /* IP_TOS */
13102             int s;
13103 #ifdef DEBUG
13104             extern int debtim;
13105             int xdebtim;
13106             xdebtim = debtim;
13107             debtim = 1;
13108 #endif /* DEBUG */
13109 
13110             ckmakxmsg(proxyhost,HTTPCPYL,ckuitoa(a1),".",ckuitoa(a2),
13111                       ".",ckuitoa(a3),".",ckuitoa(a4),":",ckuitoa((p1<<8)|p2),
13112                       NULL,NULL,NULL
13113                       );
13114             memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
13115             for (p = tcp_http_proxy, q=host; *p != '\0' && *p != ':'; p++, q++)
13116               *q = *p;
13117             *q = '\0';
13118 
13119             hisctladdr.sin_addr.s_addr = inet_addr(host);
13120             if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
13121 	    {
13122                 debug(F110,"initconn A",host,0);
13123                 hisctladdr.sin_family = AF_INET;
13124             } else {
13125                 debug(F110,"initconn B",host,0);
13126                 hp = gethostbyname(host);
13127 #ifdef HADDRLIST
13128                 hp = ck_copyhostent(hp); /* make safe copy that won't change */
13129 #endif /* HADDRLIST */
13130                 if (hp == NULL) {
13131                     fprintf(stderr, "ftp: %s: Unknown host\n", host);
13132                     ftpcode = -1;
13133 #ifdef DEBUG
13134                     debtim = xdebtim;
13135 #endif /* DEBUG */
13136                     return(0);
13137                 }
13138                 hisctladdr.sin_family = hp->h_addrtype;
13139 #ifdef HADDRLIST
13140                 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
13141                        sizeof(hisctladdr.sin_addr));
13142 #else /* HADDRLIST */
13143                 memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
13144                        sizeof(hisctladdr.sin_addr));
13145 #endif /* HADDRLIST */
13146             }
13147             data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13148             debug(F101,"initconn socket","",data);
13149             if (data < 0) {
13150                 perror("ftp: socket");
13151                 ftpcode = -1;
13152 #ifdef DEBUG
13153                 debtim = xdebtim;
13154 #endif /* DEBUG */
13155                 return(0);
13156             }
13157             if (*p == ':')
13158               p++;
13159             else
13160               p = "http";
13161 
13162             destsp = getservbyname(p,"tcp");
13163             if (destsp)
13164               hisctladdr.sin_port = destsp->s_port;
13165             else if (p)
13166               hisctladdr.sin_port = htons(atoi(p));
13167             else
13168               hisctladdr.sin_port = htons(80);
13169             errno = 0;
13170 #ifdef HADDRLIST
13171             debug(F100,"initconn HADDRLIST","",0);
13172             while
13173 #else
13174             debug(F100,"initconn no HADDRLIST","",0);
13175             if
13176 #endif /* HADDRLIST */
13177               (connect(data, (struct sockaddr *)&hisctladdr,
13178                        sizeof (hisctladdr)) < 0) {
13179                   debug(F101,"initconn connect failed","",errno);
13180 #ifdef HADDRLIST
13181                   if (hp && hp->h_addr_list[1]) {
13182                       int oerrno = errno;
13183 
13184                       fprintf(stderr,
13185                               "ftp: connect to address %s: ",
13186                               inet_ntoa(hisctladdr.sin_addr)
13187                               );
13188                       errno = oerrno;
13189                       perror("ftphookup");
13190                       hp->h_addr_list++;
13191                       memcpy((char *)&hisctladdr.sin_addr,
13192                              hp->h_addr_list[0],
13193                              sizeof(hisctladdr.sin_addr));
13194                       fprintf(stdout, "Trying %s...\n",
13195                               inet_ntoa(hisctladdr.sin_addr));
13196 #ifdef TCPIPLIB
13197                       socket_close(data);
13198 #else /* TCPIPLIB */
13199                       close(data);
13200 #endif /* TCPIPLIB */
13201                       data = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
13202                       if (data < 0) {
13203                           perror("ftp: socket");
13204                           ftpcode = -1;
13205 #ifdef DEBUG
13206                           debtim = xdebtim;
13207 #endif /* DEBUG */
13208                           return(0);
13209                       }
13210                       continue;
13211                   }
13212 #endif /* HADDRLIST */
13213                   perror("ftp: connect");
13214                   ftpcode = -1;
13215                   goto bad;
13216               }
13217             if (http_connect(data,
13218                              tcp_http_proxy_agent ?
13219 			       tcp_http_proxy_agent :
13220 			         agent,
13221 			     NULL,
13222                              tcp_http_proxy_user,
13223                              tcp_http_proxy_pwd,
13224                              0,
13225                              proxyhost
13226                              ) < 0) {
13227 #ifdef TCPIPLIB
13228                 socket_close(data);
13229 #else /* TCPIPLIB */
13230                 close(data);
13231 #endif /* TCPIPLIB */
13232                 perror("ftp: connect");
13233                 ftpcode = -1;
13234                 goto bad;
13235             }
13236         } else
13237 #endif /* NOHTTP */
13238         {
13239             data_addr.sin_family = AF_INET;
13240             data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
13241             data_addr.sin_port = htons((p1<<8)|p2);
13242 
13243             if (connect(data,
13244                         (struct sockaddr *)&data_addr,
13245                         sizeof(data_addr)) < 0
13246                 ) {
13247                 perror("ftp: connect");
13248                 return(-1);
13249             }
13250         }
13251         debug(F100,"initconn connect ok","",0);
13252 #ifdef IP_TOS
13253 #ifdef IPTOS_THROUGHPUT
13254         on = IPTOS_THROUGHPUT;
13255         if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13256           perror("ftp: setsockopt TOS (ignored)");
13257 #endif /* IPTOS_THROUGHPUT */
13258 #endif /* IP_TOS */
13259         memcpy(&hisdataaddr,&data_addr,sizeof(struct sockaddr_in));
13260         return(0);
13261     }
13262 #endif /* NO_PASSIVE_MODE */
13263 
13264   noport:
13265     memcpy(&data_addr,&myctladdr,sizeof(struct sockaddr_in));
13266     if (sendport)
13267       data_addr.sin_port = 0;   /* let system pick one */
13268     if (data != -1) {
13269 #ifdef TCPIPLIB
13270         socket_close(data);
13271 #else /* TCPIPLIB */
13272 #ifdef USE_SHUTDOWN
13273         shutdown(data, 1+1);
13274 #endif /* USE_SHUTDOWN */
13275         close(data);
13276 #endif /* TCPIPLIB */
13277     }
13278     data = socket(AF_INET, SOCK_STREAM, 0);
13279     globaldin = data;
13280     if (data < 0) {
13281         perror("ftp: socket");
13282         if (tmpno)
13283           sendport = 1;
13284         return(-1);
13285     }
13286     if (!sendport) {
13287         if (setsockopt(data,
13288                        SOL_SOCKET,
13289                        SO_REUSEADDR,
13290                        (char *)&on,
13291                        sizeof (on)
13292                        ) < 0
13293             ) {
13294             perror("ftp: setsockopt (reuse address)");
13295             goto bad;
13296         }
13297     }
13298     if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
13299         perror("ftp: bind");
13300         goto bad;
13301     }
13302     len = sizeof (data_addr);
13303     if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
13304         perror("ftp: getsockname");
13305         goto bad;
13306     }
13307     if (listen(data, 1) < 0) {
13308         perror("ftp: listen");
13309         goto bad;
13310     }
13311     if (sendport) {
13312         a = (char *)&data_addr.sin_addr;
13313         p = (char *)&data_addr.sin_port;
13314         ckmakxmsg(ftpcmdbuf,FTP_BUFSIZ,"PORT ",
13315                   UC(a[0]),",",UC(a[1]),",", UC(a[2]),",", UC(a[3]),",",
13316                   UC(p[0]),",", UC(p[1]));
13317         result = ftpcmd(ftpcmdbuf,NULL,0,0,ftp_vbm);
13318         if (result == REPLY_ERROR && sendport) {
13319             sendport = 0;
13320             tmpno = 1;
13321             goto noport;
13322         }
13323         return(result != REPLY_COMPLETE);
13324     }
13325     if (tmpno)
13326       sendport = 1;
13327 #ifdef IP_TOS
13328 #ifdef IPTOS_THROUGHPUT
13329     on = IPTOS_THROUGHPUT;
13330     if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
13331       perror("ftp: setsockopt TOS (ignored)");
13332 #endif
13333 #endif
13334     return(0);
13335   bad:
13336 #ifdef TCPIPLIB
13337     socket_close(data);
13338 #else /* TCPIPLIB */
13339 #ifdef USE_SHUTDOWN
13340     shutdown(data, 1+1);
13341 #endif /* USE_SHUTDOWN */
13342     close(data);
13343 #endif /* TCPIPLIB */
13344     data = -1;
13345     globaldin = data;
13346     if (tmpno)
13347       sendport = 1;
13348     return(-1);
13349 }
13350 
13351 #ifdef CK_SSL
13352 static int
ssl_dataconn()13353 ssl_dataconn() {
13354     if (ssl_ftp_data_con!=NULL) {       /* Do SSL */
13355         SSL_free(ssl_ftp_data_con);
13356         ssl_ftp_data_con=NULL;
13357     }
13358     ssl_ftp_data_con=(SSL *)SSL_new(ssl_ftp_ctx);
13359 
13360     SSL_set_fd(ssl_ftp_data_con,data);
13361     SSL_set_verify(ssl_ftp_data_con,ssl_verify_flag,NULL);
13362 
13363     SSL_copy_session_id(ssl_ftp_data_con,ssl_ftp_con);
13364 
13365     if (ssl_debug_flag) {
13366         fprintf(stderr,"=>START SSL connect on DATA\n");
13367         fflush(stderr);
13368     }
13369     if (SSL_connect(ssl_ftp_data_con) <= 0) {
13370         static char errbuf[1024];
13371         ckmakmsg(errbuf,1024,"ftp: SSL_connect DATA error: ",
13372                   ERR_error_string(ERR_get_error(),NULL),NULL,NULL);
13373         fprintf(stderr,"%s\n", errbuf);
13374         fflush(stderr);
13375 #ifdef TCPIPLIB
13376         socket_close(data);
13377 #else /* TCPIPLIB */
13378 #ifdef USE_SHUTDOWN
13379         shutdown(data, 1+1);
13380 #endif /* USE_SHUTDOWN */
13381         close(data);
13382 #endif /* TCPIPLIB */
13383         data = -1;
13384         globaldin = data;
13385         return(-1);
13386     } else {
13387         ssl_ftp_data_active_flag=1;
13388 
13389         if (!ssl_certsok_flag &&
13390 	    (ssl_verify_flag & SSL_VERIFY_PEER) && /* JEA 2013-12-10 */
13391 	    !tls_is_krb5(2)) {
13392             char *subject = ssl_get_subject_name(ssl_ftp_data_con);
13393 
13394             if (!subject) {
13395                 if (ssl_verify_flag & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
13396                     debug(F110,"dataconn","[SSL _- FAILED]",0);
13397 
13398                     ssl_ftp_data_active_flag = 0;
13399 #ifdef TCPIPLIB
13400                     socket_close(data);
13401 #else /* TCPIPLIB */
13402 #ifdef USE_SHUTDOWN
13403                     shutdown(data, 1+1);
13404 #endif /* USE_SHUTDOWN */
13405                     close(data);
13406 #endif /* TCPIPLIB */
13407                     data = -1;
13408                     globaldin = data;
13409                     return(-1);
13410                 } else {
13411                     if (!out2screen && displa && fdispla) {
13412                         ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13413                         /* fdispla = XYFD_B; */
13414                     }
13415 
13416                     if (uq_ok(
13417           "Warning: Server didn't provide a certificate on data connection\n",
13418                                "Continue with file transfer? (Y/N)",
13419                               3,NULL,0) <= 0) {
13420                         debug(F110, "dataconn","[SSL - FAILED]",0);
13421                         ssl_ftp_data_active_flag = 0;
13422 #ifdef TCPIPLIB
13423                         socket_close(data);
13424 #else /* TCPIPLIB */
13425 #ifdef USE_SHUTDOWN
13426                         shutdown(data, 1+1);
13427 #endif /* USE_SHUTDOWN */
13428                         close(data);
13429 #endif /* TCPIPLIB */
13430                         data = -1;
13431                         globaldin = data;
13432                         return(-1);
13433                     }
13434                 }
13435             } else {
13436                 if (!out2screen && displa && fdispla == XYFD_C) {
13437                     ftscreen(SCR_TC,0,(CK_OFF_T)0,"Display canceled");
13438                     /* fdispla = XYFD_B; */
13439                 }
13440 
13441                 if (ssl_check_server_name(ssl_ftp_data_con,ftp_user_host)) {
13442                     debug(F110,"dataconn","[SSL - FAILED]",0);
13443                     ssl_ftp_data_active_flag = 0;
13444 #ifdef TCPIPLIB
13445                     socket_close(data);
13446 #else /* TCPIPLIB */
13447 #ifdef USE_SHUTDOWN
13448                     shutdown(data, 1+1);
13449 #endif /* USE_SHUTDOWN */
13450                     close(data);
13451 #endif /* TCPIPLIB */
13452                     data = -1;
13453                     globaldin = data;
13454                     return(-1);
13455                 }
13456             }
13457         }
13458         debug(F110,"dataconn","[SSL - OK]",0);
13459 #ifdef COMMENT
13460         /* This messes up the full screen file transfer display */
13461         ssl_display_connect_details(ssl_ftp_con,0,ssl_verbose_flag);
13462 #endif /* COMMENT */
13463     }
13464     if (ssl_debug_flag) {
13465         fprintf(stderr,"=>DONE SSL connect on DATA\n");
13466         fflush(stderr);
13467     }
13468     return(data);
13469 }
13470 #endif /* CK_SSL */
13471 
13472 static int
dataconn(lmode)13473 dataconn(lmode) char *lmode; {
13474     int s;
13475 #ifdef IP_TOS
13476     int tos;
13477 #endif /* IP_TOS */
13478 #ifdef UCX50
13479     static u_int fromlen;
13480 #else
13481     static SOCKOPT_T fromlen;
13482 #endif /* UCX50 */
13483 
13484     fromlen = sizeof(hisdataaddr);
13485 
13486 #ifndef NO_PASSIVE_MODE
13487     if (passivemode) {
13488 #ifdef CK_SSL
13489         ssl_ftp_data_active_flag=0;
13490         if (ssl_ftp_active_flag &&
13491             (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13492           return(ssl_dataconn());
13493 #endif /* CK_SSL */
13494         return(data);
13495     }
13496 #endif /* NO_PASSIVE_MODE */
13497 
13498     s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
13499     if (s < 0) {
13500         perror("ftp: accept");
13501 #ifdef TCPIPLIB
13502         socket_close(data);
13503 #else /* TCPIPLIB */
13504 #ifdef USE_SHUTDOWN
13505         shutdown(data, 1+1);
13506 #endif /* USE_SHUTDOWN */
13507         close(data);
13508 #endif /* TCPIPLIB */
13509         data = -1;
13510         globaldin = data;
13511         return(-1);
13512     }
13513 #ifdef TCPIPLIB
13514     socket_close(data);
13515 #else /* TCPIPLIB */
13516 #ifdef USE_SHUTDOWN
13517     shutdown(data, 1+1);
13518 #endif /* USE_SHUTDOWN */
13519     close(data);
13520 #endif /* TCPIPLIB */
13521     data = s;
13522     globaldin = data;
13523 #ifdef IP_TOS
13524 #ifdef IPTOS_THROUGHPUT
13525     tos = IPTOS_THROUGHPUT;
13526     if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
13527       perror("ftp: setsockopt TOS (ignored)");
13528 #endif /* IPTOS_THROUGHPUT */
13529 #endif /* IP_TOS */
13530 
13531 #ifdef CK_SSL
13532     ssl_ftp_data_active_flag=0;
13533     if (ssl_ftp_active_flag &&
13534         (ssl_ftp_proxy || ftp_dpl == FPL_PRV))
13535       return(ssl_dataconn());
13536 #endif /* CK_SSL */
13537     return(data);
13538 }
13539 
13540 #ifdef FTP_PROXY
13541 static sigtype
pscancel(sig)13542 pscancel(sig) int sig; {
13543     cancelfile++;
13544 }
13545 
13546 static VOID
pswitch(flag)13547 pswitch(flag) int flag; {
13548     extern int proxy;
13549     sig_t oldintr;
13550     static struct comvars {
13551         int connect;
13552         char name[MAXHOSTNAMELEN];
13553         struct sockaddr_in mctl;
13554         struct sockaddr_in hctl;
13555         FILE *in;
13556         FILE *out;
13557         int tpe;
13558         int curtpe;
13559         int cpnd;
13560         int sunqe;
13561         int runqe;
13562         int mcse;
13563         int ntflg;
13564         char nti[17];
13565         char nto[17];
13566         int mapflg;
13567         char mi[CKMAXPATH];
13568         char mo[CKMAXPATH];
13569         char *authtype;
13570         int clvl;
13571         int dlvl;
13572 #ifdef FTP_KRB4
13573         des_cblock session;
13574         des_key_schedule ftp_sched;
13575 #endif /* FTP_KRB4 */
13576 #ifdef FTP_GSSAPI
13577         gss_ctx_id_t gcontext;
13578 #endif /* GSSAPI */
13579     } proxstruct, tmpstruct;
13580     struct comvars *ip, *op;
13581 
13582     cancelfile = 0;
13583     oldintr = signal(SIGINT, pscancel);
13584     if (flag) {
13585         if (proxy)
13586           return;
13587         ip = &tmpstruct;
13588         op = &proxstruct;
13589         proxy++;
13590     } else {
13591         if (!proxy)
13592           return;
13593         ip = &proxstruct;
13594         op = &tmpstruct;
13595         proxy = 0;
13596     }
13597     ip->connect = connected;
13598     connected = op->connect;
13599     if (ftp_host) {
13600         strncpy(ip->name, ftp_host, MAXHOSTNAMELEN - 1);
13601         ip->name[MAXHOSTNAMELEN - 1] = '\0';
13602         ip->name[strlen(ip->name)] = '\0';
13603     } else
13604       ip->name[0] = 0;
13605     ftp_host = op->name;
13606     ip->hctl = hisctladdr;
13607     hisctladdr = op->hctl;
13608     ip->mctl = myctladdr;
13609     myctladdr = op->mctl;
13610     ip->in = csocket;
13611     csocket = op->in;
13612     ip->out = csocket;
13613     csocket = op->out;
13614     ip->tpe = ftp_typ;
13615     ftp_typ = op->tpe;
13616     ip->curtpe = curtype;
13617     curtype = op->curtpe;
13618     ip->cpnd = cpend;
13619     cpend = op->cpnd;
13620     ip->sunqe = ftp_usn;
13621     ftp_usn = op->sunqe;
13622     ip->mcse = mcase;
13623     mcase = op->mcse;
13624     ip->ntflg = ntflag;
13625     ntflag = op->ntflg;
13626     strncpy(ip->nti, ntin, 16);
13627     (ip->nti)[strlen(ip->nti)] = '\0';
13628     strcpy(ntin, op->nti);
13629     strncpy(ip->nto, ntout, 16);
13630     (ip->nto)[strlen(ip->nto)] = '\0';
13631     strcpy(ntout, op->nto);
13632     ip->mapflg = mapflag;
13633     mapflag = op->mapflg;
13634     strncpy(ip->mi, mapin, CKMAXPATH - 1);
13635     (ip->mi)[strlen(ip->mi)] = '\0';
13636     strcpy(mapin, op->mi);
13637     strncpy(ip->mo, mapout, CKMAXPATH - 1);
13638     (ip->mo)[strlen(ip->mo)] = '\0';
13639     strcpy(mapout, op->mo);
13640     ip->authtype = auth_type;
13641     auth_type = op->authtype;
13642     ip->clvl = ftp_cpl;
13643     ftp_cpl = op->clvl;
13644     ip->dlvl = ftp_dpl;
13645     ftp_dpl = op->dlvl;
13646     if (!ftp_cpl)
13647       ftp_cpl = FPL_CLR;
13648     if (!ftp_dpl)
13649       ftp_dpl = FPL_CLR;
13650 #ifdef FTP_KRB4
13651     memcpy(ip->session, ftp_cred.session, sizeof(ftp_cred.session));
13652     memcpy(ftp_cred.session, op->session, sizeof(ftp_cred.session));
13653     memcpy(ip->schedule, ftp_sched, sizeof(ftp_sched));
13654     memcpy(ftp_sched, op->schedule, sizeof(ftp_sched));
13655 #endif /* FTP_KRB4 */
13656 #ifdef FTP_GSSAPI
13657     ip->gcontext = gcontext;
13658     gcontext = op->gcontext;
13659 #endif /* GSSAPI */
13660     signal(SIGINT, oldintr);
13661     if (cancelfile) {
13662         cancelfile = 0;
13663         debug(F101,"pswitch cancelfile B","",cancelfile);
13664         (*oldintr)(SIGINT);
13665     }
13666 }
13667 
13668 static sigtype
cancelpt(sig)13669 cancelpt(sig) int sig; {
13670     printf("\n");
13671     fflush(stdout);
13672     ptabflg++;
13673     cancelfile = 0;
13674 #ifndef OS2
13675     longjmp(ptcancel, 1);
13676 #else
13677     PostCtrlCSem();
13678 #endif /* OS2 */
13679 }
13680 
13681 void
proxtrans(cmd,local,remote,unique)13682 proxtrans(cmd, local, remote, unique) char *cmd, *local, *remote; int unique; {
13683     sig_t oldintr;
13684     int secndflag = 0, prox_type, nfnd;
13685     char *cmd2;
13686 #ifdef BSDSELECT
13687     fd_set mask;
13688 #endif /* BSDSELECT */
13689     sigtype cancelpt();
13690 
13691     if (strcmp(cmd, "RETR"))
13692       cmd2 = "RETR";
13693     else
13694       cmd2 = unique ? "STOU" : "STOR";
13695     if ((prox_type = type) == 0) {
13696         if (servertype == SYS_UNIX && unix_proxy)
13697           prox_type = FTT_BIN;
13698         else
13699           prox_type = FTT_ASC;
13700     }
13701     if (curtype != prox_type)
13702       changetype(prox_type, 1);
13703     if (ftpcmd("PASV",NULL,0,0,ftp_vbm) != REPLY_COMPLETE) {
13704         printf("Proxy server does not support third party transfers.\n");
13705         return;
13706     }
13707     pswitch(0);
13708     if (!connected) {
13709         printf("No primary connection\n");
13710         pswitch(1);
13711         ftpcode = -1;
13712         return;
13713     }
13714     if (curtype != prox_type)
13715       changetype(prox_type, 1);
13716 
13717     if (ftpcmd("PORT",pasv,-1,-1,ftp_vbm) != REPLY_COMPLETE) {
13718         pswitch(1);
13719         return;
13720     }
13721 
13722     /* Replace with calls to cc_execute() */
13723     if (setjmp(ptcancel))
13724       goto cancel;
13725     oldintr = signal(SIGINT, cancelpt);
13726     if (ftpcmd(cmd,remote,-1,-1,ftp_vbm) != PRELIM) {
13727         signal(SIGINT, oldintr);
13728         pswitch(1);
13729         return;
13730     }
13731     sleep(2000);
13732     pswitch(1);
13733     secndflag++;
13734     if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM)
13735       goto cancel;
13736     ptflag++;
13737     getreply(0,-1,-1,ftp_vbm,0);
13738     pswitch(0);
13739     getreply(0,-1,-1,ftp_vbm,0);
13740     signal(SIGINT, oldintr);
13741     pswitch(1);
13742     ptflag = 0;
13743     return;
13744 
13745   cancel:
13746     signal(SIGINT, SIG_IGN);
13747     ptflag = 0;
13748     if (strcmp(cmd, "RETR") && !proxy)
13749       pswitch(1);
13750     else if (!strcmp(cmd, "RETR") && proxy)
13751       pswitch(0);
13752     if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
13753         if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13754             pswitch(0);
13755             if (cpend)
13756               cancel_remote(0);
13757         }
13758         pswitch(1);
13759         if (ptabflg)
13760           ftpcode = -1;
13761         signal(SIGINT, oldintr);
13762         return;
13763     }
13764     if (cpend)
13765       cancel_remote(0);
13766     pswitch(!proxy);
13767     if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
13768         if (ftpcmd(cmd2,local,-1,-1,ftp_vbm) != PRELIM) {
13769             pswitch(0);
13770             if (cpend)
13771               cancel_remote(0);
13772             pswitch(1);
13773             if (ptabflg)
13774               ftpcode = -1;
13775             signal(SIGINT, oldintr);
13776             return;
13777         }
13778     }
13779     if (cpend)
13780       cancel_remote(0);
13781     pswitch(!proxy);
13782     if (cpend) {
13783 #ifdef BSDSELECT
13784         FD_ZERO(&mask);
13785         FD_SET(csocket, &mask);
13786         if ((nfnd = empty(&mask, 10)) <= 0) {
13787             if (nfnd < 0) {
13788                 perror("cancel");
13789             }
13790             if (ptabflg)
13791               ftpcode = -1;
13792             lostpeer();
13793         }
13794 #else /* BSDSELECT */
13795 #ifdef IBMSELECT
13796         if ((nfnd = empty(&csocket, 1, 10)) <= 0) {
13797             if (nfnd < 0) {
13798                 perror("cancel");
13799             }
13800             if (ptabflg)
13801               ftpcode = -1;
13802             lostpeer();
13803         }
13804 #endif /* IBMSELECT */
13805 #endif /* BSDSELECT */
13806         getreply(0,-1,-1,ftp_vbm,0);
13807         getreply(0,-1,-1,ftp_vbm,0);
13808     }
13809     if (proxy)
13810       pswitch(0);
13811     pswitch(1);
13812     if (ptabflg)
13813       ftpcode = -1;
13814     signal(SIGINT, oldintr);
13815 }
13816 #endif /* FTP_PROXY */
13817 
13818 #ifdef FTP_SECURITY
13819 #ifdef FTP_GSSAPI
13820 
13821 #ifdef COMMENT
13822 /* ck_gss_mech_krb5 is not declared anywhere */
13823 struct {
13824     CONST gss_OID_desc * CONST * mech_type;
13825     char *service_name;
13826 } gss_trials[] = {
13827     { &ck_gss_mech_krb5, "ftp" },
13828     { &ck_gss_mech_krb5, "host" },
13829 };
13830 #else
13831 /* This matches what is declared above */
13832 struct {
13833     CONST gss_OID_desc * CONST * mech_type;
13834     char *service_name;
13835 } gss_trials[] = {
13836     { &gss_mech_krb5, "ftp" },
13837     { &gss_mech_krb5, "host" },
13838 };
13839 #endif	/* COMMENT */
13840 
13841 
13842 int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
13843 #endif /* FTP_GSSAPI */
13844 
13845 static int
ftp_auth()13846 ftp_auth() {
13847     extern int setsafe();
13848     int j = 0, n;
13849 #ifdef FTP_KRB4
13850     char *service, inst[INST_SZ];
13851     ULONG cksum;
13852     ULONG checksum = (ULONG) getpid();
13853     CHAR out_buf[FTP_BUFSIZ];
13854     int i;
13855 #else /* FTP_KRB4 */
13856 #ifdef FTP_GSSAPI
13857     CHAR out_buf[FTP_BUFSIZ];
13858     int i;
13859 #endif /* FTP_GSSAPI */
13860 #endif /* FTP_KRB4 */
13861 
13862     if (ssl_ftp_proxy)                  /* Do not allow AUTH over SSL proxy */
13863         return(0);
13864 
13865     if (auth_type)
13866       return(1);                        /* auth already succeeded */
13867 
13868     /* Try each auth type as specified by the end user */
13869     for (j = 0; j < 8 && ftp_auth_type[j] != 0; j++) {
13870 #ifdef FTP_GSSAPI
13871         if (ftp_auth_type[j] == FTA_GK5 && ck_gssapi_is_installed()) {
13872             n = ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm);
13873             if (n == REPLY_CONTINUE) {
13874                 OM_uint32 maj_stat, min_stat;
13875                 gss_name_t target_name;
13876                 gss_buffer_desc send_tok, recv_tok, *token_ptr;
13877                 char stbuf[FTP_BUFSIZ];
13878                 int comcode, trial;
13879                 struct gss_channel_bindings_struct chan;
13880                 char * realm = NULL;
13881                 char tgt[256];
13882 
13883                 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */
13884                 chan.initiator_address.length = 4;
13885                 chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
13886                 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
13887                 chan.acceptor_address.length = 4;
13888                 chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
13889                 chan.application_data.length = 0;
13890                 chan.application_data.value = 0;
13891 
13892                 if (!quiet)
13893                   printf("GSSAPI accepted as authentication type\n");
13894 
13895                 realm = ck_krb5_realmofhost(ftp_user_host);
13896                 if (realm) {
13897                     ckmakmsg(tgt,sizeof(tgt),"krbtgt/",realm,"@",realm);
13898                     debug(F110,"ftp_auth(GSSAPI) TGT",tgt,0);
13899                     if ( krb5_autoget &&
13900                          !((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
13901                             (ck_krb5_is_tgt_valid() > 0)) )
13902                         ck_krb5_autoget_TGT(realm);
13903                 }
13904 
13905                 /* Blob from gss-client */
13906                 for (trial = 0; trial < n_gss_trials; trial++) {
13907                     /* ftp@hostname first, the host@hostname */
13908                     /* the V5 GSSAPI binding canonicalizes this for us... */
13909                     ckmakmsg(stbuf,FTP_BUFSIZ,
13910                              gss_trials[trial].service_name,
13911                              "@",
13912                              ftp_user_host,
13913                              NULL
13914                              );
13915                     if (ftp_deb)
13916                       fprintf(stderr,
13917                               "Authenticating to <%s>...\n", stbuf);
13918                     send_tok.value = stbuf;
13919                     send_tok.length = strlen(stbuf);
13920                     maj_stat = gss_import_name(&min_stat, &send_tok,
13921                                                gss_nt_service_name,
13922                                                &target_name
13923                                                );
13924                     if (maj_stat != GSS_S_COMPLETE) {
13925                         user_gss_error(maj_stat, min_stat, "parsing name");
13926                         secure_error("name parsed <%s>\n", stbuf);
13927                         continue;
13928                     }
13929                     token_ptr = GSS_C_NO_BUFFER;
13930                     gcontext = GSS_C_NO_CONTEXT; /* structure copy */
13931 
13932                     do {
13933                         if (ftp_deb)
13934                           fprintf(stderr, "calling gss_init_sec_context\n");
13935                         maj_stat =
13936                           gss_init_sec_context(&min_stat,
13937                                                GSS_C_NO_CREDENTIAL,
13938                                                &gcontext,
13939                                                target_name,
13940                                                (gss_OID) *
13941                                                  gss_trials[trial].mech_type,
13942                                                GSS_C_MUTUAL_FLAG |
13943                                                GSS_C_REPLAY_FLAG |
13944                                                (ftp_cfw ?
13945                                                 GSS_C_DELEG_FLAG : 0),
13946                                                0,
13947                                                 /* channel bindings */
13948                                                 (krb5_d_no_addresses ?
13949                                                   GSS_C_NO_CHANNEL_BINDINGS :
13950                                                   &chan),
13951                                                 token_ptr,
13952                                                NULL,    /* ignore mech type */
13953                                                &send_tok,
13954                                                NULL,    /* ignore ret_flags */
13955                                                NULL
13956                                                );       /* ignore time_rec */
13957 
13958                         if (maj_stat != GSS_S_COMPLETE &&
13959                             maj_stat != GSS_S_CONTINUE_NEEDED) {
13960                             if (trial == n_gss_trials-1)
13961                               user_gss_error(maj_stat,
13962                                              min_stat,
13963                                              "initializing context"
13964                                              );
13965                             gss_release_name(&min_stat, &target_name);
13966                             /* maybe we missed on the service name */
13967                             goto outer_loop;
13968                         }
13969                         if (send_tok.length != 0) {
13970                             int len;
13971                             reply_parse = "ADAT="; /* for ftpcmd() later */
13972                             len = FTP_BUFSIZ;
13973                             kerror =
13974                               radix_encode(send_tok.value,
13975                                            out_buf,
13976                                            send_tok.length,
13977                                            &len,
13978                                            RADIX_ENCODE
13979                                            );
13980                             if (kerror)  {
13981                                 fprintf(stderr,
13982                                         "Base 64 encoding failed: %s\n",
13983                                         radix_error(kerror)
13984                                         );
13985                                 goto gss_complete_loop;
13986                             }
13987                             comcode = ftpcmd("ADAT",out_buf,-1,-1,0);
13988                             if (comcode != REPLY_COMPLETE
13989                                 && comcode != REPLY_CONTINUE /* (335) */
13990                                 ) {
13991                                 if (trial == n_gss_trials-1) {
13992                                     fprintf(stderr, "GSSAPI ADAT failed\n");
13993                                     /* force out of loop */
13994                                     maj_stat = GSS_S_FAILURE;
13995                                 }
13996                                 /*
13997                                   Backoff to the v1 gssapi is still possible.
13998                                   Send a new AUTH command.  If that fails,
13999                                   terminate the loop.
14000                                 */
14001                                 if (ftpcmd("AUTH GSSAPI",NULL,0,0,ftp_vbm)
14002                                     != REPLY_CONTINUE) {
14003                                     fprintf(stderr,
14004                                 "GSSAPI ADAT failed, AUTH restart failed\n");
14005                                     /* force out of loop */
14006                                     maj_stat = GSS_S_FAILURE;
14007                                 }
14008                                 goto outer_loop;
14009                             }
14010                             if (!reply_parse) {
14011                                 fprintf(stderr,
14012                               "No authentication data received from server\n");
14013                                 if (maj_stat == GSS_S_COMPLETE) {
14014                                     fprintf(stderr,
14015                                             "...but no more was needed\n");
14016                                     goto gss_complete_loop;
14017                                 } else {
14018                                     user_gss_error(maj_stat,
14019                                                    min_stat,
14020                                                    "no reply, huh?"
14021                                                    );
14022                                     goto gss_complete_loop;
14023                                 }
14024                             }
14025                             len = FTP_BUFSIZ;
14026                             kerror = radix_encode(reply_parse,out_buf,i,&len,
14027                                                   RADIX_DECODE);
14028                             if (kerror) {
14029                                 fprintf(stderr,
14030                                         "Base 64 decoding failed: %s\n",
14031                                         radix_error(kerror));
14032                                 goto gss_complete_loop;
14033                             }
14034 
14035                             /* everything worked */
14036                             token_ptr = &recv_tok;
14037                             recv_tok.value = out_buf;
14038                             recv_tok.length = len;
14039                             continue;
14040 
14041                             /* get out of loop clean */
14042                           gss_complete_loop:
14043                             trial = n_gss_trials-1;
14044                             gss_release_buffer(&min_stat, &send_tok);
14045                             gss_release_name(&min_stat, &target_name);
14046                             goto outer_loop;
14047                         }
14048                     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
14049 
14050                   outer_loop:
14051                     if (maj_stat == GSS_S_COMPLETE)
14052                       break;
14053                 }
14054                 if (maj_stat == GSS_S_COMPLETE) {
14055                     printf("GSSAPI authentication succeeded\n");
14056                     reply_parse = NULL;
14057                     auth_type = "GSSAPI";
14058                     return(1);
14059                 } else {
14060                     fprintf(stderr, "GSSAPI authentication failed\n");
14061                     reply_parse = NULL;
14062                 }
14063             } else {
14064                 if (ftp_deb)
14065                 fprintf(stderr, "GSSAPI rejected as an authentication type\n");
14066                 if (ftpcode == 500 || ftpcode == 502)
14067                     return(0);
14068             }
14069         }
14070 #endif /* FTP_GSSAPI */
14071 #ifdef FTP_SRP
14072         if (ftp_auth_type[j] == FTA_SRP && ck_srp_is_installed()) {
14073             if (srp_ftp_auth(ftp_user_host,NULL,NULL))
14074               return(1);
14075             else if (ftpcode == 500 || ftpcode == 502)
14076               return(0);
14077         }
14078 #endif /* FTP_SRP */
14079 #ifdef FTP_KRB4
14080         if (ftp_auth_type[j] == FTA_K4 && ck_krb4_is_installed()) {
14081             n = ftpcmd("AUTH KERBEROS_V4",NULL,0,0,ftp_vbm);
14082             if (n == REPLY_CONTINUE) {
14083                 char tgt[4*REALM_SZ+1];
14084                 int rc;
14085 
14086                 if (!quiet)
14087                   printf("KERBEROS_V4 accepted as authentication type\n");
14088                 ckstrncpy(inst, (char *) krb_get_phost(ftp_user_host),INST_SZ);
14089                 ckstrncpy(ftp_realm,
14090                           (char *)ck_krb4_realmofhost(ftp_user_host),
14091                           REALM_SZ
14092                           );
14093 
14094                 ckmakmsg(tgt,sizeof(tgt),"krbtgt.",ftp_realm,"@",ftp_realm);
14095                 rc = ck_krb4_tkt_isvalid(tgt);
14096 
14097                 if (rc <= 0 && krb4_autoget)
14098                   ck_krb4_autoget_TGT(ftp_realm);
14099 
14100                 service = "ftp";
14101                 kerror = krb_mk_req(&ftp_tkt,service,inst,ftp_realm,checksum);
14102                 if (kerror == KDC_PR_UNKNOWN) {
14103                     service = "rcmd";
14104                     kerror = krb_mk_req(&ftp_tkt,
14105                                         service,
14106                                         inst,
14107                                         ftp_realm,
14108                                         checksum
14109                                         );
14110                 }
14111                 if (kerror)
14112                   fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
14113                           krb_get_err_text(kerror));
14114                 if (!kerror) {
14115                     kerror = krb_get_cred(service, inst, ftp_realm,&ftp_cred);
14116                     if (kerror)
14117                       fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
14118                               krb_get_err_text(kerror));
14119                 }
14120                 if (!kerror) {
14121                     int rc;
14122                     rc = des_key_sched(ftp_cred.session, ftp_sched);
14123                     if (rc == -1) {
14124                        printf("?Invalid DES key specified in credentials\r\n");
14125                        debug(F110,"ftp_auth",
14126                              "invalid DES Key specified in credentials",0);
14127                     } else if ( rc == -2 ) {
14128                         printf("?Weak DES key specified in credentials\r\n");
14129                         debug(F110,"ftp_auth",
14130                               "weak DES Key specified in credentials",0);
14131                     } else if ( rc != 0 ) {
14132                         printf("?DES Key Schedule not set by credentials\r\n");
14133                         debug(F110,"ftp_auth",
14134                               "DES Key Schedule not set by credentials",0);
14135                     }
14136                     reply_parse = "ADAT=";
14137                     i = FTP_BUFSIZ;
14138                     kerror = radix_encode(ftp_tkt.dat, out_buf, ftp_tkt.length,
14139                                           &i, RADIX_ENCODE);
14140                     if (kerror) {
14141                         fprintf(stderr, "Base 64 encoding failed: %s\n",
14142                                 radix_error(kerror));
14143                         goto krb4_err;
14144                     }
14145                     if (i > FTP_BUFSIZ - 6)
14146                       printf("?ADAT data too long\n");
14147                     if (ftpcmd("ADAT",out_buf,-1,-1,0) !=
14148                         REPLY_COMPLETE) {
14149                         fprintf(stderr, "Kerberos V4 authentication failed\n");
14150                         goto krb4_err;
14151                     }
14152                     if (!reply_parse) {
14153                         fprintf(stderr,
14154                              "No authentication data received from server\n");
14155                         goto krb4_err;
14156                     }
14157                     i = sizeof(out_buf);
14158                     kerror =
14159                       radix_encode(reply_parse, out_buf, 0, &i, RADIX_DECODE);
14160                     if (kerror) {
14161                         fprintf(stderr, "Base 64 decoding failed: %s\n",
14162                                 radix_error(kerror));
14163                         goto krb4_err;
14164                     }
14165                     kerror = krb_rd_safe(out_buf, i,
14166 #ifdef KRB524
14167                                          ftp_cred.session,
14168 #else /* KRB524 */
14169                                          &ftp_cred.session,
14170 #endif /* KRB524 */
14171                                          &hisctladdr,
14172                                          &myctladdr,
14173                                          &ftp_msg_data
14174                                          );
14175                     if (kerror) {
14176                         fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
14177                                 krb_get_err_text(kerror));
14178                         goto krb4_err;
14179                     }
14180 
14181                     /* fetch the (modified) checksum */
14182                     memcpy(&cksum, ftp_msg_data.app_data, sizeof(cksum));
14183                     if (ntohl(cksum) == checksum + 1) {
14184                         if (ftp_vbm)
14185                           printf("Kerberos V4 authentication succeeded\n");
14186                         reply_parse = NULL;
14187                         auth_type = "KERBEROS_V4";
14188                         return(1);
14189                     } else
14190                       fprintf(stderr,
14191                               "Kerberos V4 mutual authentication failed\n");
14192                   krb4_err:
14193                     reply_parse = NULL;
14194                 }
14195             } else {
14196                 if (ftp_deb)
14197 		  fprintf(stderr,
14198                       "KERBEROS_V4 rejected as an authentication type\n");
14199                 if (ftpcode == 500 || ftpcode == 502)
14200                     return(0);
14201             }
14202         }
14203 #endif /* FTP_KRB4 */
14204 #ifdef CK_SSL
14205         if (ftp_auth_type[j] == FTA_TLS && ck_ssleay_is_installed()) {
14206 #ifdef FTPHOST
14207             if (!hostcmd) {
14208                 ftpcmd("HOST",ftp_user_host,0,0,0);
14209                 hostcmd = 1;
14210             }
14211 #endif /* FTPHOST */
14212             n = ftpcmd("AUTH TLS",NULL,0,0,ftp_vbm);
14213             if (n != REPLY_COMPLETE)
14214               n = ftpcmd("AUTH TLS-P",NULL,0,0,ftp_vbm);
14215             if (n == REPLY_COMPLETE) {
14216                 if (!quiet)
14217                   printf("TLS accepted as authentication type\n");
14218 
14219                 auth_type = "TLS";
14220                 ssl_auth();
14221                 if (ssl_ftp_active_flag ) {
14222                     ftp_dpl = FPL_CLR;
14223                     ftp_cpl = FPL_PRV;
14224                     return(1);
14225                 } else {
14226                     fprintf(stderr,"TLS authentication failed\n");
14227                     auth_type = NULL;
14228 #ifdef TCPIPLIB
14229                     socket_close(csocket);
14230 #else /* TCPIPLIB */
14231 #ifdef USE_SHUTDOWN
14232                     shutdown(csocket, 1+1);
14233 #endif /* USE_SHUTDOWN */
14234                     close(csocket);
14235 #endif /* TCPIPLIB */
14236                     csocket = -1;
14237                     if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14238                       return(0);
14239                 }
14240             } else {
14241                 if (ftp_deb)
14242 		  fprintf(stderr,"TLS rejected as an authentication type\n");
14243                 if (ftpcode == 500 || ftpcode == 502)
14244                     return(0);
14245             }
14246         }
14247         if (ftp_auth_type[j] == FTA_SSL && ck_ssleay_is_installed()) {
14248 #ifdef FTPHOST
14249             if (!hostcmd) {
14250                 ftpcmd("HOST",ftp_user_host,0,0,0);
14251                 hostcmd = 1;
14252             }
14253 #endif /* FTPHOST */
14254             n = ftpcmd("AUTH SSL",NULL,0,0,ftp_vbm);
14255             if (n == REPLY_CONTINUE || n == REPLY_COMPLETE) {
14256                 if (!quiet)
14257                   printf("SSL accepted as authentication type\n");
14258                 auth_type = "SSL";
14259                 ssl_auth();
14260                 if (ssl_ftp_active_flag) {
14261                     ftp_dpl = FPL_PRV;
14262                     ftp_cpl = FPL_PRV;
14263                     setprotbuf(1<<20);
14264                     return(1);
14265                 } else {
14266                     fprintf(stderr,"SSL authentication failed\n");
14267                     auth_type = NULL;
14268 #ifdef TCPIPLIB
14269                     socket_close(csocket);
14270 #else /* TCPIPLIB */
14271 #ifdef USE_SHUTDOWN
14272                     shutdown(csocket, 1+1);
14273 #endif /* USE_SHUTDOWN */
14274                     close(csocket);
14275 #endif /* TCPIPLIB */
14276                     csocket = -1;
14277                     if (ftp_hookup(ftp_user_host,ftp_port,0) == NULL)
14278                       return(0);
14279                 }
14280 	    } else {
14281                 if (ftp_deb)
14282 		  fprintf(stderr, "SSL rejected as an authentication type\n");
14283                 if (ftpcode == 500 || ftpcode == 502)
14284 		  return(0);
14285             }
14286         }
14287 #endif /* CK_SSL */
14288         /* Other auth types go here ... */
14289     } /* for (j;;) */
14290     return(0);
14291 }
14292 #endif /* FTP_SECURITY */
14293 
14294 static int
14295 #ifdef CK_ANSIC
setprotbuf(unsigned int size)14296 setprotbuf(unsigned int size)
14297 #else
14298 setprotbuf(size) unsigned int size;
14299 #endif /* CK_ANSIC */
14300 /* setprotbuf */ {
14301     if (ucbuf)
14302       free(ucbuf);
14303     ucbuf = NULL;
14304     ucbufsiz = 0;
14305     actualbuf = size;
14306     while ((ucbuf = (CHAR *)malloc(actualbuf)) == NULL) {
14307         if (actualbuf)
14308           actualbuf /= 2;
14309         else
14310           return(0);
14311     }
14312     ucbufsiz = actualbuf - FUDGE_FACTOR;
14313     debug(F101,"setprotbuf ucbufsiz","",ucbufsiz);
14314     if (ucbufsiz < 128) {
14315         printf("WARNING: tiny ucbufsiz: %d\n",ucbufsiz);
14316     } else if (ucbufsiz < 0) {
14317         printf("ERROR: ucbuf allocation failure\n");
14318         return(-1);
14319     }
14320     maxbuf = actualbuf;
14321     return(1);
14322 }
14323 
14324 static int
14325 #ifdef CK_ANSIC
setpbsz(unsigned int size)14326 setpbsz(unsigned int size)
14327 #else
14328 setpbsz(size) unsigned int size;
14329 #endif /* CK_ANSIC */
14330 /* setpbsz */ {
14331     if (!setprotbuf(size)) {
14332         perror("?Error while trying to malloc PROT buffer:");
14333 #ifdef FTP_SRP
14334         srp_reset();
14335 #endif /* FTP_SRP */
14336         ftpclose();
14337         return(-1);
14338     }
14339     reply_parse = "PBSZ=";
14340     ckmakmsg(ftpcmdbuf,FTP_BUFSIZ,"PBSZ ",
14341 #ifdef CK_SSL
14342              ssl_ftp_active_flag ? "0" :
14343 #endif /* CK_SSL */
14344              ckuitoa(actualbuf),NULL,NULL);
14345     if (ftpcmd(ftpcmdbuf,NULL,0,0,0) != REPLY_COMPLETE) {
14346         if (connected) {
14347             printf("?Unable to negotiate PROT buffer size with FTP server\n");
14348             ftpclose();
14349         }
14350         return(-1);
14351     }
14352     if (reply_parse) {
14353         if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
14354           maxbuf = actualbuf;
14355     } else
14356       maxbuf = actualbuf;
14357     ucbufsiz = maxbuf - FUDGE_FACTOR;
14358     debug(F101,"setpbsz ucbufsiz","",ucbufsiz);
14359     reply_parse = NULL;
14360     return(0);
14361 }
14362 
14363 static VOID
cancel_remote(din)14364 cancel_remote(din) int din; {
14365     CHAR buf[FTP_BUFSIZ];
14366     int x, nfnd;
14367 #ifdef BSDSELECT
14368     fd_set mask;
14369 #endif /* BSDSELECT */
14370 #ifdef IBMSELECT
14371     int fds[2], fdcnt = 0;
14372 #endif /* IBMSELECT */
14373 #ifdef DEBUG
14374     extern int debtim;
14375     int xdebtim;
14376     xdebtim = debtim;
14377     debtim = 1;
14378 #endif /* DEBUG */
14379     debug(F100,"ftp cancel_remote entry","",0);
14380 #ifdef CK_SSL
14381     if (ssl_ftp_active_flag) {
14382         /*
14383          * Send Telnet IP, Telnet DM but do so inline and within the
14384          * TLS channel
14385          */
14386         int count, error;
14387 
14388         buf[0] = IAC;
14389         buf[1] = TN_IP;
14390         buf[2] = IAC;
14391         buf[3] = TN_DM;
14392         buf[4] = NUL;
14393 
14394         count = SSL_write(ssl_ftp_con, buf, 4);
14395         debug(F111,"ftp cancel_remote","SSL_write(IAC IP IAC DM)",count);
14396         error = SSL_get_error(ssl_ftp_con,count);
14397         debug(F111,"ftp cancel_remote","SSL_get_error()",error);
14398         switch (error) {
14399           case SSL_ERROR_NONE:
14400             break;
14401           case SSL_ERROR_WANT_WRITE:
14402           case SSL_ERROR_WANT_READ:
14403           case SSL_ERROR_SYSCALL:
14404 #ifdef NT
14405             {
14406                 int gle = GetLastError();
14407             }
14408 #endif /* NT */
14409           case SSL_ERROR_WANT_X509_LOOKUP:
14410           case SSL_ERROR_SSL:
14411           case SSL_ERROR_ZERO_RETURN:
14412           default:
14413             lostpeer();
14414             return;
14415         }
14416     } else
14417 #endif /* CK_SSL */
14418     {
14419         /*
14420          * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
14421          * after urgent byte rather than before as is protocol now.
14422          */
14423         buf[0] = IAC;
14424         buf[1] = TN_IP;
14425         buf[2] = IAC;
14426         buf[3] = NUL;
14427         if ((x = send(csocket, (SENDARG2TYPE)buf, 3, MSG_OOB)) != 3)
14428           perror("cancel");
14429         debug(F101,"ftp cancel_remote send 1","",x);
14430         buf[0] = TN_DM;
14431         x = send(csocket,(SENDARG2TYPE)buf,1,0);
14432         debug(F101,"ftp cancel_remote send 2","",x);
14433     }
14434     x = scommand("ABOR");
14435     debug(F101,"ftp cancel_remote scommand","",x);
14436 #ifdef BSDSELECT
14437     FD_ZERO(&mask);
14438     FD_SET(csocket, &mask);
14439     if (din) {
14440         FD_SET(din, &mask);
14441     }
14442     nfnd = empty(&mask, 10);
14443     debug(F101,"ftp cancel_remote empty","",nfnd);
14444     if ((nfnd) <= 0) {
14445         if (nfnd < 0) {
14446             perror("cancel");
14447         }
14448 #ifdef FTP_PROXY
14449         if (ptabflg)
14450           ftpcode = -1;
14451 #endif /* FTP_PROXY */
14452         lostpeer();
14453     }
14454     debug(F110,"ftp cancel_remote","D",0);
14455     if (din && FD_ISSET(din, &mask)) {
14456         /* Security: No threat associated with this read. */
14457         /* But you can't simply read the TLS data stream  */
14458 #ifdef CK_SSL
14459         if (ssl_ftp_data_active_flag) {
14460             int count, error;
14461             while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14462                     /* LOOP */ ;
14463         } else
14464 #endif /* CK_SSL */
14465         {
14466             while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14467                 /* LOOP */ ;
14468         }
14469     }
14470     debug(F110,"ftp cancel_remote","E",0);
14471 #else /* BSDSELECT */
14472 #ifdef IBMSELECT
14473     fds[0] = csocket;
14474     fdcnt++;
14475     if (din) {
14476         fds[1] = din;
14477         fdcnt++;
14478     }
14479     nfnd = empty(fds, fdcnt, 10);
14480     debug(F101,"ftp cancel_remote empty","",nfnd);
14481     if ((nfnd) <= 0) {
14482         if (nfnd < 0) {
14483             perror("cancel");
14484         }
14485 #ifdef FTP_PROXY
14486         if (ptabflg)
14487           ftpcode = -1;
14488 #endif /* FTP_PROXY */
14489         lostpeer();
14490     }
14491     debug(F110,"ftp cancel_remote","D",0);
14492     if (din && select(&din, 1,0,0,1) ) {
14493 #ifdef CK_SSL
14494         if (ssl_ftp_data_active_flag) {
14495             int count, error;
14496             while ((count = SSL_read(ssl_ftp_data_con, buf, FTP_BUFSIZ)) > 0)
14497                     /* LOOP */ ;
14498         } else
14499 #endif /* CK_SSL */
14500         {
14501             while (recv(din, (SENDARG2TYPE)buf, FTP_BUFSIZ,0) > 0)
14502                 /* LOOP */ ;
14503         }
14504     }
14505     debug(F110,"ftp cancel_remote","E",0);
14506 #else /* IBMSELECT */
14507     Some form of select is required.
14508 #endif /* IBMSELECT */
14509 #endif /* BSDSELECT */
14510     if (getreply(0,-1,-1,ftp_vbm,0) == REPLY_ERROR && ftpcode == 552) {
14511         debug(F110,"ftp cancel_remote","F",0);
14512         /* 552 needed for NIC style cancel */
14513         getreply(0,-1,-1,ftp_vbm,0);
14514         debug(F110,"ftp cancel_remote","G",0);
14515     }
14516     debug(F110,"ftp cancel_remote","H",0);
14517     getreply(0,-1,-1,ftp_vbm,0);
14518     debug(F110,"ftp cancel_remote","I",0);
14519 #ifdef DEBUG
14520     debtim = xdebtim;
14521 #endif /* DEBUG */
14522 }
14523 
14524 static int
fts_dpl(x)14525 fts_dpl(x) int x; {
14526     if (!auth_type
14527 #ifdef OS2
14528          || !ck_crypt_is_installed()
14529 #endif /* OS2 */
14530          ) {
14531         switch ( x ) {
14532           case FPL_PRV:
14533             printf("?Cannot set protection level to PRIVATE\n");
14534             return(0);
14535           case FPL_SAF:
14536             printf("?Cannot set protection level to SAFE\n");
14537             return(0);
14538         }
14539         ftp_dpl = x;
14540         return(1);
14541     }
14542 
14543 #ifdef CK_SSL
14544     if (x == FPL_SAF &&
14545         (!strcmp(auth_type,"SSL") || !strcmp(auth_type,"TLS"))) {
14546         printf("Cannot set protection level to safe\n");
14547         return(0);
14548     }
14549 #endif /* CK_SSL */
14550     /* Start with a PBSZ of 1 meg */
14551     if (x != FPL_CLR) {
14552         if (setpbsz(DEFAULT_PBSZ) < 0)
14553           return(0);
14554     }
14555     y = ftpcmd(x == FPL_CLR ? "PROT C" :
14556                (x == FPL_SAF ? "PROT S" : "PROT P"), NULL, 0, 0,ftp_vbm);
14557     if (y == REPLY_COMPLETE) {
14558         ftp_dpl = x;
14559         return(1);
14560     }
14561     return(0);
14562 }
14563 
14564 static int
fts_cpl(x)14565 fts_cpl(x) int x; {
14566     if (!auth_type
14567 #ifdef OS2
14568          || !ck_crypt_is_installed()
14569 #endif /* OS2 */
14570          ) {
14571         switch ( x ) {
14572           case FPL_PRV:
14573             printf("?Cannot set protection level to PRIVATE\n");
14574             return(0);
14575           case FPL_SAF:
14576             printf("?Cannot set protection level to SAFE\n");
14577             return(0);
14578         }
14579         ftp_cpl = x;
14580         return(1);
14581     }
14582     if (x == FPL_CLR) {
14583         y = ftpcmd("CCC",NULL,0,0,ftp_vbm);
14584         if (y == REPLY_COMPLETE) {
14585             ftp_cpl = x;
14586             return(1);
14587         }
14588         return(0);
14589     }
14590     ftp_cpl = x;
14591     return(1);
14592 }
14593 
14594 #ifdef FTP_GSSAPI
14595 static VOID
user_gss_error(maj_stat,min_stat,s)14596 user_gss_error(maj_stat, min_stat, s)
14597     OM_uint32 maj_stat, min_stat;
14598     char *s;
14599 {
14600     /* a lot of work just to report the error */
14601     OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
14602     gss_buffer_desc msg;
14603     msg_ctx = 0;
14604     while (!msg_ctx) {
14605         gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
14606                                        GSS_C_GSS_CODE,
14607                                        GSS_C_NULL_OID,
14608                                        &msg_ctx,
14609                                        &msg
14610                                        );
14611         if ((gmaj_stat == GSS_S_COMPLETE)||
14612             (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14613             fprintf(stderr, "GSSAPI error major: %s\n",
14614                     (char*)msg.value);
14615             gss_release_buffer(&gmin_stat, &msg);
14616         }
14617         if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14618           break;
14619     }
14620     msg_ctx = 0;
14621     while (!msg_ctx) {
14622         gmaj_stat = gss_display_status(&gmin_stat, min_stat,
14623                                        GSS_C_MECH_CODE,
14624                                        GSS_C_NULL_OID,
14625                                        &msg_ctx,
14626                                        &msg
14627                                        );
14628         if ((gmaj_stat == GSS_S_COMPLETE)||
14629             (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
14630             fprintf(stderr, "GSSAPI error minor: %s\n", (char*)msg.value);
14631             gss_release_buffer(&gmin_stat, &msg);
14632         }
14633         if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
14634           break;
14635     }
14636     fprintf(stderr, "GSSAPI error: %s\n", s);
14637 }
14638 #endif /* FTP_GSSAPI */
14639 
14640 #ifndef NOMHHOST
14641 #ifdef datageneral
14642 #define NOMHHOST
14643 #else
14644 #ifdef HPUX5WINTCP
14645 #define NOMHHOST
14646 #endif /* HPUX5WINTCP */
14647 #endif /* datageneral */
14648 #endif /* NOMHHOST */
14649 
14650 #ifdef INADDRX
14651 static struct in_addr inaddrx;
14652 #endif /* INADDRX */
14653 
14654 static char *
ftp_hookup(host,port,tls)14655 ftp_hookup(host, port, tls) char * host; int port; int tls; {
14656     register struct hostent *hp = 0;
14657 #ifdef IP_TOS
14658 #ifdef IPTOS_THROUGHPUT
14659     int tos;
14660 #endif /* IPTOS_THROUGHPUT */
14661 #endif /* IP_TOS */
14662     int s;
14663     GSOCKNAME_T len;
14664     static char hostnamebuf[MAXHOSTNAMELEN];
14665     char hostname[MAXHOSTNAMELEN] /* , *p, *q */ ;
14666     int  cport;
14667 #ifdef DEBUG
14668     extern int debtim;
14669     int xdebtim;
14670     xdebtim = debtim;
14671     debtim = 1;
14672 #endif /* DEBUG */
14673 
14674     debug(F111,"ftp_hookup",host,port);
14675 
14676 #ifndef NOHTTP
14677     if (tcp_http_proxy) {
14678         struct servent *destsp;
14679         char *p, *q;
14680 
14681         ckmakmsg(proxyhost,HTTPCPYL,host,":",ckuitoa(port),NULL);
14682         for (p = tcp_http_proxy, q = hostname;
14683              *p != '\0' && *p != ':';
14684              p++, q++
14685              )
14686           *q = *p;
14687         *q = '\0';
14688 
14689         if (*p == ':')
14690           p++;
14691         else
14692           p = "http";
14693 
14694         destsp = getservbyname(p,"tcp");
14695         if (destsp)
14696           cport = ntohs(destsp->s_port);
14697         else if (p) {
14698           cport = atoi(p);
14699         } else
14700           cport = 80;
14701     } else
14702 #endif /* NOHTTP */
14703     {
14704         ckstrncpy(hostname,host,MAXHOSTNAMELEN);
14705         cport = port;
14706     }
14707     memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
14708     hisctladdr.sin_addr.s_addr = inet_addr(host);
14709     if (hisctladdr.sin_addr.s_addr != INADDR_NONE) /* 2010-03-29 */
14710     {
14711         debug(F110,"ftp hookup A",hostname,0);
14712         hisctladdr.sin_family = AF_INET;
14713         ckstrncpy(hostnamebuf, hostname, MAXHOSTNAMELEN);
14714     } else {
14715         debug(F110,"ftp hookup B",hostname,0);
14716         hp = gethostbyname(hostname);
14717 #ifdef HADDRLIST
14718         hp = ck_copyhostent(hp);        /* make safe copy that won't change */
14719 #endif /* HADDRLIST */
14720         if (hp == NULL) {
14721             fprintf(stderr, "ftp: %s: Unknown host\n", host);
14722             ftpcode = -1;
14723 #ifdef DEBUG
14724             debtim = xdebtim;
14725 #endif /* DEBUG */
14726             return((char *) 0);
14727         }
14728         hisctladdr.sin_family = hp->h_addrtype;
14729 #ifdef HADDRLIST
14730         memcpy((char *)&hisctladdr.sin_addr, hp->h_addr_list[0],
14731                sizeof(hisctladdr.sin_addr));
14732 #else /* HADDRLIST */
14733         memcpy((char *)&hisctladdr.sin_addr, hp->h_addr,
14734                sizeof(hisctladdr.sin_addr));
14735 #endif /* HADDRLIST */
14736         ckstrncpy(hostnamebuf, hp->h_name, MAXHOSTNAMELEN);
14737     }
14738     debug(F110,"ftp hookup C",hostnamebuf,0);
14739     ftp_host = hostnamebuf;
14740     s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14741     debug(F101,"ftp hookup socket","",s);
14742     if (s < 0) {
14743         perror("ftp: socket");
14744         ftpcode = -1;
14745 #ifdef DEBUG
14746         debtim = xdebtim;
14747 #endif /* DEBUG */
14748         return(0);
14749     }
14750     hisctladdr.sin_port = htons(cport);
14751     errno = 0;
14752 
14753 #ifdef COMMENT
14754   printf("hisctladdr=%d\n",sizeof(hisctladdr));
14755   printf("hisctladdr.sin_addr=%d\n",sizeof(hisctladdr.sin_addr));
14756   printf("sockaddr_in=%d\n",sizeof(struct sockaddr_in));
14757   printf("hisctladdr.sin_addr.s_addr=%d\n",sizeof(hisctladdr.sin_addr.s_addr));
14758 #endif	/* COMMENT */
14759 
14760 #ifdef HADDRLIST
14761     debug(F100,"ftp hookup HADDRLIST","",0);
14762     while
14763 #else
14764     debug(F100,"ftp hookup no HADDRLIST","",0);
14765     if
14766 #endif /* HADDRLIST */
14767       (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
14768           debug(F101,"ftp hookup connect failed","",errno);
14769 #ifdef HADDRLIST
14770           if (hp && hp->h_addr_list[1]) {
14771               int oerrno = errno;
14772 
14773               fprintf(stderr, "ftp: connect to address %s: ",
14774                       inet_ntoa(hisctladdr.sin_addr));
14775               errno = oerrno;
14776               perror((char *) 0);
14777               hp->h_addr_list++;
14778               memcpy((char *)&hisctladdr.sin_addr,
14779                      hp->h_addr_list[0],
14780                      sizeof(hisctladdr.sin_addr));
14781               fprintf(stdout, "Trying %s...\n",
14782                       inet_ntoa(hisctladdr.sin_addr));
14783 #ifdef TCPIPLIB
14784               socket_close(s);
14785 #else /* TCPIPLIB */
14786               close(s);
14787 #endif /* TCPIPLIB */
14788               s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
14789               if (s < 0) {
14790                   perror("ftp: socket");
14791                   ftpcode = -1;
14792 #ifdef DEBUG
14793                   debtim = xdebtim;
14794 #endif /* DEBUG */
14795                   return(0);
14796               }
14797               continue;
14798           }
14799 #endif /* HADDRLIST */
14800           perror("ftp: connect");
14801           ftpcode = -1;
14802           goto bad;
14803       }
14804     debug(F100,"ftp hookup connect ok","",0);
14805 
14806     len = sizeof (myctladdr);
14807     errno = 0;
14808     if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
14809         debug(F101,"ftp hookup getsockname failed","",errno);
14810         perror("ftp: getsockname");
14811         ftpcode = -1;
14812         goto bad;
14813     }
14814     debug(F100,"ftp hookup getsockname ok","",0);
14815 
14816 #ifndef NOHTTP
14817     if (tcp_http_proxy) {
14818 #ifdef OS2
14819         char * agent = "Kermit 95";     /* Default user agent */
14820 #else
14821         char * agent = "C-Kermit";
14822 #endif /* OS2 */
14823 
14824         if (http_connect(s,agent,NULL,
14825                          tcp_http_proxy_user,
14826                          tcp_http_proxy_pwd,
14827                          0,
14828                          proxyhost
14829                          ) < 0) {
14830             char * foo = NULL;
14831 #ifdef TCPIPLIB
14832             socket_close(s);
14833 #else /* TCPIPLIB */
14834             close(s);
14835 #endif /* TCPIPLIB */
14836 
14837             while (foo == NULL && tcp_http_proxy != NULL ) {
14838 
14839                 if (tcp_http_proxy_errno == 401 ||
14840                      tcp_http_proxy_errno == 407 ) {
14841                     char uid[UIDBUFLEN];
14842                     char pwd[PWDSIZ];
14843                     struct txtbox tb[2];
14844                     int ok;
14845 
14846                     tb[0].t_buf = uid;
14847                     tb[0].t_len = UIDBUFLEN;
14848                     tb[0].t_lbl = "Proxy Userid: ";
14849                     tb[0].t_dflt = NULL;
14850                     tb[0].t_echo = 1;
14851                     tb[1].t_buf = pwd;
14852                     tb[1].t_len = 256;
14853                     tb[1].t_lbl = "Proxy Passphrase: ";
14854                     tb[1].t_dflt = NULL;
14855                     tb[1].t_echo = 2;
14856 
14857                     ok = uq_mtxt("Proxy Server Authentication Required\n",
14858                                   NULL, 2, tb);
14859 
14860                     if (ok && uid[0]) {
14861                         char * proxy_user, * proxy_pwd;
14862 
14863                         proxy_user = tcp_http_proxy_user;
14864                         proxy_pwd  = tcp_http_proxy_pwd;
14865 
14866                         tcp_http_proxy_user = uid;
14867                         tcp_http_proxy_pwd = pwd;
14868 
14869                         foo = ftp_hookup(host, port, 0);
14870 
14871                         debug(F110,"ftp_hookup()",foo,0);
14872                         memset(pwd,0,PWDSIZ);
14873                         tcp_http_proxy_user = proxy_user;
14874                         tcp_http_proxy_pwd = proxy_pwd;
14875                     } else
14876                         break;
14877                 } else
14878                     break;
14879             }
14880             if (foo != NULL)
14881               return(foo);
14882             perror("ftp: connect");
14883             ftpcode = -1;
14884             goto bad;
14885         }
14886         ckstrncpy(hostnamebuf, proxyhost, MAXHOSTNAMELEN);
14887     }
14888 #endif /* NOHTTP */
14889 
14890     csocket = s;
14891 
14892 #ifdef CK_SSL
14893     if (tls) {
14894         /* FTP over SSL
14895          * If the connection is over an SSL proxy then the
14896          * auth_type will be NULL.  However, I'm not sure
14897          * whether we should protect the data channel in
14898          * that case or not.
14899          */
14900 
14901         debug(F100,"ftp hookup use_tls","",0);
14902         if (!ssl_auth()) {
14903             debug(F100,"ftp hookup ssl_auth failed","",0);
14904             auth_type = NULL;
14905             ftpcode = -1;
14906             csocket = -1;
14907             goto bad;
14908         }
14909         ssl_ftp_proxy = 1;
14910     }
14911 #endif /* CK_SSL */
14912 
14913 #ifdef IP_TOS
14914 #ifdef IPTOS_LOWDELAY
14915     tos = IPTOS_LOWDELAY;
14916     if (setsockopt(csocket, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
14917       perror("ftp: setsockopt TOS (ignored)");
14918 #endif
14919 #endif
14920     if (!quiet)
14921       printf("Connected to %s.\n", host);
14922 
14923     /* Read greeting from server */
14924     if (getreply(0,ftp_csl,ftp_csr,ftp_vbm,0) > 2) {
14925         debug(F100,"ftp hookup bad reply","",0);
14926 #ifdef TCPIPLIB
14927         socket_close(csocket);
14928 #else /* TCPIPLIB */
14929         close(csocket);
14930 #endif /* TCPIPLIB */
14931         ftpcode = -1;
14932         goto bad;
14933     }
14934 #ifdef SO_OOBINLINE
14935     {
14936         int on = 1;
14937         errno = 0;
14938         if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
14939 		       sizeof(on)) < 0) {
14940             perror("ftp: setsockopt");
14941             debug(F101,"ftp hookup setsockopt failed","",errno);
14942         }
14943 #ifdef DEBUG
14944         else
14945           debug(F100,"ftp hookup setsockopt ok","",0);
14946 #endif /* DEBUG */
14947     }
14948 #endif /* SO_OOBINLINE */
14949 
14950 #ifdef DEBUG
14951     debtim = xdebtim;
14952 #endif /* DEBUG */
14953     return(ftp_host);
14954 
14955   bad:
14956     debug(F100,"ftp hookup bad","",0);
14957 #ifdef TCPIPLIB
14958     socket_close(s);
14959 #else /* TCPIPLIB */
14960     close(s);
14961 #endif /* TCPIPLIB */
14962 #ifdef DEBUG
14963     debtim = xdebtim;
14964 #endif /* DEBUG */
14965     csocket = -1;
14966     return((char *)0);
14967 }
14968 
14969 static VOID
ftp_init()14970 ftp_init() {
14971     int i, n;
14972 
14973     /* The purpose of the initial REST 0 is not clear, but other FTP */
14974     /* clients do it.  In any case, failure of this command is not a */
14975     /* reliable indication that the server does not support Restart. */
14976 
14977     okrestart = 0;
14978     if (!noinit) {
14979         n = ftpcmd("REST 0",NULL,0,0,0);
14980         if (n == REPLY_COMPLETE)
14981           okrestart = 1;
14982 #ifdef COMMENT
14983         else if (ftp_deb)
14984           printf("WARNING: Unable to restore file pointer.\n");
14985 #endif /* COMMENT */
14986     }
14987     n = ftpcmd("SYST",NULL,0,0,0);      /* Get server system type */
14988     if (n == REPLY_COMPLETE) {
14989         register char *cp, c = NUL;
14990         cp = ckstrchr(ftp_reply_str+4,' '); /* Get first word of reply */
14991         if (cp == NULL)
14992           cp = ckstrchr(ftp_reply_str+4,'\r');
14993         if (cp) {
14994             if (cp[-1] == '.')
14995               cp--;
14996             c = *cp;                    /* Save this char */
14997             *cp = '\0';                 /* Replace it with NUL */
14998         }
14999         if (!quiet)
15000           printf("Remote system type is %s.\n",ftp_reply_str+4);
15001         ckstrncpy(ftp_srvtyp,ftp_reply_str+4,SRVNAMLEN);
15002         if (cp)                         /* Put back saved char */
15003           *cp = c;
15004     }
15005     alike = !ckstrcmp(ftp_srvtyp,myostype,-1,0);
15006 
15007     if (!ckstrcmp(ftp_srvtyp,"UNIX",-1,0)) servertype = SYS_UNIX;
15008     else if (!ckstrcmp(ftp_srvtyp,"WIN32",-1,0)) servertype = SYS_WIN32;
15009     else if (!ckstrcmp(ftp_srvtyp,"OS/2",-1,0)) servertype = SYS_WIN32;
15010     else if (!ckstrcmp(ftp_srvtyp,"VMS",-1,0)) servertype = SYS_VMS;
15011     else if (!ckstrcmp(ftp_srvtyp,"DOS",-1,0)) servertype = SYS_DOS;
15012     else if (!ckstrcmp(ftp_srvtyp,"TOPS20",-1,0)) servertype = SYS_TOPS20;
15013     else if (!ckstrcmp(ftp_srvtyp,"TOPS10",-1,0)) servertype = SYS_TOPS10;
15014 
15015 #ifdef FTP_PROXY
15016     unix_proxy = 0;
15017     if (servertype == SYS_UNIX && proxy) unix_proxy = 1;
15018 #endif /* FTP_PROXY */
15019 
15020     if (ftp_cmdlin && ftp_xfermode == XMODE_M)
15021       ftp_typ = binary;                 /* Type given on command line */
15022     else                                /* Otherwise set it automatically */
15023       ftp_typ = alike ? FTT_BIN : FTT_ASC;
15024     changetype(ftp_typ,0);              /* Change to this type */
15025     g_ftp_typ = ftp_typ;                /* Make it the global type */
15026     if (!quiet)
15027       printf("Default transfer mode is %s\n",
15028              ftp_typ ? "BINARY" : "TEXT (\"ASCII\")"
15029              );
15030     for (i = 0; i < 16; i++)		/* Init server FEATure table */
15031       sfttab[i] = 0;
15032     if (!noinit) {
15033         n = ftpcmd("MODE S",NULL,0,0,0); /* We always send in Stream mode */
15034 #ifdef COMMENT
15035         if (n != REPLY_COMPLETE)
15036           printf("WARNING: Server does not accept MODE S(TREAM)\n");
15037 #endif /* COMMENT */
15038         n = ftpcmd("STRU F",NULL,0,0,0); /* STRU File (not Record or Page) */
15039 #ifdef COMMENT
15040         if (n != REPLY_COMPLETE)
15041           printf("WARNING: Server does not accept STRU F(ILE)\n");
15042 #endif /* COMMENT */
15043 	if (featok) {
15044 	    n = ftpcmd("FEAT",NULL,0,0,0); /* Ask server about features */
15045 	    if (n == REPLY_COMPLETE) {
15046 		debug(F101,"ftp_init FEAT","",sfttab[0]);
15047 		if (deblog || ftp_deb) {
15048 		    int i;
15049 		    for (i = 1; i < 16 && i < nfeattab; i++) {
15050 			debug(F111,"ftp_init FEAT",feattab[i].kwd,sfttab[i]);
15051 			if (ftp_deb)
15052 			  printf("  Server %s %s\n",
15053 				 sfttab[i] ? "supports" : "does not support",
15054 				 feattab[i].kwd
15055 				 );
15056 		    }
15057 		    /* Deal with disabled MLST opts here if necessary */
15058 		    /* But why would it be? */
15059 		}
15060 	    }
15061 	}
15062     }
15063 }
15064 
15065 static int
ftp_login(host)15066 ftp_login(host) char * host; {          /* (also called from ckuusy.c) */
15067     static char ftppass[PASSBUFSIZ]="";
15068     char tmp[PASSBUFSIZ];
15069     char *user = NULL, *pass = NULL, *acct = NULL;
15070     int n, aflag = 0;
15071     extern char uidbuf[];
15072     extern char pwbuf[];
15073     extern int  pwflg, pwcrypt;
15074 
15075     debug(F111,"ftp_login",ftp_logname,ftp_log);
15076 
15077     if (!ckstrcmp(ftp_logname,"anonymous",-1,0))
15078       anonymous = 1;
15079     if (!ckstrcmp(ftp_logname,"ftp",-1,0))
15080       anonymous = 1;
15081 
15082 #ifdef FTP_SRP
15083     if (auth_type && !strcmp(auth_type, "SRP")) {
15084         user = srp_user;
15085         pass = srp_pass;
15086         acct = srp_acct;
15087     } else
15088 #endif /* FTP_SRP */
15089       if (anonymous) {
15090           user = "anonymous";
15091           if (ftp_tmp) {		/* They gave a password */
15092               pass = ftp_tmp;
15093           } else if (ftp_apw) {		/* SET FTP ANONYMOUS-PASSWORD */
15094 	      pass = ftp_apw;
15095 	  } else {			/* Supply user@host */
15096 	      ckmakmsg(tmp,PASSBUFSIZ,whoami(),"@",myhost,NULL);
15097 	      pass = tmp;
15098           }
15099 	  debug(F110,"ftp anonymous",pass,0);
15100       } else {
15101 #ifdef USE_RUSERPASS
15102           if (ruserpass(host, &user, &pass, &acct) < 0) {
15103               ftpcode = -1;
15104               return(0);
15105           }
15106 #endif /* USE_RUSERPASS */
15107           if (ftp_logname) {
15108               user = ftp_logname;
15109               pass = ftp_tmp;
15110           } else if (uidbuf[0] && (ftp_tmp || pwbuf[0] && pwflg)) {
15111               user = uidbuf;
15112               if (ftp_tmp) {
15113                   pass = ftp_tmp;
15114               } else if (pwbuf[0] && pwflg) {
15115                   ckstrncpy(ftppass,pwbuf,PASSBUFSIZ);
15116 #ifdef OS2
15117                   if ( pwcrypt )
15118                       ck_encrypt((char *)ftppass);
15119 #endif /* OS2 */
15120                   pass = ftppass;
15121               }
15122           }
15123           acct = ftp_acc;
15124           while (user == NULL) {
15125               char *myname, prompt[PROMPTSIZ];
15126               int ok;
15127 
15128               myname = whoami();
15129               if (myname)
15130                 ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
15131                           NULL,NULL,NULL,NULL,NULL,NULL,NULL);
15132               else
15133                 ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
15134               tmp[0] = '\0';
15135 
15136               ok = uq_txt(NULL,prompt,1,NULL,tmp,PASSBUFSIZ,NULL,
15137                           DEFAULT_UQ_TIMEOUT);
15138               if (!ok || *tmp == '\0')
15139                 user = myname;
15140               else
15141                 user = brstrip(tmp);
15142           }
15143       }
15144     n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15145     if (n == REPLY_COMPLETE) {
15146         /* determine if we need to send a dummy password */
15147         if (ftpcmd("PWD",NULL,0,0,0) != REPLY_COMPLETE)
15148           ftpcmd("PASS dummy",NULL,0,0,1);
15149     } else if (n == REPLY_CONTINUE) {
15150 #ifdef CK_ENCRYPTION
15151         int oldftp_cpl;
15152 #endif /* CK_ENCRYPTION */
15153 
15154         if (pass == NULL) {
15155             int ok;
15156             setint();
15157             ok = uq_txt(NULL," Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
15158                         DEFAULT_UQ_TIMEOUT);
15159             if (ok)
15160                 pass = brstrip(ftppass);
15161         }
15162 
15163 #ifdef CK_ENCRYPTION
15164         oldftp_cpl = ftp_cpl;
15165         ftp_cpl = FPL_PRV;
15166 #endif /* CK_ENCRYPTION */
15167         n = ftpcmd("PASS",pass,-1,-1,1);
15168         if (!anonymous && pass) {
15169             char * p = pass;
15170             while (*p++) *(p-1) = NUL;
15171             makestr(&ftp_tmp,NULL);
15172         }
15173 #ifdef CK_ENCRYPTION
15174         /* level may have changed */
15175         if (ftp_cpl == FPL_PRV)
15176           ftp_cpl = oldftp_cpl;
15177 #endif /* CK_ENCRYPTION */
15178     }
15179     if (n == REPLY_CONTINUE) {
15180         aflag++;
15181         if (acct == NULL) {
15182             static char ftpacct[80];
15183             int ok;
15184             setint();
15185             ok = uq_txt(NULL," Account: ",2,NULL,ftpacct,80,NULL,
15186                         DEFAULT_UQ_TIMEOUT);
15187             if (ok)
15188                 acct = brstrip(ftpacct);
15189         }
15190         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15191     }
15192     if (n != REPLY_COMPLETE) {
15193         fprintf(stderr, "FTP login failed.\n");
15194         if (haveurl)
15195           doexit(BAD_EXIT,-1);
15196         return(0);
15197     }
15198     if (!aflag && acct != NULL) {
15199         ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15200     }
15201     makestr(&ftp_logname,user);
15202     loggedin = 1;
15203 #ifdef LOCUS
15204     /* Unprefixed file management commands go to server */
15205     if (autolocus && !ftp_cmdlin) {
15206 	setlocus(0,1);
15207     }
15208 #endif /* LOCUS */
15209     ftp_init();
15210 
15211     if (anonymous && !quiet) {
15212         printf(" Logged in as anonymous (%s)\n",pass);
15213         memset(pass, 0, strlen(pass));
15214     }
15215     if (ftp_rdir) {
15216         if (doftpcwd(ftp_rdir,-1) < 1)
15217           doexit(BAD_EXIT,-1);
15218     }
15219 
15220 #ifdef FTP_PROXY
15221     if (proxy)
15222       return(1);
15223 #endif /* FTP_PROXY */
15224     return(1);
15225 }
15226 
15227 static int
ftp_reset()15228 ftp_reset() {
15229     int rc;
15230 #ifdef BSDSELECT
15231     int nfnd = 1;
15232     fd_set mask;
15233     FD_ZERO(&mask);
15234     while (nfnd > 0) {
15235         FD_SET(csocket, &mask);
15236         if ((nfnd = empty(&mask,0)) < 0) {
15237             perror("reset");
15238             ftpcode = -1;
15239             lostpeer();
15240             return(0);
15241         } else if (nfnd) {
15242             getreply(0,-1,-1,ftp_vbm,0);
15243         }
15244     }
15245 #else /* BSDSELECT */
15246 #ifdef IBMSELECT
15247     int nfnd = 1;
15248     while (nfnd > 0) {
15249         if ((nfnd = empty(&csocket,1,0)) < 0) {
15250             perror("reset");
15251             ftpcode = -1;
15252             lostpeer();
15253             return(0);
15254         } else if (nfnd) {
15255             getreply(0,-1,-1,ftp_vbm,0);
15256         }
15257     }
15258 #endif /* IBMSELECT */
15259 #endif /* BSDSELECT */
15260     rc = (ftpcmd("REIN",NULL,0,0,ftp_vbm) == REPLY_COMPLETE);
15261     if (rc > 0)
15262       loggedin = 0;
15263     return(rc);
15264 }
15265 
15266 static int
ftp_rename(from,to)15267 ftp_rename(from, to) char * from, * to; {
15268     int lcs = -1, rcs = -1;
15269 #ifndef NOCSETS
15270     if (ftp_xla) {
15271         lcs = ftp_csl;
15272         if (lcs < 0) lcs = fcharset;
15273         rcs = ftp_csx;
15274         if (rcs < 0) rcs = ftp_csr;
15275     }
15276 #endif /* NOCSETS */
15277     if (ftpcmd("RNFR",from,lcs,rcs,ftp_vbm) == REPLY_CONTINUE) {
15278         return(ftpcmd("RNTO",to,lcs,rcs,ftp_vbm) == REPLY_COMPLETE);
15279     }
15280     return(0);                          /* Failure */
15281 }
15282 
15283 static int
ftp_umask(mask)15284 ftp_umask(mask) char * mask; {
15285     int rc;
15286     rc = (ftpcmd("SITE UMASK",mask,-1,-1,1) == REPLY_COMPLETE);
15287     return(rc);
15288 }
15289 
15290 static int
ftp_user(user,pass,acct)15291 ftp_user(user,pass,acct) char * user, * pass, * acct; {
15292     int n = 0, aflag = 0;
15293     char pwd[PWDSIZ];
15294 
15295     if (!auth_type && ftp_aut) {
15296 #ifdef FTP_SRP
15297         if (ck_srp_is_installed()) {
15298             if (srp_ftp_auth( NULL, user, pass)) {
15299                 makestr(&pass,srp_pass);
15300             }
15301         }
15302 #endif /* FTP_SRP */
15303     }
15304     n = ftpcmd("USER",user,-1,-1,ftp_vbm);
15305     if (n == REPLY_COMPLETE)
15306       n = ftpcmd("PASS dummy",NULL,0,0,1);
15307     else if (n == REPLY_CONTINUE) {
15308 #ifdef CK_ENCRYPTION
15309         int oldftp_cpl;
15310 #endif /* CK_ENCRYPTION */
15311         if (pass == NULL || !pass[0]) {
15312             int ok;
15313             pwd[0] = '\0';
15314             setint();
15315             ok = uq_txt(NULL," Password: ",2,NULL,pwd,PWDSIZ,NULL,
15316                         DEFAULT_UQ_TIMEOUT);
15317             if (ok)
15318                 pass = brstrip(pwd);
15319         }
15320 
15321 #ifdef CK_ENCRYPTION
15322         if ((oldftp_cpl = ftp_cpl) == PROT_S)
15323           ftp_cpl = PROT_P;
15324 #endif /* CK_ENCRYPTION */
15325         n = ftpcmd("PASS",pass,-1,-1,1);
15326         memset(pass, 0, strlen(pass));
15327 #ifdef CK_ENCRYPTION
15328         /* level may have changed */
15329         if (ftp_cpl == PROT_P)
15330           ftp_cpl = oldftp_cpl;
15331 #endif /* CK_ENCRYPTION */
15332     }
15333     if (n == REPLY_CONTINUE) {
15334         if (acct == NULL || !acct[0]) {
15335             int ok;
15336             pwd[0] = '\0';
15337             setint();
15338             ok = uq_txt(NULL," Account: ",2,NULL,pwd,PWDSIZ,NULL,
15339                         DEFAULT_UQ_TIMEOUT);
15340             if (ok)
15341                 acct = pwd;
15342         }
15343         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15344         aflag++;
15345     }
15346     if (n != REPLY_COMPLETE) {
15347         printf("Login failed.\n");
15348         return(0);
15349     }
15350     if (!aflag && acct != NULL && acct[0]) {
15351         n = ftpcmd("ACCT",acct,-1,-1,ftp_vbm);
15352     }
15353     if (n == REPLY_COMPLETE) {
15354         makestr(&ftp_logname,user);
15355         loggedin = 1;
15356         ftp_init();
15357         return(1);
15358     }
15359     return(0);
15360 }
15361 
15362 char *
ftp_authtype()15363 ftp_authtype() {
15364     if (!connected)
15365       return("NULL");
15366     return(auth_type ? auth_type : "NULL");
15367 }
15368 
15369 char *
ftp_cpl_mode()15370 ftp_cpl_mode() {
15371     switch (ftp_cpl) {
15372       case FPL_CLR:
15373         return("clear");
15374       case FPL_SAF:
15375         return("safe");
15376       case FPL_PRV:
15377         return("private");
15378       case FPL_CON:
15379         return("confidential");
15380       default:
15381         return("(error)");
15382     }
15383 }
15384 
15385 char *
ftp_dpl_mode()15386 ftp_dpl_mode() {
15387     switch (ftp_dpl) {
15388       case FPL_CLR:
15389         return("clear");
15390       case FPL_SAF:
15391         return("safe");
15392       case FPL_PRV:
15393         return("private");
15394       case FPL_CON:
15395         return("confidential");
15396       default:
15397         return("(error)");
15398     }
15399 }
15400 
15401 
15402 /* remote_files() */
15403 /*
15404    Returns next remote filename on success;
15405    NULL on error or no more files with global rfrc set to:
15406      -1: Bad argument
15407      -2: Server error response to NLST, e.g. file not found
15408      -3: No more files
15409      -9: Internal error
15410 */
15411 #define FTPNAMBUFLEN CKMAXPATH+1024
15412 
15413 /* Check: ckmaxfiles CKMAXOPEN */
15414 
15415 #define MLSDEPTH 128			/* Stack of open temp files */
15416 static int mlsdepth = 0;		/* Temp file stack depth */
15417 static FILE * tmpfilptr[MLSDEPTH+1] = { NULL, NULL }; /* Temp file pointers */
15418 static char * tmpfilnam[MLSDEPTH+1] = { NULL, NULL }; /* Temp file names */
15419 
15420 static VOID
mlsreset()15421 mlsreset() {				/* Reset MGET temp-file stack */
15422     int i;
15423     for (i = 0; i <= mlsdepth; i++) {
15424 	if (tmpfilptr[i]) {
15425 	    fclose(tmpfilptr[i]);
15426 	    tmpfilptr[i] = NULL;
15427 	    if (tmpfilnam[i]) {
15428 #ifdef OS2
15429 		unlink(tmpfilnam[i]);
15430 #endif /* OS2 */
15431 		free(tmpfilnam[i]);
15432 	    }
15433 	}
15434     }
15435     mlsdepth = 0;
15436 }
15437 
15438 static CHAR *
15439 #ifdef CK_ANSIC
remote_files(int new_query,CHAR * arg,CHAR * pattern,int proxy_switch)15440 remote_files(int new_query, CHAR * arg, CHAR * pattern, int proxy_switch)
15441 #else /* CK_ANSIC */
15442 remote_files(new_query, arg, pattern, proxy_switch)
15443     int new_query;
15444     CHAR * arg;				/* That we send to the server */
15445     CHAR * pattern;			/* That we use locally */
15446     int proxy_switch;
15447 #endif /* CK_ANSIC */
15448 /* remote_files */ {
15449     static CHAR buf[FTPNAMBUFLEN];
15450     CHAR *cp, *whicharg;
15451     char * cdto = NULL;
15452     char * p;
15453     int i, x, forced = 0;
15454     int lcs = 0, rcs = 0, xlate = 0;
15455 
15456     debug(F101,"ftp remote_files new_query","",new_query);
15457     debug(F110,"ftp remote_files arg",arg,0);
15458     debug(F110,"ftp remote_files pattern",pattern,0);
15459 
15460     rfrc = -1;
15461     if (pattern)			/* Treat empty pattern same as NULL */
15462       if (!*pattern)
15463 	pattern = NULL;
15464     if (arg)				/* Ditto for arg */
15465       if (!*arg)
15466 	arg = NULL;
15467 
15468   again:
15469 
15470     if (new_query) {
15471         if (tmpfilptr[mlsdepth]) {
15472             fclose(tmpfilptr[mlsdepth]);
15473             tmpfilptr[mlsdepth] = NULL;
15474 #ifdef OS2
15475             if (!ftp_deb && !deblog)
15476               unlink(tmpfilnam[mlsdepth]);
15477 #endif /* OS2 */
15478         }
15479     }
15480     if (tmpfilptr[mlsdepth] == NULL) {
15481         extern char * tempdir;
15482         char * p;
15483         debug(F110,"ftp remote_files tempdir",tempdir,0);
15484         if (tempdir) {
15485             p = tempdir;
15486         } else {
15487 #ifdef OS2
15488 #ifdef NT
15489             p = getenv("K95TMP");
15490 #else
15491             p = getenv("K2TMP");
15492 #endif /* NT */
15493             if (!p)
15494 #endif /* OS2 */
15495               p = getenv("CK_TMP");
15496             if (!p)
15497               p = getenv("TMPDIR");
15498             if (!p) p = getenv("TEMP");
15499             if (!p) p = getenv("TMP");
15500 #ifdef OS2ORUNIX
15501             if (p) {
15502                 int len = strlen(p);
15503                 if (p[len-1] != '/'
15504 #ifdef OS2
15505                     && p[len-1] != '\\'
15506 #endif /* OS2 */
15507                      ) {
15508                     static char foo[CKMAXPATH];
15509                     ckstrncpy(foo,p,CKMAXPATH);
15510                     ckstrncat(foo,"/",CKMAXPATH);
15511                     p = foo;
15512                 }
15513             } else
15514 #else /* OS2ORUNIX */
15515             if (!p)
15516 #endif /* OS2ORUNIX */
15517 #ifdef UNIX                             /* Systems that have a standard */
15518                 p = "/tmp/";            /* temporary directory... */
15519 #else
15520 #ifdef datageneral
15521             p = ":TMP:";
15522 #else
15523             p = "";
15524 #endif /* datageneral */
15525 #endif /* UNIX */
15526         }
15527         debug(F110,"ftp remote_files p",p,0);
15528 
15529 	/* Get temp file */
15530 
15531 	if ((tmpfilnam[mlsdepth] = (char *)malloc(CKMAXPATH+1))) {
15532 	    ckmakmsg((char *)tmpfilnam[mlsdepth],
15533 		     CKMAXPATH+1,p,"ckXXXXXX",NULL,NULL);
15534 	} else {
15535 	    printf("?Malloc failure: remote_files()\n");
15536 	    return(NULL);
15537 	}
15538 
15539 #ifdef NT
15540 	{
15541 	    char * tmpfil = mktemp((char *)tmpfilnam[mlsdepth]);
15542 	    if ( tmpfil )
15543 		ckstrncpy(tmpfilnam[mlsdepth],tmpfil,CKMAXPATH+1);
15544 	}
15545 #else /* NT */
15546 #ifdef MKTEMP
15547 #ifdef MKSTEMP
15548 	x = mkstemp((char *)tmpfilnam[mlsdepth]);
15549 	if (x > -1) close(x);		/* We just want the name. */
15550 #else
15551         mktemp((char *)tmpfilnam[mlsdepth]);
15552 #endif /* MKSTEMP */
15553         /* if no mktmpnam() the name will just be "ckXXXXXX"... */
15554 #endif /* MKTEMP */
15555 #endif /* NT */
15556 
15557 	debug(F111,"ftp remote_files tmpfilnam[mlsdepth]",
15558 	      tmpfilnam[mlsdepth],mlsdepth);
15559 
15560 #ifdef FTP_PROXY
15561         if (proxy_switch) {
15562             pswitch(!proxy);
15563         }
15564 #endif /* FTP_PROXY */
15565 
15566         debug(F101,"ftp remote_files ftp_xla","",ftp_xla);
15567         debug(F101,"ftp remote_files ftp_csl","",ftp_csl);
15568         debug(F101,"ftp remote_files ftp_csr","",ftp_csr);
15569 
15570 #ifndef NOCSETS
15571         xlate = ftp_xla;                /* SET FTP CHARACTER-SET-TRANSLATION */
15572         if (xlate) {                    /* ON? */
15573             lcs = ftp_csl;              /* Local charset */
15574             if (lcs < 0) lcs = fcharset;
15575             if (lcs < 0) xlate = 0;
15576         }
15577         if (xlate) {                    /* Still ON? */
15578             rcs = ftp_csx;              /* Remote (Server) charset */
15579             if (rcs < 0) rcs = ftp_csr;
15580             if (rcs < 0) xlate = 0;
15581         }
15582 #endif /* NOCSETS */
15583 
15584 	forced = mgetforced;		/* MGET method forced? */
15585 	if (!forced || !mgetmethod)	/* Not forced... */
15586 	  mgetmethod = (sfttab[0] && sfttab[SFT_MLST]) ? /* so pick one */
15587 	      SND_MLS :
15588 	      SND_NLS;
15589 /*
15590   User's Command:                 Result:
15591     mget /nlst                     NLST (NULL)
15592     mget /nlst foo                 NLST foo
15593     mget /nlst *.txt               NLST *.txt
15594     mget /nlst /match:*.txt        NLST (NULL)
15595     mget /nlst /match:*.txt  foo   NLST foo
15596     mget /mlsd                     MLSD (NULL)
15597     mget /mlsd foo                 MLSD foo
15598     mget /mlsd *.txt               MLSD (NULL)
15599     mget /mlsd /match:*.txt        MLSD (NULL)
15600     mget /mlsd /match:*.txt  foo   MLSD foo
15601 */
15602 	x = -1;
15603 	while (x < 0) {
15604 	    if (pattern) {		/* Don't simplify this! */
15605 		whicharg = arg;
15606 	    } else if (mgetmethod == SND_MLS) {
15607 		if (arg)
15608 		  whicharg = iswild((char *)arg) ? NULL : arg;
15609 		else
15610 		  whicharg = NULL;
15611 	    } else {
15612 		whicharg = arg;
15613 	    }
15614 	    debug(F110,"ftp remote_files mgetmethod",
15615 		  mgetmethod == SND_MLS ? "MLSD" : "NLST", 0);
15616 	    debug(F110,"ftp remote_files whicharg",whicharg,0);
15617 
15618 	    x = recvrequest((mgetmethod == SND_MLS) ? "MLSD" : "NLST",
15619 			    (char *)tmpfilnam[mlsdepth],
15620 			    (char *)whicharg,
15621 			    "wb",
15622 			    0,
15623 			    0,
15624 			    NULL,
15625 			    xlate,
15626 			    lcs,
15627 			    rcs
15628 			    );
15629 	    if (x < 0) {		/* Chosen method wasn't accepted */
15630 		if (forced) {
15631 		    if (ftpcode > 500 && ftpcode < 505 && !quiet)
15632 		      printf("?%s: Not supported by server\n",
15633 			     mgetmethod == SND_MLS ? "MLSD" : "NLST"
15634 			     );
15635 		    rfrc = -2;		/* Fail */
15636 		    return(NULL);
15637 		}
15638 		/* Not forced - if MLSD failed, try NLST */
15639 		if (mgetmethod == SND_MLS) {  /* Server lied about MLST */
15640 		    sfttab[SFT_MLST] = 0;     /* So disable it */
15641 		    mlstok = 0;		      /* and */
15642 		    mgetmethod = SND_NLS;     /* try NLST */
15643 		    continue;
15644 		}
15645 		rfrc = -2;
15646 		return(NULL);
15647 	    }
15648 	}
15649 #ifdef FTP_PROXY
15650         if (proxy_switch) {
15651             pswitch(!proxy);
15652         }
15653 #endif /* FTP_PROXY */
15654         tmpfilptr[mlsdepth] = fopen((char *)tmpfilnam[mlsdepth], "r");
15655 #ifndef OS2
15656 	if (tmpfilptr[mlsdepth]) {
15657 	    if (!ftp_deb && !deblog)
15658 	      unlink(tmpfilnam[mlsdepth]);
15659 	}
15660 #endif /* OS2 */
15661       notemp:
15662         if (!tmpfilptr[mlsdepth]) {
15663             debug(F110,"ftp remote_files open fail",tmpfilnam[mlsdepth],0);
15664             if ((!dpyactive || ftp_deb))
15665               printf("?Can't find list of remote files, oops\n");
15666             rfrc = -9;
15667             return(NULL);
15668         }
15669 	if (ftp_deb)
15670 	  printf("LISTFILE: %s\n",tmpfilnam[mlsdepth]);
15671     }
15672     buf[0] = NUL;
15673     buf[FTPNAMBUFLEN-1] = NUL;
15674     buf[FTPNAMBUFLEN-2] = NUL;
15675 
15676     /* We have to redo all this because the first time was only for */
15677     /* for getting the file list, now it's for getting each file */
15678 
15679     if (arg && mgetmethod == SND_MLS) {	/* MLSD */
15680 	if (!pattern && iswild((char *)arg)) {
15681 	    pattern = arg;		/* Wild arg is really a pattern */
15682 	    if (pattern)
15683 	      if (!*pattern)
15684 		pattern = NULL;
15685 	    arg = NULL;			/* and not an arg */
15686 	}
15687 	if (new_query) {		/* Initial query? */
15688 	    cdto = (char *)arg;		/* (nonwild) arg given? */
15689 	    if (cdto)
15690 	      if (!*cdto)
15691 		cdto = NULL;
15692 	    if (cdto)			/* If so, then CD to it */
15693 	      doftpcwd(cdto,0);
15694 	}
15695     }
15696     new_query = 0;
15697 
15698     if (fgets((char *)buf, FTPNAMBUFLEN, tmpfilptr[mlsdepth]) == NULL) {
15699         fclose(tmpfilptr[mlsdepth]);
15700         tmpfilptr[mlsdepth] = NULL;
15701 
15702 #ifdef OS2
15703         if (!ftp_deb && !deblog)
15704           unlink(tmpfilnam[mlsdepth]);
15705 #endif /* OS2 */
15706         if (ftp_deb && !deblog) {
15707             printf("(Temporary file %s NOT deleted)\n",
15708 		   (char *)tmpfilnam[mlsdepth]);
15709         }
15710 	if (mlsdepth <= 0) {		/* EOF at depth 0 */
15711 	    rfrc = -3;			/* means we're done */
15712 	    return(NULL);
15713 	}
15714 	printf("POPPING(%d)...\n",mlsdepth-1);
15715 	if (tmpfilnam[mlsdepth]) free(tmpfilnam[mlsdepth]);
15716 	mlsdepth--;
15717 	doftpcdup();
15718 	zchdir("..");			/* <-- Not portable */
15719 	goto again;
15720     }
15721     if (buf[FTPNAMBUFLEN-1]) {
15722 	printf("?BUFFER OVERFLOW -- FTP NLST or MLSD string longer than %d\n",
15723 	       FTPNAMBUFLEN
15724 	       );
15725 	debug(F101,"remote_files buffer overrun","",FTPNAMBUFLEN);
15726 	return(NULL);
15727     }
15728     /* debug(F110,"ftp remote_files buf 1",buf,0); */
15729     if ((cp = (CHAR *)ckstrchr((char *)buf,'\n')) != NULL)
15730       *cp = '\0';
15731     if ((cp = (CHAR *)ckstrchr((char *)buf,'\r')) != NULL)
15732       *cp = '\0';
15733     debug(F110,"ftp remote_files buf",buf,0);
15734     rfrc = 0;
15735 
15736     if (ftp_deb)
15737       printf("[%s]\n",(char *)buf);
15738 
15739     havesize = (CK_OFF_T)-1;		/* Initialize file facts... */
15740     havetype = 0;
15741     makestr(&havemdtm,NULL);
15742     p = (char *)buf;
15743 
15744     if (mgetmethod == SND_NLS) {	/* NLST... */
15745 	if (pattern) {
15746 	    if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15747 	      goto again;
15748 	}
15749     } else {				/* MLSD... */
15750 	p = parsefacts((char *)buf);
15751 	switch (havetype) {
15752 	  case FTYP_FILE:		/* File: Get it if it matches */
15753 	    if (pattern) {
15754 		if (!ckmatch((char *)pattern,p,(servertype == SYS_UNIX),1))
15755 		  goto again;
15756 	    }
15757 	    break;
15758 	  case FTYP_CDIR:		/* Current directory */
15759 	  case FTYP_PDIR:		/* Parent directory */
15760 	    goto again;			/* Skip */
15761 	  case FTYP_DIR:		/* (Sub)Directory */
15762 	    if (!recursive)		/* If not /RECURSIVE */
15763 	      goto again;		/* Skip */
15764 	    if (mlsdepth < MLSDEPTH) {
15765 		char * p2 = NULL;
15766 		mlsdepth++;
15767 		printf("RECURSING [%s](%d)...\n",p,mlsdepth);
15768 		if (doftpcwd(p,0) > 0) {
15769 		    int x;
15770 		    if (!ckstrchr(p,'/')) {
15771 			/* zmkdir() needs dirsep */
15772 			if ((p2 = (char *)malloc((int)strlen(p) + 2))) {
15773 			    strcpy(p2,p);	/* SAFE */
15774 			    strcat(p2,"/");	/* SAFE */
15775 			    p = p2;
15776 			}
15777 		    }
15778 #ifdef NOMKDIR
15779 		    x = -1;
15780 #else
15781 		    x = zmkdir(p);
15782 #endif /* NOMKDIR */
15783 		    if (x > -1) {
15784 			zchdir(p);
15785 			p = (char *)remote_files(1,arg,pattern,0);
15786 			if (p2) free(p2);
15787 		    } else {
15788 			printf("?mkdir failed: [%s] Depth=%d\n",
15789 			       p,
15790 			       mlsdepth
15791 			       );
15792 			mlsreset();
15793 			if (p2) free(p2);
15794 			return(NULL);
15795 		    }
15796 		} else {
15797 		    printf("?CWD failed: [%s] Depth=%d\n",p,mlsdepth);
15798 		    mlsreset();
15799 		    return(NULL);
15800 		}
15801 	    } else {
15802 		printf("MAX DIRECTORY STACK DEPTH EXCEEDED: %d\n",
15803 		       mlsdepth
15804 		       );
15805 		mlsreset();
15806 		return(NULL);
15807 	    }
15808 	}
15809     }
15810 
15811 #ifdef DEBUG
15812     if (deblog) {
15813 	debug(F101,"remote_files havesize","",havesize);
15814 	debug(F101,"remote_files havetype","",havetype);
15815 	debug(F110,"remote_files havemdtm",havemdtm,0);
15816 	debug(F110,"remote_files name",p,0);
15817     }
15818 #endif /* DEBUG */
15819     return((CHAR *)p);
15820 }
15821 
15822 /* N O T  P O R T A B L E !!! */
15823 
15824 #if (SIZEOF_SHORT == 4)
15825 typedef unsigned short ftp_uint32;
15826 typedef short ftp_int32;
15827 #else
15828 #if (SIZEOF_INT == 4)
15829 typedef unsigned int ftp_uint32;
15830 typedef int ftp_int32;
15831 #else
15832 #if (SIZEOF_LONG == 4)
15833 typedef ULONG ftp_uint32;
15834 typedef long ftp_int32;
15835 #endif
15836 #endif
15837 #endif
15838 
15839 /* Perhaps use these in general, certainly use them for GSSAPI */
15840 
15841 #ifndef looping_write
15842 #define ftp_int32 int
15843 #define ftp_uint32 unsigned int
15844 static int
looping_write(fd,buf,len)15845 looping_write(fd, buf, len)
15846     int fd;
15847     register CONST char *buf;
15848     int len;
15849 {
15850     int cc;
15851     register int wrlen = len;
15852     do {
15853         cc = send(fd, (SENDARG2TYPE)buf, wrlen, 0);
15854         if (cc < 0) {
15855             if (errno == EINTR)
15856               continue;
15857             return(cc);
15858         } else {
15859             buf += cc;
15860             wrlen -= cc;
15861         }
15862     } while (wrlen > 0);
15863     return(len);
15864 }
15865 #endif
15866 #ifndef looping_read
15867 static int
looping_read(fd,buf,len)15868 looping_read(fd, buf, len)
15869     int fd;
15870     register char *buf;
15871     register int len;
15872 {
15873     int cc, len2 = 0;
15874 
15875     do {
15876         cc = recv(fd, (char *)buf, len,0);
15877         if (cc < 0) {
15878             if (errno == EINTR)
15879               continue;
15880             return(cc);                 /* errno is already set */
15881         } else if (cc == 0) {
15882             return(len2);
15883         } else {
15884             buf += cc;
15885             len2 += cc;
15886             len -= cc;
15887         }
15888     } while (len > 0);
15889     return(len2);
15890 }
15891 #endif /* looping_read */
15892 
15893 #define ERR -2
15894 
15895 #ifdef COMMENT
15896 static
secure_putbyte(fd,c)15897 secure_putbyte(fd, c) int fd; CHAR c; {
15898     int ret;
15899 
15900     ucbuf[nout++] = c;
15901     if (nout == (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR) {
15902         nout = 0;
15903         if (!ftpissecure())
15904           ret = send(fd, (SENDARG2TYPE)ucbuf,
15905                      (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR, 0);
15906         else
15907           ret = secure_putbuf(fd,
15908                               ucbuf,
15909                               (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR
15910                               );
15911         return(ret?ret:c);
15912     }
15913     return(c);
15914 }
15915 #endif /* COMMENT */
15916 
15917 /* returns:
15918  *       0  on success
15919  *      -1  on error (errno set)
15920  *      -2  on security error
15921  */
15922 static int
secure_flush(fd)15923 secure_flush(fd) int fd; {
15924     int rc = 0;
15925     int len = 0;
15926 
15927     if (nout > 0) {
15928         len = nout;
15929         if (!ftpissecure()) {
15930             rc = send(fd, (SENDARG2TYPE)ucbuf, nout, 0);
15931             nout = 0;
15932             goto xflush;
15933         } else {
15934             rc = secure_putbuf(fd, ucbuf, nout);
15935             if (rc)
15936               goto xflush;
15937         }
15938     }
15939     rc = (!ftpissecure()) ? 0 : secure_putbuf(fd, (CHAR *)"", nout = 0);
15940 
15941   xflush:
15942     if (rc > -1 && len > 0 && fdispla != XYFD_B) {
15943 	spackets++;
15944         spktl = len;
15945         ftscreen(SCR_PT,'D',(CK_OFF_T)spackets,NULL);
15946     }
15947     return(rc);
15948 }
15949 
15950 #ifdef COMMENT                          /* (not used) */
15951 /* returns:
15952  *      c>=0  on success
15953  *      -1    on error
15954  *      -2    on security error
15955  */
15956 static int
15957 #ifdef CK_ANSIC
secure_putc(char c,int fd)15958 secure_putc(char c, int fd)
15959 #else
15960 secure_putc(c, fd) char c; int fd;
15961 #endif /* CK_ANSIC */
15962 /* secure_putc */ {
15963     return(secure_putbyte(fd, (CHAR) c));
15964 }
15965 #endif /* COMMENT */
15966 
15967 /* returns:
15968  *      nbyte on success
15969  *      -1  on error (errno set)
15970  *      -2  on security error
15971  */
15972 static int
15973 #ifdef CK_ANSIC
secure_write(int fd,CHAR * buf,unsigned int nbyte)15974 secure_write(int fd, CHAR * buf, unsigned int nbyte)
15975 #else
15976 secure_write(fd, buf, nbyte)
15977     int fd;
15978     CHAR * buf;
15979     unsigned int nbyte;
15980 #endif /* CK_ANSIC */
15981 {
15982     int ret;
15983 
15984 #ifdef FTP_TIMEOUT
15985     ftp_timed_out = 0;
15986     if (check_data_connection(fd,1) < 0) {
15987 	ftp_timed_out = 1;
15988 	return(-3);
15989     }
15990 #endif	/* FTP_TIMEOUT */
15991 
15992     if (!ftpissecure()) {
15993         if (nout > 0) {
15994             if ((ret = send(fd, (SENDARG2TYPE)ucbuf, nout, 0)) < 0)
15995               return(ret);
15996             nout = 0;
15997         }
15998         return(send(fd,(SENDARG2TYPE)buf,nbyte,0));
15999     } else {
16000         int ucbuflen = (maxbuf ? maxbuf : actualbuf) - FUDGE_FACTOR;
16001         int bsent = 0;
16002 
16003         while (bsent < nbyte) {
16004             int b2cp = ((nbyte - bsent) > (ucbuflen - nout) ?
16005                         (ucbuflen - nout) : (nbyte - bsent));
16006 #ifdef DEBUG
16007 	    if (deblog) {
16008 		debug(F101,"secure_write ucbuflen","",ucbuflen);
16009 		debug(F101,"secure_write ucbufsiz","",ucbufsiz);
16010 		debug(F101,"secure_write bsent","",bsent);
16011 		debug(F101,"secure_write b2cp","",b2cp);
16012 	    }
16013 #endif /* DEBUG */
16014             memcpy(&ucbuf[nout],&buf[bsent],b2cp);
16015             nout += b2cp;
16016             bsent += b2cp;
16017 
16018             if (nout == ucbuflen) {
16019                 nout = 0;
16020                 ret = secure_putbuf(fd, ucbuf, ucbuflen);
16021                 if (ret < 0)
16022                   return(ret);
16023             }
16024         }
16025         return(bsent);
16026     }
16027 }
16028 
16029 /* returns:
16030  *       0  on success
16031  *      -1  on error (errno set)
16032  *      -2  on security error
16033  */
16034 static int
16035 #ifdef CK_ANSIC
secure_putbuf(int fd,CHAR * buf,unsigned int nbyte)16036 secure_putbuf(int fd, CHAR * buf, unsigned int nbyte)
16037 #else
16038 secure_putbuf(fd, buf, nbyte) int fd; CHAR * buf; unsigned int nbyte;
16039 #endif /* CK_ANSIC */
16040 {
16041     static char *outbuf = NULL;         /* output ciphertext */
16042 #ifdef FTP_SECURITY
16043     static unsigned int bufsize = 0;    /* size of outbuf */
16044 #endif /* FTP_SECURITY */
16045     ftp_int32 length   = 0;
16046     ftp_uint32 net_len = 0;
16047 
16048     /* Other auth types go here ... */
16049 #ifdef CK_SSL
16050     if (ssl_ftp_data_active_flag) {
16051         int count, error;
16052 
16053         /* there is no need to send an empty buffer when using SSL/TLS */
16054         if ( nbyte == 0 )
16055 	  return(0);
16056 
16057         count = SSL_write(ssl_ftp_data_con, buf, nbyte);
16058         error = SSL_get_error(ssl_ftp_data_con,count);
16059         switch (error) {
16060           case SSL_ERROR_NONE:
16061             return(0);
16062           case SSL_ERROR_WANT_WRITE:
16063           case SSL_ERROR_WANT_READ:
16064           case SSL_ERROR_SYSCALL:
16065 #ifdef NT
16066             {
16067                 int gle = GetLastError();
16068 		if (gle == 0)
16069 		  return(0);
16070 		debug(F111,"secure_putbuf","SSL_ERROR_SYSCALL",gle);
16071             }
16072 #endif /* NT */
16073           case SSL_ERROR_WANT_X509_LOOKUP:
16074           case SSL_ERROR_SSL:
16075           case SSL_ERROR_ZERO_RETURN:
16076           default:
16077             SSL_shutdown(ssl_ftp_data_con);
16078             SSL_free(ssl_ftp_data_con);
16079             ssl_ftp_data_active_flag = 0;
16080             ssl_ftp_data_con = NULL;
16081 #ifdef TCPIPLIB
16082             socket_close(data);
16083 #else /* TCPIPLIB */
16084 #ifdef USE_SHUTDOWN
16085             shutdown(data, 1+1);
16086 #endif /* USE_SHUTDOWN */
16087             close(data);
16088 #endif /* TCPIPLIB */
16089             data = -1;
16090             globaldin = data;
16091             return(-1);
16092         }
16093         return(-1);
16094     }
16095 #endif /* CK_SSL */
16096 
16097 #ifdef FTP_SRP
16098     if (ck_srp_is_installed() && (strcmp(auth_type, "SRP") == 0)) {
16099         if (bufsize < nbyte + FUDGE_FACTOR) {
16100             if (outbuf?
16101                 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16102                 (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16103                 bufsize = nbyte + FUDGE_FACTOR;
16104             } else {
16105                 bufsize = 0;
16106                 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16107                 return(ERR);
16108             }
16109         }
16110         if ((length =
16111              srp_encode(ftp_dpl == FPL_PRV,
16112                         (CHAR *) buf,
16113                         (CHAR *) outbuf,
16114                         nbyte
16115                         )
16116              ) < 0) {
16117             secure_error ("srp_encode failed");
16118             return ERR;
16119         }
16120     }
16121 #endif /* FTP_SRP */
16122 #ifdef FTP_KRB4
16123     if (ck_krb4_is_installed() && (strcmp(auth_type, "KERBEROS_V4") == 0)) {
16124         struct sockaddr_in myaddr, hisaddr;
16125         GSOCKNAME_T len;
16126         len = sizeof(myaddr);
16127         if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16128             secure_error("secure_putbuf: getsockname failed");
16129             return(ERR);
16130         }
16131         len = sizeof(hisaddr);
16132         if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16133             secure_error("secure_putbuf: getpeername failed");
16134             return(ERR);
16135         }
16136         if (bufsize < nbyte + FUDGE_FACTOR) {
16137             if (outbuf ?
16138                 (outbuf = realloc(outbuf, (unsigned) (nbyte + FUDGE_FACTOR))):
16139                  (outbuf = malloc((unsigned) (nbyte + FUDGE_FACTOR)))) {
16140                 bufsize = nbyte + FUDGE_FACTOR;
16141             } else {
16142                 bufsize = 0;
16143                 secure_error("%s (in malloc of PROT buffer)", ck_errstr());
16144                 return(ERR);
16145             }
16146         }
16147         if (ftp_dpl == FPL_PRV) {
16148             length = krb_mk_priv(buf, (CHAR *) outbuf, nbyte,
16149                                  ftp_sched,
16150 #ifdef KRB524
16151                                  ftp_cred.session,
16152 #else /* KRB524 */
16153                                  &ftp_cred.session,
16154 #endif /* KRB524 */
16155                                  &myaddr,
16156                                  &hisaddr
16157                                  );
16158         } else {
16159             length = krb_mk_safe(buf, (CHAR *) outbuf, nbyte,
16160 #ifdef KRB524
16161                                  ftp_cred.session,
16162 #else /* KRB524 */
16163                                  &ftp_cred.session,
16164 #endif /* KRB524 */
16165                                  &myaddr,
16166                                  &hisaddr
16167                                  );
16168         }
16169         if (length == -1) {
16170             secure_error("krb_mk_%s failed for KERBEROS_V4",
16171                          ftp_dpl == FPL_PRV ? "priv" : "safe");
16172             return(ERR);
16173         }
16174     }
16175 #endif /* FTP_KRB4 */
16176 #ifdef FTP_GSSAPI
16177     if (ck_gssapi_is_installed() && (strcmp(auth_type, "GSSAPI") == 0)) {
16178         gss_buffer_desc in_buf, out_buf;
16179         OM_uint32 maj_stat, min_stat;
16180         int conf_state;
16181 
16182         in_buf.value = buf;
16183         in_buf.length = nbyte;
16184         maj_stat = gss_seal(&min_stat, gcontext,
16185                             (ftp_dpl == FPL_PRV), /* confidential */
16186                             GSS_C_QOP_DEFAULT,
16187                             &in_buf,
16188                             &conf_state,
16189                             &out_buf
16190                             );
16191         if (maj_stat != GSS_S_COMPLETE) {
16192             /* generally need to deal */
16193             /* ie. should loop, but for now just fail */
16194             user_gss_error(maj_stat, min_stat,
16195                            ftp_dpl == FPL_PRV?
16196                            "GSSAPI seal failed":
16197                            "GSSAPI sign failed");
16198             return(ERR);
16199         }
16200         if (bufsize < out_buf.length) {
16201             if (outbuf ?
16202                 (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
16203                 (outbuf = malloc((unsigned) out_buf.length))) {
16204                 bufsize = out_buf.length;
16205             } else {
16206                 bufsize = 0;
16207                 secure_error("%s (in malloc of PROT buffer)",
16208                              ck_errstr());
16209                 return(ERR);
16210             }
16211         }
16212         memcpy(outbuf, out_buf.value, length=out_buf.length);
16213         gss_release_buffer(&min_stat, &out_buf);
16214     }
16215 #endif /* FTP_GSSAPI */
16216     net_len = htonl((ULONG) length);
16217     if (looping_write(fd, (char *)&net_len, 4) == -1)
16218       return(-1);
16219     if (looping_write(fd, outbuf, length) != length)
16220       return(-1);
16221     return(0);
16222 }
16223 
16224 
16225 /* fc = 0 means to get a byte; nonzero means to initialize buffer pointers */
16226 
16227 static int
secure_getbyte(fd,fc)16228 secure_getbyte(fd,fc) int fd,fc; {
16229     /* number of chars in ucbuf, pointer into ucbuf */
16230     static unsigned int nin = 0, bufp = 0;
16231     int kerror;
16232     ftp_uint32 length;
16233 
16234     if (fc) {
16235 	nin = bufp = 0;
16236 	ucbuf[0] = NUL;
16237 	return(0);
16238     }
16239     if (nin == 0) {
16240         if (iscanceled())
16241           return(-9);
16242 
16243 #ifdef FTP_TIMEOUT
16244 	if (check_data_connection(fd,0) < 0)
16245 	  return(-3);
16246 #endif	/* FTP_TIMEOUT */
16247 
16248 #ifdef CK_SSL
16249         if (ssl_ftp_data_active_flag) {
16250             int count, error;
16251             count = SSL_read(ssl_ftp_data_con, ucbuf, ucbufsiz);
16252             error = SSL_get_error(ssl_ftp_data_con,count);
16253 #ifdef DEBUG
16254 	    if (error != SSL_ERROR_NONE)
16255 	      debug(F101,"ftp secure_getbyte error","",error);
16256 	    if (count == 0)
16257 	      debug(F101,"ftp secure_getbyte count","",count);
16258 #endif	/* DEBUG */
16259             switch (error) {
16260               case SSL_ERROR_NONE:
16261 		if (count > 0) {
16262 		    nin = bufp = count;
16263 		    rpackets++;
16264 		    pktnum++;
16265 		    if (fdispla != XYFD_B) {
16266 			rpktl = count;
16267 			ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16268 		    }
16269 		    break;
16270 		}
16271               case SSL_ERROR_WANT_WRITE:
16272               case SSL_ERROR_WANT_READ:
16273               case SSL_ERROR_SYSCALL:
16274 #ifdef NT
16275                 {
16276                     int gle = GetLastError();
16277                 }
16278 #endif /* NT */
16279               case SSL_ERROR_WANT_X509_LOOKUP:
16280               case SSL_ERROR_SSL:
16281               case SSL_ERROR_ZERO_RETURN:
16282               default:
16283                 nin = bufp = count = 0;
16284                 SSL_shutdown(ssl_ftp_data_con);
16285                 SSL_free(ssl_ftp_data_con);
16286                 ssl_ftp_data_active_flag = 0;
16287                 ssl_ftp_data_con = NULL;
16288 #ifdef TCPIPLIB
16289                 socket_close(data);
16290 #else /* TCPIPLIB */
16291 #ifdef USE_SHUTDOWN
16292                 shutdown(data, 1+1);
16293 #endif /* USE_SHUTDOWN */
16294                 close(data);
16295 #endif /* TCPIPLIB */
16296                 data = -1;
16297                 globaldin = data;
16298                 break;
16299             }
16300         } else
16301 #endif /* CK_SSL */
16302           {
16303               kerror = looping_read(fd, (char *)&length, sizeof(length));
16304               if (kerror != sizeof(length)) {
16305                   secure_error("Couldn't read PROT buffer length: %d/%s",
16306                                kerror,
16307                                kerror == -1 ? ck_errstr()
16308                                : "premature EOF"
16309                                );
16310                   return(ERR);
16311               }
16312               debug(F101,"secure_getbyte length","",length);
16313               debug(F101,"secure_getbyte ntohl(length)","",ntohl(length));
16314 
16315               length = (ULONG) ntohl(length);
16316               if (length > maxbuf) {
16317                   secure_error("Length (%d) of PROT buffer > PBSZ=%u",
16318                                length,
16319                                maxbuf
16320                                );
16321                   return(ERR);
16322               }
16323               if ((kerror = looping_read(fd, ucbuf, length)) != length) {
16324                   secure_error("Couldn't read %u byte PROT buffer: %s",
16325                                length,
16326                                kerror == -1 ? ck_errstr() : "premature EOF"
16327                                );
16328                   return(ERR);
16329               }
16330 
16331               /* Other auth types go here ... */
16332 #ifdef FTP_SRP
16333               if (strcmp(auth_type, "SRP") == 0) {
16334                   if ((nin = bufp = srp_decode (ftp_dpl == FPL_PRV,
16335                                                 (CHAR *) ucbuf,
16336                                                 ucbuf,
16337                                                 length
16338                                                 )
16339                        ) == -1) {
16340                       secure_error ("srp_encode failed" );
16341                       return ERR;
16342                   }
16343               }
16344 #endif /* FTP_SRP */
16345 #ifdef FTP_KRB4
16346               if (strcmp(auth_type, "KERBEROS_V4") == 0) {
16347                   struct sockaddr_in myaddr, hisaddr;
16348                   GSOCKNAME_T len;
16349                   len = sizeof(myaddr);
16350                   if (getsockname(fd, (struct sockaddr*)&myaddr, &len) < 0) {
16351                       secure_error("secure_putbuf: getsockname failed");
16352                       return(ERR);
16353                   }
16354                   len = sizeof(hisaddr);
16355                   if (getpeername(fd, (struct sockaddr*)&hisaddr, &len) < 0) {
16356                       secure_error("secure_putbuf: getpeername failed");
16357                       return(ERR);
16358                   }
16359                   if (ftp_dpl) {
16360                       kerror = krb_rd_priv(ucbuf, length, ftp_sched,
16361 #ifdef KRB524
16362                                            ftp_cred.session,
16363 #else /* KRB524 */
16364                                            &ftp_cred.session,
16365 #endif /* KRB524 */
16366                                            &hisaddr, &myaddr, &ftp_msg_data);
16367                   } else {
16368                       kerror = krb_rd_safe(ucbuf, length,
16369 #ifdef KRB524
16370                                            ftp_cred.session,
16371 #else /* KRB524 */
16372                                            &ftp_cred.session,
16373 #endif /* KRB524 */
16374                                            &hisaddr, &myaddr, &ftp_msg_data);
16375                   }
16376                   if (kerror) {
16377                       secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
16378                                    ftp_dpl == FPL_PRV ? "priv" : "safe",
16379                                    krb_get_err_text(kerror));
16380                       return(ERR);
16381                   }
16382                   memcpy(ucbuf,ftp_msg_data.app_data,ftp_msg_data.app_length);
16383                   nin = bufp = ftp_msg_data.app_length;
16384               }
16385 #endif /* FTP_KRB4 */
16386 #ifdef FTP_GSSAPI
16387               if (strcmp(auth_type, "GSSAPI") == 0) {
16388                   gss_buffer_desc xmit_buf, msg_buf;
16389                   OM_uint32 maj_stat, min_stat;
16390                   int conf_state;
16391 
16392                   xmit_buf.value = ucbuf;
16393                   xmit_buf.length = length;
16394                   conf_state = (ftp_dpl == FPL_PRV);
16395                   /* decrypt/verify the message */
16396                   maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
16397                                         &msg_buf, &conf_state, NULL);
16398                   if (maj_stat != GSS_S_COMPLETE) {
16399                       user_gss_error(maj_stat, min_stat,
16400                                      (ftp_dpl == FPL_PRV)?
16401                                      "failed unsealing ENC message":
16402                                      "failed unsealing MIC message");
16403                       return ERR;
16404                   }
16405                   memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
16406                   gss_release_buffer(&min_stat, &msg_buf);
16407               }
16408 #endif /* FTP_GSSAPI */
16409               /* Other auth types go here ... */
16410 
16411               /* Update file transfer display */
16412               rpackets++;
16413               pktnum++;
16414               if (fdispla != XYFD_B) {
16415                   rpktl = nin;
16416                   ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16417               }
16418           }
16419     }
16420     if (nin == 0)
16421       return(EOF);
16422     else
16423       return(ucbuf[bufp - nin--]);
16424 }
16425 
16426 /* secure_getc(fd,fc)
16427  * Call with:
16428  *   fd = file descriptor for connection.
16429  *   fc = 0 to get a character, fc != 0 to initialize buffer pointers.
16430  * Returns:
16431  *   c>=0 on success (character value)
16432  *   -1   on EOF
16433  *   -2   on security error
16434  *   -3   on timeout (if built with FTP_TIMEOUT defined)
16435  */
16436 static int
secure_getc(fd,fc)16437 secure_getc(fd,fc) int fd,fc; {		/* file descriptor, function code */
16438 
16439     if (!ftpissecure()) {
16440         static unsigned int nin = 0, bufp = 0;
16441 	if (fc) {
16442 	    nin = bufp = 0;
16443 	    ucbuf[0] = NUL;
16444 	    return(0);
16445 	}
16446         if (nin == 0) {
16447             if (iscanceled())
16448               return(-9);
16449 
16450 #ifdef FTP_TIMEOUT
16451 	    if (check_data_connection(fd,0) < 0) {
16452                 debug(F100,"secure_getc TIMEOUT","",0);
16453                 nin = bufp = 0;
16454 		ftp_timed_out = 1;
16455 		return(-3);
16456 	    }
16457 #endif	/* FTP_TIMEOUT */
16458 
16459             nin = bufp = recv(fd,(char *)ucbuf,actualbuf,0);
16460             if ((nin == 0) || (nin == (unsigned int)-1)) {
16461                 debug(F111,"secure_getc recv errno",ckitoa(nin),errno);
16462                 debug(F101,"secure_getc returns EOF","",EOF);
16463                 nin = bufp = 0;
16464                 return(EOF);
16465             }
16466             debug(F101,"ftp secure_getc recv","",nin);
16467             ckhexdump("ftp secure_getc recv",ucbuf,16);
16468             rpackets++;
16469             pktnum++;
16470             if (fdispla != XYFD_B) {
16471                 rpktl = nin;
16472                 ftscreen(SCR_PT,'D',(CK_OFF_T)rpackets,NULL);
16473             }
16474         }
16475         return(ucbuf[bufp - nin--]);
16476     } else
16477       return(secure_getbyte(fd,fc));
16478 }
16479 
16480 /* returns:
16481  *     n>0  on success (n == # of bytes read)
16482  *       0  on EOF
16483  *      -1  on error (errno set), only for FPL_CLR
16484  *      -2  on security error
16485  */
16486 static int
secure_read(fd,buf,nbyte)16487 secure_read(fd, buf, nbyte) int fd; char *buf; int nbyte; {
16488     static int c = 0;
16489     int i;
16490 
16491     debug(F101,"secure_read bytes requested","",nbyte);
16492     if (c == EOF)
16493       return(c = 0);
16494     for (i = 0; nbyte > 0; nbyte--) {
16495         c = secure_getc(fd,0);
16496         switch (c) {
16497           case -9:                      /* Canceled from keyboard */
16498             debug(F101,"ftp secure_read interrupted","",c);
16499             return(0);
16500           case ERR:
16501             debug(F101,"ftp secure_read error","",c);
16502             return(c);
16503           case EOF:
16504             debug(F101,"ftp secure_read EOF","",c);
16505             if (!i)
16506               c = 0;
16507             return(i);
16508 #ifdef FTP_TIMEOUT
16509           case -3:
16510             debug(F101,"ftp secure_read timeout","",c);
16511 	    return(c);
16512 #endif	/* FTP_TIMEOUT */
16513           default:
16514             buf[i++] = c;
16515         }
16516     }
16517     return(i);
16518 }
16519 
16520 #ifdef USE_RUSERPASS
16521 /* BEGIN_RUSERPASS
16522  *
16523  * Copyright (c) 1985 Regents of the University of California.
16524  * All rights reserved.
16525  *
16526  * Redistribution and use in source and binary forms, with or without
16527  * modification, are permitted provided that the following conditions
16528  * are met:
16529  * 1. Redistributions of source code must retain the above copyright
16530  *    notice, this list of conditions and the following disclaimer.
16531  * 2. Redistributions in binary form must reproduce the above copyright
16532  *    notice, this list of conditions and the following disclaimer in the
16533  *    documentation and/or other materials provided with the distribution.
16534  * 3. All advertising materials mentioning features or use of this software
16535  *    must display the following acknowledgement:
16536  *      This product includes software developed by the University of
16537  *      California, Berkeley and its contributors.
16538  * 4. Neither the name of the University nor the names of its contributors
16539  *    may be used to endorse or promote products derived from this software
16540  *    without specific prior written permission.
16541  *
16542  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16543  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16544  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16545  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16546  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16547  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16548  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16549  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16550  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16551  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16552  * SUCH DAMAGE.
16553  */
16554 
16555 #ifndef lint
16556 static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91";
16557 #endif /* not lint */
16558 
16559 #ifndef MAXHOSTNAMELEN
16560 #define MAXHOSTNAMELEN 64
16561 #endif
16562 
16563 char * renvlook();
16564 static FILE * cfile;
16565 
16566 #define DEFAULT 1
16567 #define LOGIN   2
16568 #define PASSWD  3
16569 #define ACCOUNT 4
16570 #define MACDEF  5
16571 #define ID      10
16572 #define MACH    11
16573 
16574 static char tokval[100];
16575 
16576 static struct toktab {
16577     char *tokstr;
16578     int tval;
16579 } toktab[]= {
16580     "default",  DEFAULT,
16581     "login",    LOGIN,
16582     "password", PASSWD,
16583     "passwd",   PASSWD,
16584     "account",  ACCOUNT,
16585     "machine",  MACH,
16586     "macdef",   MACDEF,
16587     0,          0
16588 };
16589 
16590 static int
token()16591 token() {
16592     char *cp;
16593     int c;
16594     struct toktab *t;
16595 
16596     if (feof(cfile))
16597       return(0);
16598     while ((c = getc(cfile)) != EOF &&
16599            (c == '\n' || c == '\t' || c == ' ' || c == ','))
16600       continue;
16601     if (c == EOF)
16602       return(0);
16603     cp = tokval;
16604     if (c == '"') {
16605         while ((c = getc(cfile)) != EOF && c != '"') {
16606             if (c == '\\')
16607               c = getc(cfile);
16608             *cp++ = c;
16609         }
16610     } else {
16611         *cp++ = c;
16612         while ((c = getc(cfile)) != EOF
16613                && c != '\n' && c != '\t' && c != ' ' && c != ',') {
16614             if (c == '\\')
16615               c = getc(cfile);
16616             *cp++ = c;
16617         }
16618     }
16619     *cp = 0;
16620     if (tokval[0] == 0)
16621       return(0);
16622     for (t = toktab; t->tokstr; t++)
16623       if (!strcmp(t->tokstr, tokval))
16624         return(t->tval);
16625     return(ID);
16626 }
16627 
ruserpass(host,aname,apass,aacct)16628 ruserpass(host, aname, apass, aacct)
16629     char *host, **aname, **apass, **aacct;
16630 {
16631     char *hdir, buf[FTP_BUFSIZ], *tmp;
16632     char myname[MAXHOSTNAMELEN], *mydomain;
16633     int t, i, c, usedefault = 0;
16634 #ifdef NT
16635     struct _stat stb;
16636 #else /* NT */
16637     struct stat stb;
16638 #endif /* NT */
16639 
16640     hdir = getenv("HOME");
16641     if (hdir == NULL)
16642         hdir = ".";
16643     ckmakmsg(buf,FTP_BUFSIZ,hdir,"/.netrc",NULL,NULL);
16644     cfile = fopen(buf, "r");
16645     if (cfile == NULL) {
16646         if (errno != ENOENT)
16647           perror(buf);
16648         return(0);
16649     }
16650     if (gethostname(myname, MAXHOSTNAMELEN) < 0)
16651       myname[0] = '\0';
16652     if ((mydomain = ckstrchr(myname, '.')) == NULL)
16653       mydomain = "";
16654 
16655   next:
16656     while ((t = token())) switch(t) {
16657 
16658       case DEFAULT:
16659         usedefault = 1;
16660         /* FALL THROUGH */
16661 
16662       case MACH:
16663         if (!usedefault) {
16664             if (token() != ID)
16665               continue;
16666             /*
16667              * Allow match either for user's input host name
16668              * or official hostname.  Also allow match of
16669              * incompletely-specified host in local domain.
16670              */
16671             if (ckstrcmp(host, tokval,-1,1) == 0)
16672               goto match;
16673             if (ckstrcmp(ftp_host, tokval,-1,0) == 0)
16674               goto match;
16675             if ((tmp = ckstrchr(ftp_host, '.')) != NULL &&
16676                 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16677                 ckstrcmp(ftp_host, tokval, tmp-ftp_host,0) == 0 &&
16678                 tokval[tmp - ftp_host] == '\0')
16679               goto match;
16680             if ((tmp = ckstrchr(host, '.')) != NULL &&
16681                 ckstrcmp(tmp, mydomain,-1,1) == 0 &&
16682                 ckstrcmp(host, tokval, tmp - host, 0) == 0 &&
16683                 tokval[tmp - host] == '\0')
16684               goto match;
16685             continue;
16686         }
16687 
16688       match:
16689         while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16690 
16691           case LOGIN:
16692             if (token())
16693               if (*aname == 0) {
16694                   *aname = malloc((unsigned) strlen(tokval) + 1);
16695                   strcpy(*aname, tokval);      /* safe */
16696               } else {
16697                   if (strcmp(*aname, tokval))
16698                     goto next;
16699               }
16700             break;
16701           case PASSWD:
16702             if (strcmp(*aname, "anonymous") &&
16703                 fstat(fileno(cfile), &stb) >= 0 &&
16704                 (stb.st_mode & 077) != 0) {
16705                 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16706                 fprintf(stderr, "Remove password or correct mode.\n");
16707                 goto bad;
16708             }
16709             if (token() && *apass == 0) {
16710                 *apass = malloc((unsigned) strlen(tokval) + 1);
16711                 strcpy(*apass, tokval);          /* safe */
16712             }
16713             break;
16714           case ACCOUNT:
16715             if (fstat(fileno(cfile), &stb) >= 0
16716                 && (stb.st_mode & 077) != 0) {
16717                 fprintf(stderr, "Error - .netrc file not correct mode.\n");
16718                 fprintf(stderr, "Remove account or correct mode.\n");
16719                 goto bad;
16720             }
16721             if (token() && *aacct == 0) {
16722                 *aacct = malloc((unsigned) strlen(tokval) + 1);
16723                 strcpy(*aacct, tokval);          /* safe */
16724             }
16725             break;
16726 
16727           default:
16728             fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
16729             break;
16730         }
16731         goto done;
16732     }
16733 
16734   done:
16735     fclose(cfile);
16736     return(0);
16737 
16738   bad:
16739     fclose(cfile);
16740     return(-1);
16741 }
16742 #endif /* USE_RUSERPASS */
16743 
16744 static char *radixN =
16745   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16746 
16747 static char pad = '=';
16748 
16749 static int
radix_encode(inbuf,outbuf,inlen,outlen,decode)16750 radix_encode(inbuf, outbuf, inlen, outlen, decode)
16751     CHAR inbuf[], outbuf[];
16752     int inlen, *outlen, decode;
16753 {
16754     int i, j, D = 0;
16755     char *p;
16756     CHAR c = NUL;
16757 
16758     if (decode) {
16759         for (i = 0, j = 0; inbuf[i] && inbuf[i] != pad; i++) {
16760             if ((p = ckstrchr(radixN, inbuf[i])) == NULL)
16761               return(1);
16762             D = p - radixN;
16763             switch (i&3) {
16764               case 0:
16765                 outbuf[j] = D<<2;
16766                 break;
16767               case 1:
16768                 outbuf[j++] |= D>>4;
16769                 outbuf[j] = (D&15)<<4;
16770                 break;
16771               case 2:
16772                 outbuf[j++] |= D>>2;
16773                 outbuf[j] = (D&3)<<6;
16774                 break;
16775               case 3:
16776                 outbuf[j++] |= D;
16777             }
16778             if (j == *outlen)
16779               return(4);
16780         }
16781         switch (i&3) {
16782           case 1: return(3);
16783           case 2: if (D&15) return(3);
16784             if (strcmp((char *)&inbuf[i], "==")) return(2);
16785             break;
16786           case 3: if (D&3) return(3);
16787             if (strcmp((char *)&inbuf[i], "="))  return(2);
16788         }
16789         *outlen = j;
16790     } else {
16791         for (i = 0, j = 0; i < inlen; i++) {
16792             switch (i%3) {
16793               case 0:
16794                 outbuf[j++] = radixN[inbuf[i]>>2];
16795                 c = (inbuf[i]&3)<<4;
16796                 break;
16797               case 1:
16798                 outbuf[j++] = radixN[c|inbuf[i]>>4];
16799                 c = (inbuf[i]&15)<<2;
16800                 break;
16801               case 2:
16802                 outbuf[j++] = radixN[c|inbuf[i]>>6];
16803                 outbuf[j++] = radixN[inbuf[i]&63];
16804                 c = 0;
16805             }
16806             if (j == *outlen)
16807               return(4);
16808         }
16809         if (i%3) outbuf[j++] = radixN[c];
16810         switch (i%3) {
16811           case 1: outbuf[j++] = pad;
16812           case 2: outbuf[j++] = pad;
16813         }
16814         outbuf[*outlen = j] = '\0';
16815     }
16816     return(0);
16817 }
16818 
16819 static char *
radix_error(e)16820 radix_error(e) int e;
16821 {
16822     switch (e) {
16823       case 0:  return("Success");
16824       case 1:  return("Bad character in encoding");
16825       case 2:  return("Encoding not properly padded");
16826       case 3:  return("Decoded # of bits not a multiple of 8");
16827       case 4:  return("Output buffer too small");
16828       default: return("Unknown error");
16829     }
16830 }
16831 /* END_RUSERPASS */
16832 
16833 #ifdef FTP_SRP
16834 /*---------------------------------------------------------------------------+
16835  |                                                                           |
16836  |   Package: srpftp                                                         |
16837  |   Author: Eugene Jhong                                                    |
16838  |                                                                           |
16839  +---------------------------------------------------------------------------*/
16840 
16841 /*
16842  * Copyright (c) 1997-1999  The Stanford SRP Authentication Project
16843  * All Rights Reserved.
16844  *
16845  * Permission is hereby granted, free of charge, to any person obtaining
16846  * a copy of this software and associated documentation files (the
16847  * "Software"), to deal in the Software without restriction, including
16848  * without limitation the rights to use, copy, modify, merge, publish,
16849  * distribute, sublicense, and/or sell copies of the Software, and to
16850  * permit persons to whom the Software is furnished to do so, subject to
16851  * the following conditions:
16852  *
16853  * The above copyright notice and this permission notice shall be
16854  * included in all copies or substantial portions of the Software.
16855  *
16856  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16857  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16858  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16859  *
16860  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
16861  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
16862  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
16863  * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
16864  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16865  *
16866  * In addition, the following conditions apply:
16867  *
16868  * 1. Any software that incorporates the SRP authentication technology
16869  *    must display the following acknowlegment:
16870  *    "This product uses the 'Secure Remote Password' cryptographic
16871  *     authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
16872  *
16873  * 2. Any software that incorporates all or part of the SRP distribution
16874  *    itself must also display the following acknowledgment:
16875  *    "This product includes software developed by Tom Wu and Eugene
16876  *     Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
16877  *
16878  * 3. Redistributions in source or binary form must retain an intact copy
16879  *    of this copyright notice and list of conditions.
16880  */
16881 
16882 #define SRP_PROT_VERSION        1
16883 
16884 #ifdef CK_ENCRYPTION
16885 #define SRP_DEFAULT_CIPHER      CIPHER_ID_CAST5_CBC
16886 #else
16887 #define SRP_DEFAULT_CIPHER      CIPHER_ID_NONE
16888 #endif /* CK_ENCRYPTION */
16889 
16890 #define SRP_DEFAULT_HASH        HASH_ID_SHA
16891 
16892 CHAR srp_pref_cipher = CIPHER_ID_DES3_ECB;
16893 CHAR srp_pref_hash = HASH_ID_SHA;
16894 
16895 static struct t_client *tc = NULL;
16896 static CHAR *skey = NULL;
16897 static krypto_context *incrypt = NULL;
16898 static krypto_context *outcrypt = NULL;
16899 
16900 typedef unsigned int srp_uint32;
16901 
16902 /*--------------------------------------------------------------+
16903  | srp_selcipher: select cipher                                 |
16904  +--------------------------------------------------------------*/
16905 static int
srp_selcipher(cname)16906 srp_selcipher (cname) char *cname; {
16907     cipher_desc *cd;
16908 
16909     if (!(cd = cipher_getdescbyname (cname))) {
16910         int i;
16911         CHAR *list = cipher_getlist ();
16912 
16913         fprintf (stderr, "ftp: supported ciphers:\n\n");
16914         for (i = 0; i < strlen (list); i++)
16915           fprintf (stderr, "    %s\n", (cipher_getdescbyid(list[i]))->name);
16916         fprintf (stderr, "\n");
16917         return -1;
16918     }
16919     srp_pref_cipher = cd->id;
16920     return 0;
16921 }
16922 
16923 /*--------------------------------------------------------------+
16924  | srp_selhash: select hash                                     |
16925  +--------------------------------------------------------------*/
16926 static int
srp_selhash(hname)16927 srp_selhash (hname) char *hname; {
16928     hash_desc *hd;
16929 
16930     if (!(hd = hash_getdescbyname (hname))) {
16931         int i;
16932         CHAR *list = hash_getlist ();
16933 
16934         fprintf (stderr, "ftp: supported hash functions:\n\n");
16935         for (i = 0; i < strlen (list); i++)
16936           fprintf (stderr, "    %s\n", (hash_getdescbyid(list[i]))->name);
16937         fprintf (stderr, "\n");
16938         return -1;
16939     }
16940     srp_pref_hash = hd->id;
16941     return 0;
16942 }
16943 
16944 /*--------------------------------------------------------------+
16945  | srp_userpass: get username and password                      |
16946  +--------------------------------------------------------------*/
16947 static int
srp_userpass(host)16948 srp_userpass (host) char *host; {
16949     char tmp[BUFSIZ], prompt[PROMPTSIZ];
16950     char *user;
16951 
16952     user = NULL;
16953 #ifdef USE_RUSERPASS
16954     ruserpass (host, &user, &srp_pass, &srp_acct);
16955 #endif /* USE_RUSERPASS */
16956 
16957     while (user == NULL)     {
16958         char *myname;
16959         int ok;
16960 
16961         myname = whoami();
16962         if (!myname) myname = "";
16963         if (myname[0])
16964           ckmakxmsg(prompt,PROMPTSIZ," Name (",host,":",myname,"): ",
16965                     NULL,NULL,NULL,NULL,NULL,NULL,NULL);
16966         else
16967           ckmakmsg(prompt,PROMPTSIZ," Name (",host,"): ",NULL);
16968         tmp[0] = '\0';
16969         ok = uq_txt(NULL,prompt,1,NULL,tmp,BUFSIZ,NULL,
16970                     DEFAULT_UQ_TIMEOUT);
16971         if (!ok || *tmp == '\0')
16972           user = myname;
16973         else
16974           user = brstrip(tmp);
16975     }
16976     ckstrncpy (srp_user, user,BUFSIZ);
16977     return(0);
16978 }
16979 
16980 /*--------------------------------------------------------------+
16981  | srp_reset: reset srp information                             |
16982  +--------------------------------------------------------------*/
16983 static int
srp_reset()16984 srp_reset () {
16985     if (tc) { t_clientclose (tc); tc = NULL; }
16986     if (incrypt) { krypto_delete (incrypt); incrypt = NULL; }
16987     if (outcrypt) { krypto_delete (outcrypt); outcrypt = NULL; }
16988     return(0);
16989 }
16990 
16991 /*--------------------------------------------------------------+
16992  | srp_ftp_auth: perform srp authentication                         |
16993  +--------------------------------------------------------------*/
16994 static int
srp_ftp_auth(host,user,pass)16995 srp_ftp_auth(host, user, pass)
16996     char *host;
16997     char *user;
16998     char *pass;
16999 {
17000     struct t_num *wp;
17001     struct t_num N;
17002     struct t_num g;
17003     struct t_num s;
17004     struct t_num yp;
17005     CHAR buf[FTP_BUFSIZ];
17006     CHAR tmp[FTP_BUFSIZ];
17007     CHAR *bp, *cp;
17008     int n, e, clen, blen, len, i;
17009     CHAR cid = 0;
17010     CHAR hid = 0;
17011 
17012     srp_pass = srp_acct = 0;
17013 
17014     n = ftpcmd("AUTH SRP",NULL,0,0,ftp_vbm);
17015     if (n != REPLY_CONTINUE) {
17016         if (ftp_deb)
17017             fprintf(stderr, "SRP rejected as an authentication type\n");
17018         return(0);
17019     } else {                            /* Send protocol version */
17020         CHAR vers[4];
17021         memset (vers, 0, 4);
17022         vers[3] = SRP_PROT_VERSION;
17023         if (!quiet)
17024           printf ("SRP accepted as authentication type.\n");
17025         bp = tmp; blen = 0;
17026         srp_put (vers, &bp, 4, &blen);
17027         len = FTP_BUFSIZ;
17028         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17029           goto encode_error;
17030         reply_parse = "ADAT=";
17031         n = ftpcmd("ADAT",buf,-1,-1,0);
17032     }
17033     if (n == REPLY_CONTINUE) {          /* Get protocol version */
17034         bp = buf;
17035         if (!reply_parse)
17036           goto data_error;
17037         blen = FTP_BUFSIZ;
17038         if (e = radix_encode(reply_parse, bp, 0, &blen, RADIX_DECODE))
17039           goto decode_error;
17040         if (srp_get (&bp, &cp, &blen, &clen) != 4)
17041           goto data_error;
17042 
17043         if (host) {                     /* Get username/password if needed */
17044             srp_userpass (host);
17045         } else {
17046             ckstrncpy (srp_user, user, BUFSIZ);
17047             srp_pass = pass;
17048         }
17049         bp = tmp; blen = 0;             /* Send username */
17050         srp_put (srp_user, &bp, strlen (srp_user), &blen);
17051         len = FTP_BUFSIZ;
17052         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17053           goto encode_error;
17054         reply_parse = "ADAT=";
17055         n = ftpcmd("ADAT",buf,-1,-1,0);
17056     }
17057     if (n == REPLY_CONTINUE) {          /* Get N, g and s */
17058         bp = buf;
17059         if (!reply_parse)
17060           goto data_error;
17061         blen = FTP_BUFSIZ;
17062         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17063           goto decode_error;
17064         if (srp_get (&bp, &(N.data), &blen, &(N.len)) < 0)
17065           goto data_error;
17066         if (srp_get (&bp, &(g.data), &blen, &(g.len)) < 0)
17067           goto data_error;
17068         if (srp_get (&bp, &(s.data), &blen, &(s.len)) < 0)
17069           goto data_error;
17070         if ((tc = t_clientopen (srp_user, &N, &g, &s)) == NULL) {
17071             fprintf (stderr, "Unable to open SRP client structure.\n");
17072             goto bad;
17073         }
17074         wp = t_clientgenexp (tc);       /* Send wp */
17075         bp = tmp; blen = 0;
17076         srp_put (wp->data, &bp, wp->len, &blen);
17077         len = FTP_BUFSIZ;
17078         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17079           goto encode_error;
17080         reply_parse = "ADAT=";
17081         n = ftpcmd("ADAT",buf,-1,-1,0);
17082     }
17083     if (n == REPLY_CONTINUE) {          /* Get yp */
17084         bp = buf;
17085         if (!reply_parse)
17086           goto data_error;
17087         blen = FTP_BUFSIZ;
17088         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17089           goto decode_error;
17090         if (srp_get (&bp, &(yp.data), &blen, &(yp.len)) < 0)
17091           goto data_error;
17092         if (!srp_pass) {
17093             static char ftppass[PASSBUFSIZ];
17094             int ok;
17095             setint();
17096             ok = uq_txt(NULL," SRP Password: ",2,NULL,ftppass,PASSBUFSIZ,NULL,
17097                         DEFAULT_UQ_TIMEOUT);
17098             if (ok)
17099 	      srp_pass = brstrip(ftppass);
17100         }
17101         t_clientpasswd (tc, srp_pass);
17102         memset (srp_pass, 0, strlen (srp_pass));
17103         skey = t_clientgetkey (tc, &yp); /* Send response */
17104         bp = tmp; blen = 0;
17105         srp_put (t_clientresponse (tc), &bp, 20, &blen);
17106         len = FTP_BUFSIZ;
17107         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17108           goto encode_error;
17109         reply_parse = "ADAT=";
17110         n = ftpcmd("ADAT",buf,-1,-1,0);
17111     }
17112     if (n == REPLY_CONTINUE) {          /* Get response */
17113         bp = buf;
17114         if (!reply_parse)
17115           goto data_error;
17116         blen = FTP_BUFSIZ;
17117         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17118           goto encode_error;
17119         if (srp_get (&bp, &cp, &blen, &clen) != 20)
17120           goto data_error;
17121         if (t_clientverify (tc, cp)) {
17122             fprintf (stderr, "WARNING: bad response to client challenge.\n");
17123             goto bad;
17124         }
17125         bp = tmp; blen = 0;             /* Send nothing */
17126         srp_put ("\0", &bp, 1, &blen);
17127         len = FTP_BUFSIZ;
17128         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17129           goto encode_error;
17130         reply_parse = "ADAT=";
17131         n = ftpcmd("ADAT",buf,-1,-1,0);
17132     }
17133     if (n == REPLY_CONTINUE) {          /* Get cipher & hash lists, seqnum */
17134         CHAR seqnum[4];
17135         CHAR *clist;
17136         CHAR *hlist;
17137         CHAR *p1;
17138         int clist_len, hlist_len;
17139         bp = buf;
17140         if (!reply_parse)
17141           goto data_error;
17142         blen = FTP_BUFSIZ;
17143         if (e = radix_encode (reply_parse, bp, 0, &blen, RADIX_DECODE))
17144           goto encode_error;
17145         if (srp_get (&bp, &clist, &blen, &clist_len) < 0)
17146           goto data_error;
17147         if (srp_get (&bp, &hlist, &blen, &hlist_len) < 0)
17148           goto data_error;
17149         if (srp_get (&bp, &cp, &blen, &clen) != 4)
17150           goto data_error;
17151         memcpy (seqnum, cp, 4);
17152         if (cipher_supported (clist, srp_pref_cipher)) /* Choose cipher */
17153           cid = srp_pref_cipher;
17154         if (!cid && cipher_supported (clist, SRP_DEFAULT_CIPHER))
17155           cid = SRP_DEFAULT_CIPHER;
17156         if (!cid) {
17157             CHAR *loclist = cipher_getlist ();
17158             for (i = 0; i < strlen (loclist); i++)
17159               if (cipher_supported (clist, loclist[i])) {
17160                   cid = loclist[i];
17161                   break;
17162               }
17163         }
17164         if (!cid) {
17165             fprintf (stderr, "Unable to agree on cipher.\n");
17166             goto bad;
17167         }
17168         /* Choose hash */
17169 
17170         if (srp_pref_hash && hash_supported (hlist, srp_pref_hash))
17171           hid = srp_pref_hash;
17172 
17173         if (!hid && hash_supported (hlist, SRP_DEFAULT_HASH))
17174           hid = SRP_DEFAULT_HASH;
17175 
17176         if (!hid) {
17177             CHAR *loclist = hash_getlist ();
17178             for (i = 0; i < strlen (loclist); i++)
17179               if (hash_supported (hlist, loclist[i])) {
17180                   hid = loclist[i];
17181                   break;
17182               }
17183         }
17184         if (!hid) {
17185             fprintf (stderr, "Unable to agree on hash.\n");
17186             goto bad;
17187         }
17188         /* Set incrypt */
17189 
17190         if (!(incrypt = krypto_new (cid, hid, skey, 20, NULL, 0, seqnum,
17191                                     KRYPTO_DECODE)))
17192           goto bad;
17193 
17194         /* Generate random number for outkey and outseqnum */
17195 
17196         t_random (seqnum, 4);
17197 
17198         /* Send cid, hid, outkey, outseqnum */
17199 
17200         bp = tmp; blen = 0;
17201         srp_put (&cid, &bp, 1, &blen);
17202         srp_put (&hid, &bp, 1, &blen);
17203         srp_put (seqnum, &bp, 4, &blen);
17204         len = FTP_BUFSIZ;
17205         if (e = radix_encode (tmp, buf, blen, &len, RADIX_ENCODE))
17206           goto encode_error;
17207         reply_parse = "ADAT=";
17208         n = ftpcmd("ADAT",buf,-1,-1,0);
17209 
17210         /* Set outcrypt */
17211 
17212         if (!(outcrypt = krypto_new (cid, hid, skey+20, 20, NULL, 0, seqnum,
17213                                      KRYPTO_ENCODE)))
17214           goto bad;
17215 
17216         t_clientclose (tc);
17217         tc = NULL;
17218     }
17219     if (n != REPLY_COMPLETE)
17220       goto bad;
17221 
17222     if (ftp_vbm) {
17223         if (ftp_deb)
17224           printf("\n");
17225         printf ("SRP authentication succeeded.\n");
17226         printf ("Using cipher %s and hash function %s.\n",
17227                 (cipher_getdescbyid(cid))->name,
17228                 (hash_getdescbyid(hid))->name
17229                 );
17230     }
17231     reply_parse = NULL;
17232     auth_type = "SRP";
17233     return(1);
17234 
17235   encode_error:
17236     fprintf (stderr, "Base 64 encoding failed: %s.\n", radix_error (e));
17237     goto bad;
17238 
17239   decode_error:
17240     fprintf (stderr, "Base 64 decoding failed: %s.\n", radix_error (e));
17241     goto bad;
17242 
17243   data_error:
17244     fprintf (stderr, "Unable to unmarshal authentication data.\n");
17245     goto bad;
17246 
17247   bad:
17248     fprintf (stderr, "SRP authentication failed, trying regular login.\n");
17249     reply_parse = NULL;
17250     return(0);
17251 }
17252 
17253 /*--------------------------------------------------------------+
17254  | srp_put: put item to send buffer                             |
17255  +--------------------------------------------------------------*/
17256 static int
srp_put(in,out,inlen,outlen)17257 srp_put (in, out, inlen, outlen)
17258     CHAR *in;
17259     CHAR **out;
17260     int inlen;
17261     int *outlen;
17262 {
17263     srp_uint32 net_len;
17264 
17265     net_len = htonl (inlen);
17266     memcpy (*out, &net_len, 4);
17267 
17268     *out += 4; *outlen += 4;
17269 
17270     memcpy (*out, in, inlen);
17271 
17272     *out += inlen; *outlen += inlen;
17273     return(0);
17274 }
17275 
17276 /*--------------------------------------------------------------+
17277  | srp_get: get item from receive buffer                        |
17278  +--------------------------------------------------------------*/
17279 static int
srp_get(in,out,inlen,outlen)17280 srp_get (in, out, inlen, outlen)
17281     CHAR **in;
17282     CHAR **out;
17283     int *inlen;
17284     int *outlen;
17285 {
17286     srp_uint32 net_len;
17287 
17288     if (*inlen < 4) return -1;
17289 
17290     memcpy (&net_len, *in, 4); *inlen -= 4; *in += 4;
17291     *outlen = ntohl (net_len);
17292 
17293     if (*inlen < *outlen) return -1;
17294 
17295     *out = *in; *inlen -= *outlen; *in += *outlen;
17296 
17297     return *outlen;
17298 }
17299 
17300 /*--------------------------------------------------------------+
17301  | srp_encode: encode control message                           |
17302  +--------------------------------------------------------------*/
17303 static int
srp_encode(private,in,out,len)17304 srp_encode (private, in, out, len)
17305     int private;
17306     CHAR *in;
17307     CHAR *out;
17308     unsigned len;
17309 {
17310     if (private)
17311       return krypto_msg_priv (outcrypt, in, out, len);
17312     else
17313       return krypto_msg_safe (outcrypt, in, out, len);
17314 }
17315 
17316 /*--------------------------------------------------------------+
17317  | srp_decode: decode control message                           |
17318  +--------------------------------------------------------------*/
17319 static int
srp_decode(private,in,out,len)17320 srp_decode (private, in, out, len)
17321     int private;
17322     CHAR *in;
17323     CHAR *out;
17324     unsigned len;
17325 {
17326     if (private)
17327       return krypto_msg_priv (incrypt, in, out, len);
17328     else
17329       return krypto_msg_safe (incrypt, in, out, len);
17330 }
17331 
17332 #endif /* FTP_SRP */
17333 
17334 
17335 
17336 #ifdef NOT_USED
17337 /*
17338   The following code is from the Unix FTP client.  Be sure to
17339   make sure that the functionality is not lost.  Especially
17340   the Proxy stuff even though we have not yet implemented it.
17341 */
17342 
17343 /* Send multiple files  */
17344 
17345 static int
ftp_mput(argc,argv)17346 ftp_mput(argc, argv) int argc; char **argv; {
17347     register int i;
17348     sig_t oldintr;
17349     int ointer;
17350     char *tp;
17351     sigtype mcancel();
17352 
17353     if (argc < 2 && !another(&argc, &argv, "local-files")) {
17354         printf("usage: %s local-files\n", argv[0]);
17355         ftpcode = -1;
17356         return;
17357     }
17358     mname = argv[0];
17359     mflag = 1;
17360     oldintr = signal(SIGINT, mcancel);
17361 
17362     /* Replace with calls to cc_execute() */
17363     setjmp(jcancel);
17364 #ifdef FTP_PROXY
17365     if (proxy) {
17366         char *cp, *tp2, tmpbuf[CKMAXPATH];
17367 
17368         while ((cp = remglob(argv,0)) != NULL) {
17369             if (*cp == 0) {
17370                 mflag = 0;
17371                 continue;
17372             }
17373             if (mflag && confirm(argv[0], cp)) {
17374                 tp = cp;
17375                 if (mcase) {
17376                     while (*tp && !islower(*tp)) {
17377                         tp++;
17378                     }
17379                     if (!*tp) {
17380                         tp = cp;
17381                         tp2 = tmpbuf;
17382                         while ((*tp2 = *tp) != 0) {
17383                             if (isupper(*tp2)) {
17384                                 *tp2 = 'a' + *tp2 - 'A';
17385                             }
17386                             tp++;
17387                             tp2++;
17388                         }
17389                     }
17390                     tp = tmpbuf;
17391                 }
17392                 if (ntflag) {
17393                     tp = dotrans(tp);
17394                 }
17395                 if (mapflag) {
17396                     tp = domap(tp);
17397                 }
17398                 sendrequest((sunique) ? "STOU" : "STOR", cp, tp, 0, -1, -1, 0);
17399                 if (!mflag && fromatty) {
17400                     ointer = interactive;
17401                     interactive = 1;
17402                     if (confirm("Continue with","mput")) {
17403                         mflag++;
17404                     }
17405                     interactive = ointer;
17406                 }
17407             }
17408         }
17409         signal(SIGINT, oldintr);
17410         mflag = 0;
17411         return;
17412     }
17413 #endif /* FTP_PROXY */
17414     for (i = 1; i < argc; i++) {
17415         register char **cpp, **gargs;
17416 
17417         if (mflag && confirm(argv[0], argv[i])) {
17418             tp = argv[i];
17419             sendrequest((ftp_usn) ? "STOU" : "STOR", argv[i], tp, 0,-1,-1, 0);
17420             if (!mflag && fromatty) {
17421                 ointer = interactive;
17422                 interactive = 1;
17423                 if (confirm("Continue with","mput")) {
17424                     mflag++;
17425                 }
17426                 interactive = ointer;
17427             }
17428         }
17429         continue;
17430 
17431         gargs = ftpglob(argv[i]);
17432         if (globerr != NULL) {
17433             printf("%s\n", globerr);
17434             if (gargs) {
17435                 blkfree(gargs);
17436                 free((char *)gargs);
17437             }
17438             continue;
17439         }
17440         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
17441             if (mflag && confirm(argv[0], *cpp)) {
17442                 tp = *cpp;
17443                 sendrequest((sunique) ? "STOU":"STOR", *cpp, tp, 0, -1, -1, 0);
17444                 if (!mflag && fromatty) {
17445                     ointer = interactive;
17446                     interactive = 1;
17447                     if (confirm("Continue with","mput")) {
17448                         mflag++;
17449                     }
17450                     interactive = ointer;
17451                 }
17452             }
17453         }
17454         if (gargs != NULL) {
17455             blkfree(gargs);
17456             free((char *)gargs);
17457         }
17458     }
17459     signal(SIGINT, oldintr);
17460     mflag = 0;
17461 }
17462 
17463 /* Get multiple files */
17464 
17465 static int
ftp_mget(argc,argv)17466 ftp_mget(argc, argv) int argc; char **argv; {
17467     int rc = -1;
17468     sig_t oldintr;
17469     int ointer;
17470     char *cp, *tp, *tp2, tmpbuf[CKMAXPATH];
17471     sigtype mcancel();
17472 
17473     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17474         printf("usage: %s remote-files\n", argv[0]);
17475         ftpcode = -1;
17476         return(-1);
17477     }
17478     mname = argv[0];
17479     mflag = 1;
17480     oldintr = signal(SIGINT,mcancel);
17481     /* Replace with calls to cc_execute() */
17482     setjmp(jcancel);
17483     while ((cp = remglob(argv,proxy)) != NULL) {
17484         if (*cp == '\0') {
17485             mflag = 0;
17486             continue;
17487         }
17488         if (mflag && confirm(argv[0], cp)) {
17489             tp = cp;
17490             if (mcase) {
17491                 while (*tp && !islower(*tp)) {
17492                     tp++;
17493                 }
17494                 if (!*tp) {
17495                     tp = cp;
17496                     tp2 = tmpbuf;
17497                     while ((*tp2 = *tp) != 0) {
17498                         if (isupper(*tp2)) {
17499                             *tp2 = 'a' + *tp2 - 'A';
17500                         }
17501                         tp++;
17502                         tp2++;
17503                     }
17504                 }
17505                 tp = tmpbuf;
17506             }
17507             rc = (recvrequest("RETR", tp, cp, "wb",
17508                                tp != cp || !interactive) == 0,0,NULL,0,0,0);
17509             if (!mflag && fromatty) {
17510                 ointer = interactive;
17511                 interactive = 1;
17512                 if (confirm("Continue with","mget")) {
17513                     mflag++;
17514                 }
17515                 interactive = ointer;
17516             }
17517         }
17518     }
17519     signal(SIGINT,oldintr);
17520     mflag = 0;
17521     return(rc);
17522 }
17523 
17524 /* Delete multiple files */
17525 
17526 static int
mdelete(argc,argv)17527 mdelete(argc, argv) int argc; char **argv; {
17528     sig_t oldintr;
17529     int ointer;
17530     char *cp;
17531     sigtype mcancel();
17532 
17533     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
17534         printf("usage: %s remote-files\n", argv[0]);
17535         ftpcode = -1;
17536         return(-1);
17537     }
17538     mname = argv[0];
17539     mflag = 1;
17540     oldintr = signal(SIGINT, mcancel);
17541     /* Replace with calls to cc_execute() */
17542     setjmp(jcancel);
17543     while ((cp = remglob(argv,0)) != NULL) {
17544         if (*cp == '\0') {
17545             mflag = 0;
17546             continue;
17547         }
17548         if (mflag && confirm(argv[0], cp)) {
17549             rc = (ftpcmd("DELE",cp,-1,-1,ftp_vbm) == REPLY_COMPLETE);
17550             if (!mflag && fromatty) {
17551                 ointer = interactive;
17552                 interactive = 1;
17553                 if (confirm("Continue with", "mdelete")) {
17554                     mflag++;
17555                 }
17556                 interactive = ointer;
17557             }
17558         }
17559     }
17560     signal(SIGINT, oldintr);
17561     mflag = 0;
17562     return(rc);
17563 }
17564 
17565 /* Get a directory listing of multiple remote files */
17566 
17567 static int
mls(argc,argv)17568 mls(argc, argv) int argc; char **argv; {
17569     sig_t oldintr;
17570     int ointer, i;
17571     char *cmd, mode[1], *dest;
17572     sigtype mcancel();
17573     int rc = -1;
17574 
17575     if (argc < 2 && !another(&argc, &argv, "remote-files"))
17576       goto usage;
17577     if (argc < 3 && !another(&argc, &argv, "local-file")) {
17578       usage:
17579         printf("usage: %s remote-files local-file\n", argv[0]);
17580         ftpcode = -1;
17581         return(-1);
17582     }
17583     dest = argv[argc - 1];
17584     argv[argc - 1] = NULL;
17585     if (strcmp(dest, "-") && *dest != '|')
17586       if (!globulize(&dest) ||
17587           !confirm("output to local-file:", dest)) {
17588           ftpcode = -1;
17589           return(-1);
17590       }
17591     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
17592     mname = argv[0];
17593     mflag = 1;
17594     oldintr = signal(SIGINT, mcancel);
17595     /* Replace with calls to cc_execute() */
17596     setjmp(jcancel);
17597     for (i = 1; mflag && i < argc-1; ++i) {
17598         *mode = (i == 1) ? 'w' : 'a';
17599         rc = recvrequest(cmd, dest, argv[i], mode, 0,0,NULL,0,0,0);
17600         if (!mflag && fromatty) {
17601             ointer = interactive;
17602             interactive = 1;
17603             if (confirm("Continue with", argv[0])) {
17604                 mflag ++;
17605             }
17606             interactive = ointer;
17607         }
17608     }
17609     signal(SIGINT, oldintr);
17610     mflag = 0;
17611     return(rc);
17612 }
17613 
17614 static char *
remglob(argv,doswitch)17615 remglob(argv,doswitch) char *argv[]; int doswitch; {
17616     char temp[16];
17617     static char buf[CKMAXPATH];
17618     static FILE *ftemp = NULL;
17619     static char **args;
17620     int oldhash;
17621     char *cp, *mode;
17622 
17623     if (!mflag) {
17624         if (!doglob) {
17625             args = NULL;
17626         } else {
17627             if (ftemp) {
17628                 (void) fclose(ftemp);
17629                 ftemp = NULL;
17630             }
17631         }
17632         return(NULL);
17633     }
17634     if (!doglob) {
17635         if (args == NULL)
17636           args = argv;
17637         if ((cp = *++args) == NULL)
17638           args = NULL;
17639         return(cp);
17640     }
17641     if (ftemp == NULL) {
17642         (void) strcpy(temp, _PATH_TMP);
17643 #ifdef MKTEMP
17644 #ifndef MKSTEMP
17645         (void) mktemp(temp);
17646 #endif /* MKSTEMP */
17647 #endif /* MKTEMP */
17648         verbose = 0;
17649         oldhash = hash, hash = 0;
17650 #ifdef FTP_PROXY
17651         if (doswitch) {
17652             pswitch(!proxy);
17653         }
17654 #endif /* FTP_PROXY */
17655         for (mode = "wb"; *++argv != NULL; mode = "ab")
17656           recvrequest ("NLST", temp, *argv, mode, 0);
17657 #ifdef FTP_PROXY
17658         if (doswitch) {
17659             pswitch(!proxy);
17660         }
17661 #endif /* FTP_PROXY */
17662         hash = oldhash;
17663         ftemp = fopen(temp, "r");
17664         unlink(temp);
17665         if (ftemp == NULL && (!dpyactive || ftp_deb)) {
17666             printf("Can't find list of remote files, oops\n");
17667             return(NULL);
17668         }
17669     }
17670     if (fgets(buf, CKMAXPATH, ftemp) == NULL) {
17671         fclose(ftemp), ftemp = NULL;
17672         return(NULL);
17673     }
17674     if ((cp = ckstrchr(buf,'\n')) != NULL)
17675       *cp = '\0';
17676     return(buf);
17677 }
17678 #endif /* NOT_USED */
17679 #endif /* TCPSOCKET (top of file) */
17680 #endif /* SYSFTP (top of file) */
17681 #endif /* NOFTP (top of file) */
17682