openenvutils/commandshell/shell/src/modules/zftp.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 //
       
     2 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     3 //
       
     4 /*
       
     5  * zftp.c - builtin FTP client
       
     6  *
       
     7  * This file is part of zsh, the Z shell.
       
     8  *
       
     9  * Copyright (c) 1998 Peter Stephenson
       
    10  * All rights reserved.
       
    11  *
       
    12  * Permission is hereby granted, without written agreement and without
       
    13  * license or royalty fees, to use, copy, modify, and distribute this
       
    14  * software and to distribute modified versions of this software for any
       
    15  * purpose, provided that the above copyright notice and the following
       
    16  * two paragraphs appear in all copies of this software.
       
    17  *
       
    18  * In no event shall Peter Stephenson or the Zsh Development Group be liable
       
    19  * to any party for direct, indirect, special, incidental, or consequential
       
    20  * damages arising out of the use of this software and its documentation,
       
    21  * even if Peter Stephenson and the Zsh Development Group have been advised of
       
    22  * the possibility of such damage.
       
    23  *
       
    24  * Peter Stephenson and the Zsh Development Group specifically disclaim any
       
    25  * warranties, including, but not limited to, the implied warranties of
       
    26  * merchantability and fitness for a particular purpose.  The software
       
    27  * provided hereunder is on an "as is" basis, and Peter Stephenson and the
       
    28  * Zsh Development Group have no obligation to provide maintenance,
       
    29  * support, updates, enhancements, or modifications.
       
    30  *
       
    31  */
       
    32 
       
    33 /*
       
    34  * TODO:
       
    35  *   should be eight-bit clean, but isn't.
       
    36  *   tracking of logical rather than physical directories, like nochaselinks
       
    37  *     (usually PWD returns physical directory).
       
    38  *   can signal handling be improved?
       
    39  *   maybe we should block CTRL-c on some more operations,
       
    40  *     otherwise you can get the connection closed prematurely.
       
    41  *   some way of turning off progress reports when backgrounded
       
    42  *     would be nice, but the shell doesn't make it easy to find that out.
       
    43  *   proxy/gateway connections if i knew what to do
       
    44  *   options to specify e.g. a non-standard port
       
    45  */
       
    46 
       
    47 /* needed in prototypes for statics */
       
    48 
       
    49 struct hostent;
       
    50 struct in_addr;
       
    51 struct sockaddr_in;
       
    52 struct sockaddr_in6;
       
    53 struct zftp_session;
       
    54 typedef struct zftp_session *Zftp_session;
       
    55 
       
    56 #include "tcp.h"
       
    57 #include "zftp.mdh"
       
    58 #include "zftp.pro"
       
    59 
       
    60 /* it's a TELNET based protocol, but don't think I like doing this */
       
    61 #ifndef __SYMBIAN32__
       
    62 #include <arpa/telnet.h>
       
    63 #else
       
    64 #include "telnet.h"
       
    65 #include "dummy.h"
       
    66 #endif //__SYMBIAN32__
       
    67 
       
    68 /*
       
    69  * We use poll() in preference to select because some subset of manuals says
       
    70  * that's the thing to do, plus it's a bit less fiddly.  I don't actually
       
    71  * have access to a system with poll but not select, however, though
       
    72  * both bits of the code have been tested on a machine with both.
       
    73  */
       
    74 #ifdef HAVE_POLL_H
       
    75 #ifndef __SYMBIAN32__
       
    76 # include <sys/poll.h>
       
    77 #else
       
    78 # include "poll.h"
       
    79 #endif
       
    80 #endif
       
    81 #if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM)
       
    82 # undef HAVE_POLL
       
    83 #endif
       
    84 
       
    85 #ifdef __SYMBIAN32__
       
    86 #ifdef __WINSCW__
       
    87 #pragma warn_unusedarg off
       
    88 #endif//__WINSCW__
       
    89 #endif//__SYMBIAN32__
       
    90 
       
    91 #ifdef USE_LOCAL_H_ERRNO
       
    92 int h_errno;
       
    93 #endif
       
    94 
       
    95 union zftp_sockaddr {
       
    96     struct sockaddr a;
       
    97     struct sockaddr_in in;
       
    98 #ifdef SUPPORT_IPV6
       
    99     struct sockaddr_in6 in6;
       
   100 #endif
       
   101 };
       
   102 
       
   103 #ifdef USE_LOCAL_H_ERRNO
       
   104 int h_errno;
       
   105 #endif
       
   106 
       
   107 /*
       
   108  * For FTP block mode
       
   109  *
       
   110  * The server on our AIX machine here happily accepts block mode, takes the
       
   111  * first connection, then at the second complains that it's got nowhere
       
   112  * to send data.  The same problem happens with ncftp, it's not just
       
   113  * me.  And a lot of servers don't even support block mode. So I'm not sure
       
   114  * how widespread the supposed ability to leave open the data fd between
       
   115  * transfers.  Therefore, I've closed all connections after the transfer.
       
   116  * But then what's the point in block mode?  I only implemented it because
       
   117  * it says in RFC959 that you need it to be able to restart transfers
       
   118  * later in the file.  However, it turns out that's not true for
       
   119  * most servers --- but our AIX machine happily accepts the REST
       
   120  * command and then dumps the whole file onto you.  Sigh.
       
   121  *
       
   122  * Note on block sizes:
       
   123  * Not quite sure how to optimize this:  in principle
       
   124  * we should handle blocks up to 65535 bytes, which
       
   125  * is pretty big, and should presumably send blocks
       
   126  * which are smaller to be on the safe side.
       
   127  * Currently we send 32768 and use that also as
       
   128  * the maximum to receive.  No-one's complained yet.  Of course,
       
   129  * no-one's *used* it yet apart from me, but even so.
       
   130  */
       
   131 
       
   132 struct zfheader {
       
   133     char flags;
       
   134     unsigned char bytes[2];
       
   135 };
       
   136 
       
   137 enum {
       
   138     ZFHD_MARK = 16,		/* restart marker */
       
   139     ZFHD_ERRS = 32,		/* suspected errors in block */
       
   140     ZFHD_EOFB = 64,		/* block is end of record */
       
   141     ZFHD_EORB = 128		/* block is end of file */
       
   142 };
       
   143 
       
   144 typedef int (*readwrite_t)(int, char *, off_t, int);
       
   145 
       
   146 struct zftpcmd {
       
   147     const char *nam;
       
   148     int (*fun) _((char *, char **, int));
       
   149     int min, max, flags;
       
   150 };
       
   151 
       
   152 enum {
       
   153     ZFTP_CONN  = 0x0001,	/* must be connected */
       
   154     ZFTP_LOGI  = 0x0002,	/* must be logged in */
       
   155     ZFTP_TBIN  = 0x0004,	/* set transfer type image */
       
   156     ZFTP_TASC  = 0x0008,	/* set transfer type ASCII */
       
   157     ZFTP_NLST  = 0x0010,	/* use NLST rather than LIST */
       
   158     ZFTP_DELE  = 0x0020,	/* a delete rather than a make */
       
   159     ZFTP_SITE  = 0x0040,	/* a site rather than a quote */
       
   160     ZFTP_APPE  = 0x0080,	/* append rather than overwrite */
       
   161     ZFTP_HERE  = 0x0100,	/* here rather than over there */
       
   162     ZFTP_CDUP  = 0x0200,	/* CDUP rather than CWD */
       
   163     ZFTP_REST  = 0x0400,	/* restart: set point in remote file */
       
   164     ZFTP_RECV  = 0x0800,	/* receive rather than send */
       
   165     ZFTP_TEST  = 0x1000,	/* test command, don't test */
       
   166     ZFTP_SESS  = 0x2000		/* session command, don't need status */
       
   167 };
       
   168 
       
   169 typedef struct zftpcmd *Zftpcmd;
       
   170 
       
   171 static struct zftpcmd zftpcmdtab[] = {
       
   172     { "open", zftp_open, 0, 4, 0 },
       
   173     { "params", zftp_params, 0, 4, 0 },
       
   174     { "login", zftp_login, 0, 3, ZFTP_CONN },
       
   175     { "user", zftp_login, 0, 3, ZFTP_CONN },
       
   176     { "test", zftp_test, 0, 0, ZFTP_TEST },
       
   177     { "cd", zftp_cd, 1, 1, ZFTP_CONN|ZFTP_LOGI },
       
   178     { "cdup", zftp_cd, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_CDUP },
       
   179     { "dir", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI },
       
   180     { "ls", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_NLST },
       
   181     { "type", zftp_type, 0, 1, ZFTP_CONN|ZFTP_LOGI },
       
   182     { "ascii", zftp_type, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_TASC },
       
   183     { "binary", zftp_type, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_TBIN },
       
   184     { "mode", zftp_mode, 0, 1, ZFTP_CONN|ZFTP_LOGI },
       
   185     { "local", zftp_local, 0, -1, ZFTP_HERE },
       
   186     { "remote", zftp_local, 1, -1, ZFTP_CONN|ZFTP_LOGI },
       
   187     { "get", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_RECV },
       
   188     { "getat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_RECV|ZFTP_REST },
       
   189     { "put", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI },
       
   190     { "putat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_REST },
       
   191     { "append", zftp_getput, 1, -1, ZFTP_CONN|ZFTP_LOGI|ZFTP_APPE },
       
   192     { "appendat", zftp_getput, 2, 2, ZFTP_CONN|ZFTP_LOGI|ZFTP_APPE|ZFTP_REST },
       
   193     { "delete", zftp_delete, 1, -1, ZFTP_CONN|ZFTP_LOGI },
       
   194     { "mkdir", zftp_mkdir, 1, 1, ZFTP_CONN|ZFTP_LOGI },
       
   195     { "rmdir", zftp_mkdir, 1, 1, ZFTP_CONN|ZFTP_LOGI|ZFTP_DELE },
       
   196     { "rename", zftp_rename, 2, 2, ZFTP_CONN|ZFTP_LOGI },
       
   197     { "quote", zftp_quote, 1, -1, ZFTP_CONN },
       
   198     { "site", zftp_quote, 1, -1, ZFTP_CONN|ZFTP_SITE },
       
   199     { "close", zftp_close, 0, 0, ZFTP_CONN },
       
   200     { "quit", zftp_close, 0, 0, ZFTP_CONN },
       
   201     { "session", zftp_session, 0, 1, ZFTP_SESS },
       
   202     { "rmsession", zftp_rmsession, 0, 1, ZFTP_SESS },
       
   203     { 0, 0, 0, 0, 0 }
       
   204 };
       
   205 
       
   206 static struct builtin bintab[] = {
       
   207     BUILTIN("zftp", 0, bin_zftp, 1, -1, 0, NULL, NULL),
       
   208 };
       
   209 
       
   210 /*
       
   211  * these are the non-special params to unset when a connection
       
   212  * closes.  any special params are handled, well, specially.
       
   213  * currently there aren't any, which is the way I like it.
       
   214  */
       
   215 static char *zfparams[] = {
       
   216     "ZFTP_HOST", "ZFTP_PORT", "ZFTP_IP", "ZFTP_SYSTEM", "ZFTP_USER",
       
   217     "ZFTP_ACCOUNT", "ZFTP_PWD", "ZFTP_TYPE", "ZFTP_MODE", NULL
       
   218 };
       
   219 
       
   220 /* flags for zfsetparam */
       
   221 
       
   222 enum {
       
   223     ZFPM_READONLY = 0x01,	/* make parameter readonly */
       
   224     ZFPM_IFUNSET  = 0x02,	/* only set if not already set */
       
   225     ZFPM_INTEGER  = 0x04	/* passed pointer to off_t */
       
   226 };
       
   227 
       
   228 /* Number of connections actually open */
       
   229 static int zfnopen;
       
   230 
       
   231 /*
       
   232  * zcfinish = 0 keep going
       
   233  *            1 line finished, alles klar
       
   234  *            2 EOF
       
   235  */
       
   236 static int zcfinish;
       
   237 /* zfclosing is set if zftp_close() is active */
       
   238 static int zfclosing;
       
   239 
       
   240 /*
       
   241  * Stuff about last message:  last line of message and status code.
       
   242  * The reply is also stored in $ZFTP_REPLY; we keep these separate
       
   243  * for convenience.
       
   244  */
       
   245 static char *lastmsg, lastcodestr[4];
       
   246 static int lastcode;
       
   247 
       
   248 /* remote system has size, mdtm commands */
       
   249 enum {
       
   250     ZFCP_UNKN = 0,		/* dunno if it works on this server */
       
   251     ZFCP_YUPP = 1,		/* it does */
       
   252     ZFCP_NOPE = 2		/* it doesn't */
       
   253 };
       
   254 
       
   255 /*
       
   256  * We keep an fd open for communication between the main shell
       
   257  * and forked off bits and pieces.  This allows us to know
       
   258  * if something happend in a subshell:  mode changed, type changed,
       
   259  * connection was closed.  If something too substantial happened
       
   260  * in a subshell --- connection opened, ZFTP_USER and ZFTP_PWD changed
       
   261  * --- we don't try to track it because it's too complicated.
       
   262  */
       
   263 enum {
       
   264     ZFST_ASCI = 0x0000,		/* type for next transfer is ASCII */
       
   265     ZFST_IMAG = 0x0001,		/* type for next transfer is image */
       
   266 
       
   267     ZFST_TMSK = 0x0001,		/* mask for type flags */
       
   268     ZFST_TBIT = 0x0001,		/* number of bits in type flags */
       
   269 
       
   270     ZFST_CASC = 0x0000,		/* current type is ASCII - default */
       
   271     ZFST_CIMA = 0x0002,		/* current type is image */
       
   272 
       
   273     ZFST_STRE = 0x0000,		/* stream mode - default */
       
   274     ZFST_BLOC = 0x0004,		/* block mode */
       
   275 
       
   276     ZFST_MMSK = 0x0004,		/* mask for mode flags */
       
   277 
       
   278     ZFST_LOGI = 0x0008,		/* user logged in */
       
   279     ZFST_SYST = 0x0010,		/* done system type check */
       
   280     ZFST_NOPS = 0x0020,		/* server doesn't understand PASV */
       
   281     ZFST_NOSZ = 0x0040,		/* server doesn't send `(XXXX bytes)' reply */
       
   282     ZFST_TRSZ = 0x0080,		/* tried getting 'size' from reply */
       
   283     ZFST_CLOS = 0x0100		/* connection closed */
       
   284 };
       
   285 #define ZFST_TYPE(x) (x & ZFST_TMSK)
       
   286 /*
       
   287  * shift current type flags to match type flags: should be by
       
   288  * the number of bits in the type flags
       
   289  */
       
   290 #define ZFST_CTYP(x) ((x >> ZFST_TBIT) & ZFST_TMSK)
       
   291 #define ZFST_MODE(x) (x & ZFST_MMSK)
       
   292 
       
   293 /* fd containing status for all sessions and array for internal use */
       
   294 static int zfstatfd = -1, *zfstatusp;
       
   295 
       
   296 /* Preferences, read in from the `zftp_prefs' array variable */
       
   297 enum {
       
   298     ZFPF_SNDP = 0x01,		/* Use send port mode */
       
   299     ZFPF_PASV = 0x02,		/* Try using passive mode */
       
   300     ZFPF_DUMB = 0x04		/* Don't do clever things with variables */
       
   301 };
       
   302 
       
   303 /* The flags as stored internally. */
       
   304 static int zfprefs;
       
   305 
       
   306 /*
       
   307  * Data node for linked list of sessions.
       
   308  *
       
   309  * Memory management notes:
       
   310  *   name is permanently allocated and remains for the life of the node.
       
   311  *   userparams is set directly by zftp_params and also freed with the node.
       
   312  *   params and its data are allocated when we need
       
   313  *     to save an existing session, and are freed when we switch back
       
   314  *     to that session.
       
   315  *   The node itself is deleted when we remove it from the list.
       
   316  */
       
   317 struct zftp_session {
       
   318     char *name;			/* name of session */
       
   319     char **params;		/* parameters ordered as in zfparams */
       
   320     char **userparams;		/* user parameters set by zftp_params */
       
   321     FILE *cin;			/* control input file */
       
   322     Tcp_session control;	/* the control connection */
       
   323     int dfd;			/* data connection */
       
   324     int has_size;		/* understands SIZE? */
       
   325     int has_mdtm;		/* understands MDTM? */
       
   326 };
       
   327 
       
   328 /* List of active sessions */
       
   329 static LinkList zfsessions;
       
   330 
       
   331 /* Current session */
       
   332 static Zftp_session zfsess;
       
   333 
       
   334 /* Number of current session, corresponding to position in list */
       
   335 static int zfsessno;
       
   336 
       
   337 /* Total number of sessions */
       
   338 static int zfsesscnt;
       
   339 
       
   340 /*
       
   341  * Bits and pieces for dealing with SIGALRM (and SIGPIPE, but that's
       
   342  * easier).  The complication is that SIGALRM may already be handled
       
   343  * by the user setting TMOUT and possibly setting their own trap --- in
       
   344  * fact, it's always handled by the shell when it's interactive.  It's
       
   345  * too difficult to use zsh's own signal handler --- either it would
       
   346  * need rewriting to use a C function as a trap, or we would need a
       
   347  * hack to make it callback via a hidden builtin from a function --- so
       
   348  * just install our own, and use settrap() to restore the behaviour
       
   349  * afterwards if necessary.  However, the more that could be done by
       
   350  * the main shell code, the better I would like it.
       
   351  *
       
   352  * Since we don't want to go through the palaver of changing between
       
   353  * the main zsh signal handler and ours every time we start or stop the
       
   354  * alarm, we keep the flag zfalarmed set to 1 while zftp is rigged to
       
   355  * handle alarms.  This is tested at the end of bin_zftp(), which is
       
   356  * the entry point for all functions, and that restores the original
       
   357  * handler for SIGALRM.  To turn off the alarm temporarily in the zftp
       
   358  * code we then just call alarm(0).
       
   359  *
       
   360  * If we could rely on having select() or some replacement, we would
       
   361  * only need the alarm during zftp_open().
       
   362  */
       
   363 
       
   364 /* flags for alarm set, alarm gone off */
       
   365 int zfalarmed, zfdrrrring;
       
   366 /* remember old alarm status */
       
   367 time_t oaltime;
       
   368 unsigned int oalremain;
       
   369 
       
   370 /*
       
   371  * Where to jump to when the alarm goes off.  This is much
       
   372  * easier than fiddling with error flags at every turn.
       
   373  * Since we don't expect too many alarm's, the simple setjmp()
       
   374  * mechanism should be good enough.
       
   375  *
       
   376  * gcc -O gives apparently spurious `may be clobbered by longjmp' warnings.
       
   377  */
       
   378 jmp_buf zfalrmbuf;
       
   379 
       
   380 /* The signal handler itself */
       
   381 
       
   382 /**/
       
   383 static RETSIGTYPE
       
   384 zfhandler(int sig)
       
   385 {
       
   386     if (sig == SIGALRM) {
       
   387 	zfdrrrring = 1;
       
   388 #ifdef ETIMEDOUT		/* just in case */
       
   389 	errno = ETIMEDOUT;
       
   390 #else
       
   391 	errno = EIO;
       
   392 #endif
       
   393 	longjmp(zfalrmbuf, 1);
       
   394     }
       
   395     DPUTS(1, "zfhandler caught incorrect signal");
       
   396 }
       
   397 
       
   398 /* Set up for an alarm call */
       
   399 
       
   400 /**/
       
   401 static void
       
   402 zfalarm(int tmout)
       
   403 {
       
   404     zfdrrrring = 0;
       
   405     /*
       
   406      * We need to do this even if tmout is zero, since there may
       
   407      * be a non-zero timeout set in the main shell which we don't
       
   408      * want to go off.  This could be argued the other way, since
       
   409      * if we don't get that it's probably harmless.  But this looks safer.
       
   410      */
       
   411     if (zfalarmed) {
       
   412 	alarm(tmout);
       
   413 	return;
       
   414     }
       
   415 #ifndef __SYMBIAN32__    
       
   416     signal(SIGALRM, zfhandler); 
       
   417 #endif    
       
   418     oalremain = alarm(tmout);
       
   419     if (oalremain)
       
   420 	oaltime = time(NULL);
       
   421     /*
       
   422      * We'll leave sigtrapped, sigfuncs and TRAPXXX as they are; since the
       
   423      * shell's handler doesn't get the signal, they don't matter.
       
   424      */
       
   425     zfalarmed = 1;
       
   426 }
       
   427 
       
   428 /* Set up for a broken pipe */
       
   429 
       
   430 /**/
       
   431 static void
       
   432 zfpipe()
       
   433 {
       
   434     /* Just ignore SIGPIPE and rely on getting EPIPE from the write. */
       
   435 #ifndef __SYMBIAN32__    
       
   436     signal(SIGPIPE, SIG_IGN); 
       
   437 #endif    
       
   438 }
       
   439 
       
   440 /* Unset the alarm, see above */
       
   441 
       
   442 /**/
       
   443 static void
       
   444 zfunalarm(void)
       
   445 {
       
   446     if (oalremain) {
       
   447 	/*
       
   448 	 * The alarm was previously set, so set it back, adjusting
       
   449 	 * for the time used.  Mostly the alarm was set to zero
       
   450 	 * beforehand, so it would probably be best to reinstall
       
   451 	 * the proper signal handler before resetting the alarm.
       
   452 	 *
       
   453 	 * I love the way alarm() uses unsigned int while time_t
       
   454 	 * is probably something completely different.
       
   455 	 */
       
   456 	unsigned int tdiff = time(NULL) - oaltime;
       
   457 	alarm(oalremain < tdiff ? 1 : oalremain - tdiff);
       
   458     } else
       
   459 	alarm(0);
       
   460     if (sigtrapped[SIGALRM] || interact) {
       
   461 	if (sigfuncs[SIGALRM] || !sigtrapped[SIGALRM])
       
   462 	    install_handler(SIGALRM);
       
   463 	else
       
   464 	    signal_ignore(SIGALRM);
       
   465     } else
       
   466 	signal_default(SIGALRM);
       
   467     zfalarmed = 0;
       
   468 }
       
   469 
       
   470 /* Restore SIGPIPE handling to its usual status */
       
   471 
       
   472 /**/
       
   473 static void
       
   474 zfunpipe()
       
   475 {
       
   476     if (sigtrapped[SIGPIPE]) {
       
   477 	if (sigfuncs[SIGPIPE])
       
   478 	    install_handler(SIGPIPE);
       
   479 	else
       
   480 	    signal_ignore(SIGPIPE);
       
   481     } else
       
   482 	signal_default(SIGPIPE);
       
   483 }
       
   484 
       
   485 /*
       
   486  * Same as movefd(), but don't mark the fd in the zsh tables,
       
   487  * because we only want it closed by zftp.  However, we still
       
   488  * need to shift the fd's out of the way of the user-visible 0-9.
       
   489  */
       
   490 
       
   491 /**/
       
   492 static int
       
   493 zfmovefd(int fd)
       
   494 {
       
   495     if (fd != -1 && fd < 10) {
       
   496 #ifdef F_DUPFD
       
   497 	int fe = fcntl(fd, F_DUPFD, 10);
       
   498 #else
       
   499 	int fe = zfmovefd(dup(fd));
       
   500 #endif
       
   501 	close(fd);
       
   502 	fd = fe;
       
   503     }
       
   504     return fd;
       
   505 }
       
   506 
       
   507 /*
       
   508  * set a non-special parameter.
       
   509  * if ZFPM_IFUNSET, don't set if it already exists.
       
   510  * if ZFPM_READONLY, make it readonly, but only when creating it.
       
   511  * if ZFPM_INTEGER, val pointer is to off_t (NB not int), don't free.
       
   512  */
       
   513 /**/
       
   514 static void
       
   515 zfsetparam(char *name, void *val, int flags)
       
   516 {
       
   517     Param pm = NULL;
       
   518     int type = (flags & ZFPM_INTEGER) ? PM_INTEGER : PM_SCALAR;
       
   519 
       
   520     if (!(pm = (Param) paramtab->getnode(paramtab, name))
       
   521 	|| (pm->flags & PM_UNSET)) {
       
   522 	/*
       
   523 	 * just make it readonly when creating, in case user
       
   524 	 * *really* knows what they're doing
       
   525 	 */
       
   526 	if ((pm = createparam(name, type)) && (flags & ZFPM_READONLY))
       
   527 	    pm->flags |= PM_READONLY;
       
   528     } else if (flags & ZFPM_IFUNSET) {
       
   529 	pm = NULL;
       
   530     }
       
   531     if (!pm || PM_TYPE(pm->flags) != type) {
       
   532 	/* parameters are funny, you just never know */
       
   533 	if (type == PM_SCALAR)
       
   534 	    zsfree((char *)val);
       
   535 	return;
       
   536     }
       
   537     if (type == PM_INTEGER)
       
   538 	pm->gsu.i->setfn(pm, *(off_t *)val);
       
   539     else
       
   540 	pm->gsu.s->setfn(pm, (char *)val);
       
   541 }
       
   542 
       
   543 /*
       
   544  * Unset a ZFTP parameter when the connection is closed.
       
   545  * We only do this with connection-specific parameters.
       
   546  */
       
   547 
       
   548 /**/
       
   549 static void
       
   550 zfunsetparam(char *name)
       
   551 {
       
   552     Param pm;
       
   553 
       
   554     if ((pm = (Param) paramtab->getnode(paramtab, name))) {
       
   555 	pm->flags &= ~PM_READONLY;
       
   556 	unsetparam_pm(pm, 0, 1);
       
   557     }
       
   558 }
       
   559 
       
   560 /*
       
   561  * Join command and arguments to make a proper TELNET command line.
       
   562  * New line is in permanent storage.
       
   563  */
       
   564 
       
   565 /**/
       
   566 static char *
       
   567 zfargstring(char *cmd, char **args)
       
   568 {
       
   569     int clen = strlen(cmd) + 3;
       
   570     char *line, **aptr;
       
   571 
       
   572     for (aptr = args; *aptr; aptr++)
       
   573 	clen += strlen(*aptr) + 1;
       
   574     line = zalloc(clen);
       
   575     strcpy(line, cmd);
       
   576     for (aptr = args; *aptr; aptr++) {
       
   577 	strcat(line, " ");
       
   578 	strcat(line, *aptr);
       
   579     }
       
   580     strcat(line, "\r\n");
       
   581 
       
   582     return line;
       
   583 }
       
   584 
       
   585 /*
       
   586  * get a line on the control connection according to TELNET rules
       
   587  * Return status is first digit of FTP reply code
       
   588  */
       
   589 
       
   590 /**/
       
   591 static int
       
   592 zfgetline(char *ln, int lnsize, int tmout)
       
   593 {
       
   594     int ch, added = 0;
       
   595     /* current line point */
       
   596     char *pcur = ln, cmdbuf[3];
       
   597 
       
   598     zcfinish = 0;
       
   599     /* leave room for null byte */
       
   600     lnsize--;
       
   601     /* in case we return unexpectedly before getting anything */
       
   602     ln[0] = '\0';
       
   603 
       
   604     if (setjmp(zfalrmbuf)) {
       
   605 	alarm(0);
       
   606 	zwarnnam("zftp", "timeout getting response", NULL, 0);
       
   607 	return 6;
       
   608     }
       
   609     zfalarm(tmout);
       
   610 
       
   611     /*
       
   612      * We need to be more careful about errors here; we
       
   613      * should do the stuff with errflag and so forth.
       
   614      * We should probably holdintr() here, since if we don't
       
   615      * get the message, the connection is going to be messed up.
       
   616      * But then we get `frustrated user syndrome'.
       
   617      */
       
   618     for (;;) {
       
   619 	ch = fgetc(zfsess->cin);
       
   620 
       
   621 	switch(ch) {
       
   622 	case EOF:
       
   623 	    if (ferror(zfsess->cin) && errno == EINTR) {
       
   624 		clearerr(zfsess->cin);
       
   625 		continue;
       
   626 	    }
       
   627 	    zcfinish = 2;
       
   628 	    break;
       
   629 
       
   630 	case '\r':
       
   631 	    /* always precedes something else */
       
   632 	    ch = fgetc(zfsess->cin);
       
   633 	    if (ch == EOF) {
       
   634 		zcfinish = 2;
       
   635 		break;
       
   636 	    }
       
   637 	    if (ch == '\n') {
       
   638 		zcfinish = 1;
       
   639 		break;
       
   640 	    }
       
   641 	    if (ch == '\0') {
       
   642 		ch = '\r';
       
   643 		break;
       
   644 	    }
       
   645 	    /* not supposed to get here */
       
   646 	    ch = '\r';
       
   647 	    break;
       
   648 
       
   649 	case '\n':
       
   650 	    /* not supposed to get here */
       
   651 	    zcfinish = 1;
       
   652 	    break;
       
   653 
       
   654 	case IAC:
       
   655 	    /*
       
   656 	     * oh great, now it's sending TELNET commands.  try
       
   657 	     * to persuade it not to.
       
   658 	     */
       
   659 	    ch = fgetc(zfsess->cin);
       
   660 	    switch (ch) {
       
   661 	    case WILL:
       
   662 	    case WONT:
       
   663 		ch = fgetc(zfsess->cin);
       
   664 		/* whatever it wants to do, stop it. */
       
   665 		cmdbuf[0] = (char)IAC;
       
   666 		cmdbuf[1] = (char)DONT;
       
   667 		cmdbuf[2] = ch;
       
   668 		write(zfsess->control->fd, cmdbuf, 3);
       
   669 		continue;
       
   670 
       
   671 	    case DO:
       
   672 	    case DONT:
       
   673 		ch = fgetc(zfsess->cin);
       
   674 		/* well, tough, we're not going to. */
       
   675 		cmdbuf[0] = (char)IAC;
       
   676 		cmdbuf[1] = (char)WONT;
       
   677 		cmdbuf[2] = ch;
       
   678 		write(zfsess->control->fd, cmdbuf, 3);
       
   679 		continue;
       
   680 
       
   681 	    case EOF:
       
   682 		/* strange machine. */
       
   683 		zcfinish = 2;
       
   684 		break;
       
   685 
       
   686 	    default:
       
   687 		break;
       
   688 	    }
       
   689 	    break;
       
   690 	}
       
   691 	
       
   692 	if (zcfinish)
       
   693 	    break;
       
   694 	if (added < lnsize) {
       
   695 	    *pcur++ = ch;
       
   696 	    added++;
       
   697 	}
       
   698 	/* junk it if we don't have room, but go on reading */
       
   699     }
       
   700 
       
   701     alarm(0);
       
   702 
       
   703     *pcur = '\0';
       
   704     /* if zcfinish == 2, at EOF, return that, else 0 */
       
   705     return (zcfinish & 2);
       
   706 }
       
   707 
       
   708 /*
       
   709  * Get a whole message from the server.  A dash after
       
   710  * the first line code means keep reading until we get
       
   711  * a line with the same code followed by a space.
       
   712  *
       
   713  * Note that this returns an FTP status code, the first
       
   714  * digit of the reply.  There is also a pseudocode, 6, which
       
   715  * means `there's no point trying anything, just yet'.
       
   716  * We return it either if the connection is closed, or if
       
   717  * we got a 530 (user not logged in), in which case whatever
       
   718  * you're trying to do isn't going to work.
       
   719  */
       
   720 
       
   721 /**/
       
   722 static int 
       
   723 zfgetmsg(void)
       
   724 {
       
   725     char line[256], *ptr, *verbose;
       
   726     int stopit, printing = 0, tmout;
       
   727 
       
   728     if (!zfsess->control)
       
   729 	return 6;
       
   730     zsfree(lastmsg);
       
   731     lastmsg = NULL;
       
   732 
       
   733     tmout = getiparam("ZFTP_TMOUT");
       
   734 
       
   735     zfgetline(line, 256, tmout);
       
   736     ptr = line;
       
   737     if (zfdrrrring || !isdigit(STOUC(*ptr)) || !isdigit(STOUC(ptr[1])) || 
       
   738 	!isdigit(STOUC(ptr[2]))) {
       
   739 	/* timeout, or not talking FTP.  not really interested. */
       
   740 	zcfinish = 2;
       
   741 	if (!zfclosing)
       
   742 	    zfclose(0);
       
   743 	lastmsg = ztrdup("");
       
   744 	strcpy(lastcodestr, "000");
       
   745 	zfsetparam("ZFTP_REPLY", ztrdup(lastmsg), ZFPM_READONLY);
       
   746 	return 6;
       
   747     }
       
   748     strncpy(lastcodestr, ptr, 3);
       
   749     ptr += 3;
       
   750     lastcodestr[3] = '\0';
       
   751     lastcode = atoi(lastcodestr);
       
   752     zfsetparam("ZFTP_CODE", ztrdup(lastcodestr), ZFPM_READONLY);
       
   753     stopit = (*ptr++ != '-');
       
   754 
       
   755     queue_signals();
       
   756     if (!(verbose = getsparam("ZFTP_VERBOSE")))
       
   757 	verbose = "";
       
   758     if (strchr(verbose, lastcodestr[0])) {
       
   759 	/* print the whole thing verbatim */
       
   760 	printing = 1;
       
   761 	fputs(line, stderr);
       
   762     }  else if (strchr(verbose, '0') && !stopit) {
       
   763 	/* print multiline parts with the code stripped */
       
   764 	printing = 2;
       
   765 	fputs(ptr, stderr);
       
   766     }
       
   767     unqueue_signals();
       
   768     if (printing)
       
   769 	fputc('\n', stderr);
       
   770 
       
   771     while (zcfinish != 2 && !stopit) {
       
   772 	zfgetline(line, 256, tmout);
       
   773 	ptr = line;
       
   774 	if (zfdrrrring) {
       
   775 	    line[0] = '\0';
       
   776 	    break;
       
   777 	}
       
   778 
       
   779 	if (!strncmp(lastcodestr, line, 3)) {
       
   780 	    if (line[3] == ' ') {
       
   781 		stopit = 1;
       
   782 		ptr += 4;
       
   783 	    } else if (line[3] == '-')
       
   784 		ptr += 4;
       
   785 	} else if (!strncmp("    ", line, 4))
       
   786 	    ptr += 4;
       
   787 
       
   788 	if (printing == 2) {
       
   789 	    if (!stopit) {
       
   790 		fputs(ptr, stderr);
       
   791 		fputc('\n', stderr);
       
   792 	    }
       
   793 	} else if (printing) {
       
   794 	    fputs(line, stderr);
       
   795 	    fputc('\n', stderr);
       
   796 	}
       
   797     }
       
   798 
       
   799     if (printing)
       
   800 	fflush(stderr);
       
   801 
       
   802     /* The internal message is just the text. */
       
   803     lastmsg = ztrdup(ptr);
       
   804     /*
       
   805      * The parameter is the whole thing, including the code.
       
   806      */
       
   807     zfsetparam("ZFTP_REPLY", ztrdup(line), ZFPM_READONLY);
       
   808     /*
       
   809      * close the connection here if zcfinish == 2, i.e. EOF,
       
   810      * or if we get a 421 (service not available, closing connection),
       
   811      * but don't do it if it's expected (zfclosing set).
       
   812      */
       
   813     if ((zcfinish == 2 || lastcode == 421) && !zfclosing) {
       
   814 	zcfinish = 2;		/* don't need to tell server */
       
   815 	zfclose(0);
       
   816 	/* unexpected, so tell user */
       
   817 	zwarnnam("zftp", "remote server has closed connection", NULL, 0);
       
   818 	return 6;
       
   819     }
       
   820     if (lastcode == 530) {
       
   821 	/* user not logged in */
       
   822 	return 6;
       
   823     }
       
   824     /*
       
   825      * May as well handle this here, though it's pretty uncommon.
       
   826      * A 120 is something like "service ready in nnn minutes".
       
   827      * It means we just hang around waiting for another reply.
       
   828      */
       
   829     if (lastcode == 120) {
       
   830 	zwarnnam("zftp", "delay expected, waiting: %s", lastmsg, 0);
       
   831 	return zfgetmsg();
       
   832     }
       
   833 
       
   834     /* first digit of code determines success, failure, not in the mood... */
       
   835     return lastcodestr[0] - '0';
       
   836 }
       
   837 
       
   838 
       
   839 /*
       
   840  * Send a command and get the reply.
       
   841  * The command is expected to have the \r\n already tacked on.
       
   842  * Returns the status code for the reply.
       
   843  */
       
   844 
       
   845 /**/
       
   846 static int
       
   847 zfsendcmd(char *cmd)
       
   848 {
       
   849     /*
       
   850      * We use the fd directly; there's no point even using
       
   851      * stdio with line buffering, since we always send the
       
   852      * complete line in one string anyway.
       
   853      */
       
   854     int ret, tmout;
       
   855 
       
   856     if (!zfsess->control)
       
   857 	return 6;
       
   858     tmout = getiparam("ZFTP_TMOUT");
       
   859     if (setjmp(zfalrmbuf)) {
       
   860 	alarm(0);
       
   861 	zwarnnam("zftp", "timeout sending message", NULL, 0);
       
   862 	return 6;
       
   863     }
       
   864     zfalarm(tmout);
       
   865     ret = write(zfsess->control->fd, cmd, strlen(cmd));
       
   866     alarm(0);
       
   867 
       
   868     if (ret <= 0) {
       
   869 	zwarnnam("zftp send", "failure sending control message: %e",
       
   870 		 NULL, errno);
       
   871 	return 6;
       
   872     }
       
   873 
       
   874     return zfgetmsg();
       
   875 }
       
   876 
       
   877 
       
   878 /* Set up a data connection, return 1 for failure, 0 for success */
       
   879 
       
   880 /**/
       
   881 static int
       
   882 zfopendata(char *name, union tcp_sockaddr *zdsockp, int *is_passivep)
       
   883 {
       
   884     if (!(zfprefs & (ZFPF_SNDP|ZFPF_PASV))) {
       
   885 	zwarnnam(name, "Must set preference S or P to transfer data", NULL, 0);
       
   886 	return 1;
       
   887     }
       
   888     zfsess->dfd = socket(zfsess->control->peer.a.sa_family, SOCK_STREAM, 0);
       
   889     if (zfsess->dfd < 0) {
       
   890 	zwarnnam(name, "can't get data socket: %e", NULL, errno);
       
   891 	return 1;
       
   892     }
       
   893 
       
   894     if (!(zfstatusp[zfsessno] & ZFST_NOPS) && (zfprefs & ZFPF_PASV)) {
       
   895 	char *psv_cmd;
       
   896 	int err, salen;
       
   897 
       
   898 #ifdef SUPPORT_IPV6
       
   899 	if(zfsess->control->peer.a.sa_family == AF_INET6)
       
   900 	    psv_cmd = "EPSV\r\n";
       
   901 	else
       
   902 #endif /* SUPPORT_IPV6 */
       
   903 	    psv_cmd = "PASV\r\n";
       
   904 	if (zfsendcmd(psv_cmd) == 6)
       
   905 	    return 1;
       
   906 	else if (lastcode >= 500 && lastcode <= 504) {
       
   907 	    /*
       
   908 	     * Fall back to send port mode.  That will
       
   909 	     * test the preferences for whether that's OK.
       
   910 	     */
       
   911 	    zfstatusp[zfsessno] |= ZFST_NOPS;
       
   912 	    zfclosedata();
       
   913 	    return zfopendata(name, zdsockp, is_passivep);
       
   914 	}
       
   915 	zdsockp->a.sa_family = zfsess->control->peer.a.sa_family;
       
   916 #ifdef SUPPORT_IPV6
       
   917 	if(zfsess->control->peer.a.sa_family == AF_INET6) {
       
   918 	    /* see RFC 2428 for explanation */
       
   919 	    char const *ptr, *end;
       
   920 	    char delim, portbuf[6], *pbp;
       
   921 	    unsigned long portnum;
       
   922 	    ptr = strchr(lastmsg, '(');
       
   923 	    if(!ptr) {
       
   924 	    bad_epsv:
       
   925 		zwarnnam(name, "bad response to EPSV: %s", lastmsg, 0);
       
   926 		zfclosedata();
       
   927 		return 1;
       
   928 	    }
       
   929 	    delim = ptr[1];
       
   930 	    if(delim < 33 || delim > 126 || ptr[2] != delim || ptr[3] != delim)
       
   931 		goto bad_epsv;
       
   932 	    ptr += 4;
       
   933 	    end = strchr(ptr, delim);
       
   934 	    if(!end || end[1] != ')')
       
   935 		goto bad_epsv;
       
   936 	    while(ptr != end && *ptr == '0')
       
   937 		ptr++;
       
   938 	    if(ptr == end || (end-ptr) > 5 || !isdigit(STOUC(*ptr)))
       
   939 		goto bad_epsv;
       
   940 	    memcpy(portbuf, ptr, (end-ptr));
       
   941 	    portbuf[end-ptr] = 0;
       
   942 	    portnum = strtoul(portbuf, &pbp, 10);
       
   943 	    if(*pbp || portnum > 65535UL)
       
   944 		goto bad_epsv;
       
   945 	    *zdsockp = zfsess->control->peer;
       
   946 	    zdsockp->in6.sin6_port = htons((unsigned)portnum);
       
   947 	    salen = sizeof(struct sockaddr_in6);
       
   948 	} else
       
   949 #endif /* SUPPORT_IPV6 */
       
   950 	{
       
   951 	    char *ptr;
       
   952 	    int i, nums[6];
       
   953 	    unsigned char iaddr[4], iport[2];
       
   954 
       
   955 	    /*
       
   956 	     * OK, now we need to know what port we're looking at,
       
   957 	     * which is cunningly concealed in the reply.
       
   958 	     * lastmsg already has the reply code expunged.
       
   959 	     */
       
   960 	    for (ptr = lastmsg; *ptr; ptr++)
       
   961 		if (isdigit(STOUC(*ptr)))
       
   962 		    break;
       
   963 	    if (sscanf(ptr, "%d,%d,%d,%d,%d,%d",
       
   964 		       nums, nums+1, nums+2, nums+3, nums+4, nums+5) != 6) {
       
   965 		zwarnnam(name, "bad response to PASV: %s", lastmsg, 0);
       
   966 		zfclosedata();
       
   967 		return 1;
       
   968 	    }
       
   969 	    for (i = 0; i < 4; i++)
       
   970 		iaddr[i] = STOUC(nums[i]);
       
   971 	    iport[0] = STOUC(nums[4]);
       
   972 	    iport[1] = STOUC(nums[5]);
       
   973 
       
   974 	    memcpy(&zdsockp->in.sin_addr, iaddr, sizeof(iaddr));
       
   975 	    memcpy(&zdsockp->in.sin_port, iport, sizeof(iport));
       
   976 	    salen = sizeof(struct sockaddr_in);
       
   977 	}
       
   978 
       
   979 	/* we should timeout this connect */
       
   980 	do {
       
   981 	    err = connect(zfsess->dfd, (struct sockaddr *)zdsockp, salen);
       
   982 	} while (err && errno == EINTR && !errflag);
       
   983 
       
   984 	if (err) {
       
   985 	    zwarnnam(name, "connect failed: %e", NULL, errno);
       
   986 	    zfclosedata();
       
   987 	    return 1;
       
   988 	}
       
   989 
       
   990 	*is_passivep = 1;
       
   991     } else {
       
   992 #ifdef SUPPORT_IPV6
       
   993 	char portcmd[8+INET6_ADDRSTRLEN+9];
       
   994 #else
       
   995 	char portcmd[40];
       
   996 #endif
       
   997 	ZSOCKLEN_T len;
       
   998 	int ret;
       
   999 
       
  1000 	if (!(zfprefs & ZFPF_SNDP)) {
       
  1001 	    zwarnnam(name, "only sendport mode available for data", NULL, 0);
       
  1002 	    return 1;
       
  1003 	}
       
  1004 
       
  1005 	*zdsockp = zfsess->control->sock;
       
  1006 #ifdef SUPPORT_IPV6
       
  1007 	if(zdsockp->a.sa_family == AF_INET6) {
       
  1008 	    zdsockp->in6.sin6_port = 0;	/* to be set by bind() */
       
  1009 	    len = sizeof(struct sockaddr_in6);
       
  1010 	} else
       
  1011 #endif /* SUPPORT_IPV6 */
       
  1012 	{
       
  1013 	    zdsockp->in.sin_port = 0;	/* to be set by bind() */
       
  1014 	    len = sizeof(struct sockaddr_in);
       
  1015 	}
       
  1016 	/* need to do timeout stuff and probably handle EINTR here */
       
  1017 	if (bind(zfsess->dfd, (struct sockaddr *)zdsockp, len) < 0)
       
  1018 	    ret = 1;
       
  1019 	else if (getsockname(zfsess->dfd, (struct sockaddr *)zdsockp,
       
  1020 			     &len) < 0)
       
  1021 	    ret = 2;
       
  1022 	else if (listen(zfsess->dfd, 1) < 0)
       
  1023 	    ret = 3;
       
  1024 	else
       
  1025 	    ret = 0;
       
  1026 
       
  1027 	if (ret) {
       
  1028 	    zwarnnam(name, "failure on data socket: %s: %e",
       
  1029 		     ret == 3 ? "listen" : ret == 2 ? "getsockname" : "bind",
       
  1030 		     errno);
       
  1031 	    zfclosedata();
       
  1032 	    return 1;
       
  1033 	}
       
  1034 
       
  1035 #ifdef SUPPORT_IPV6
       
  1036 	if(zdsockp->a.sa_family == AF_INET6) {
       
  1037 	    /* see RFC 2428 for explanation */
       
  1038 	    strcpy(portcmd, "EPRT |2|");
       
  1039 	    zsh_inet_ntop(AF_INET6, &zdsockp->in6.sin6_addr,
       
  1040 			  portcmd+8, INET6_ADDRSTRLEN);
       
  1041 	    sprintf(strchr(portcmd, 0), "|%u|\r\n",
       
  1042 		    (unsigned)ntohs(zdsockp->in6.sin6_port));
       
  1043 	} else
       
  1044 #endif /* SUPPORT_IPV6 */
       
  1045 	{
       
  1046 	    unsigned char *addr = (unsigned char *) &zdsockp->in.sin_addr;
       
  1047 	    unsigned char *port = (unsigned char *) &zdsockp->in.sin_port;
       
  1048 	    sprintf(portcmd, "PORT %d,%d,%d,%d,%d,%d\r\n",
       
  1049 		    addr[0],addr[1],addr[2],addr[3],port[0],port[1]);
       
  1050 	}
       
  1051 	if (zfsendcmd(portcmd) >= 5) {
       
  1052 	    zwarnnam(name, "port command failed", NULL, 0);
       
  1053 	    zfclosedata();
       
  1054 	    return 1;
       
  1055 	}
       
  1056 	*is_passivep = 0;
       
  1057     }
       
  1058 
       
  1059     return 0;
       
  1060 }
       
  1061 
       
  1062 /* Close the data connection. */
       
  1063 
       
  1064 /**/
       
  1065 static void
       
  1066 zfclosedata(void)
       
  1067 {
       
  1068     if (zfsess->dfd == -1)
       
  1069 	return;
       
  1070     close(zfsess->dfd);
       
  1071     zfsess->dfd = -1;
       
  1072 }
       
  1073 
       
  1074 /*
       
  1075  * Set up a data connection and use cmd to initiate a transfer.
       
  1076  * The actual data fd will be zfsess->dfd; the calling routine
       
  1077  * must handle the data itself.
       
  1078  * rest is a REST command to specify starting somewhere other
       
  1079  * then the start of the remote file.
       
  1080  * getsize is non-zero if we want to try to find the number
       
  1081  * of bytes in the reply to a RETR command.
       
  1082  *
       
  1083  * Return 0 on success, 1 on failure.
       
  1084  */
       
  1085 
       
  1086 /**/
       
  1087 static int
       
  1088 zfgetdata(char *name, char *rest, char *cmd, int getsize)
       
  1089 {
       
  1090     ZSOCKLEN_T len;
       
  1091     int newfd, is_passive;
       
  1092     union tcp_sockaddr zdsock;
       
  1093 
       
  1094     if (zfopendata(name, &zdsock, &is_passive))
       
  1095 	return 1;
       
  1096 
       
  1097     /*
       
  1098      * Set position in remote file for get/put.
       
  1099      * According to RFC959, the restart command needs something
       
  1100      * called a marker which has previously been put into the data.
       
  1101      * Luckily for the real world, UNIX machines just interpret this
       
  1102      * as an offset into the byte stream.
       
  1103      *
       
  1104      * This has to be sent immediately before the data transfer, i.e.
       
  1105      * after all mucking around with types and sizes and so on.
       
  1106      */
       
  1107     if (rest && zfsendcmd(rest) > 3) {
       
  1108 	zfclosedata();
       
  1109 	return 1;
       
  1110     }
       
  1111 
       
  1112     if (zfsendcmd(cmd) > 2) {
       
  1113 	zfclosedata();
       
  1114 	return 1;
       
  1115     }
       
  1116     if (getsize || (!(zfstatusp[zfsessno] & ZFST_TRSZ) &&
       
  1117 		    !strncmp(cmd, "RETR", 4))) {
       
  1118 	/*
       
  1119 	 * See if we got something like:
       
  1120 	 *   Opening data connection for nortypix.gif (1234567 bytes).
       
  1121 	 * On the first RETR, always see if this works,  Then we
       
  1122 	 * can avoid sending a special SIZE command beforehand.
       
  1123 	 */
       
  1124 	char *ptr = strstr(lastmsg, "bytes");
       
  1125 	zfstatusp[zfsessno] |= ZFST_NOSZ|ZFST_TRSZ;
       
  1126 	if (ptr) {
       
  1127 	    while (ptr > lastmsg && !isdigit(STOUC(*ptr)))
       
  1128 		ptr--;
       
  1129 	    while (ptr > lastmsg && isdigit(STOUC(ptr[-1])))
       
  1130 		ptr--;
       
  1131 	    if (isdigit(STOUC(*ptr))) {
       
  1132 		zfstatusp[zfsessno] &= ~ZFST_NOSZ;
       
  1133 		if (getsize) {
       
  1134 		    off_t sz = zstrtol(ptr, NULL, 10);
       
  1135 		    zfsetparam("ZFTP_SIZE", &sz, ZFPM_READONLY|ZFPM_INTEGER);
       
  1136 		}
       
  1137 	    }
       
  1138 	}
       
  1139     }
       
  1140 
       
  1141     if (!is_passive) {
       
  1142 	/*
       
  1143 	 * the current zfsess->dfd is the socket we opened, but we need
       
  1144 	 * to let the server set up a different fd for reading/writing.
       
  1145 	 * then we can close the fd we were listening for a connection on.
       
  1146 	 * don't expect me to understand this, i'm only the programmer.
       
  1147 	 */
       
  1148 
       
  1149 	/* accept the connection */
       
  1150 	len = sizeof(zdsock);
       
  1151 	newfd = zfmovefd(accept(zfsess->dfd, (struct sockaddr *)&zdsock, 
       
  1152 				&len));
       
  1153 	if (newfd < 0)
       
  1154 	    zwarnnam(name, "unable to accept data: %e", NULL, errno);
       
  1155 	zfclosedata();
       
  1156 	if (newfd < 0)
       
  1157 	    return 1;
       
  1158 	zfsess->dfd = newfd;	/* this is now the actual data fd */
       
  1159     } else {
       
  1160 	/*
       
  1161 	 * We avoided dup'ing zfsess->dfd up to this point, to try to keep
       
  1162 	 * things simple, so we now need to move it out of the way
       
  1163 	 * of the user-visible fd's.
       
  1164 	 */
       
  1165 	zfsess->dfd = zfmovefd(zfsess->dfd);
       
  1166     }
       
  1167 
       
  1168 
       
  1169     /* more options, just to look professional */
       
  1170 #ifdef SO_LINGER
       
  1171     /*
       
  1172      * Since data can take arbitrary amounts of time to arrive,
       
  1173      * the socket can be made to hang around until it doesn't think
       
  1174      * anything is arriving.
       
  1175      *
       
  1176      * In BSD 4.3, you could only linger for infinity.  Don't
       
  1177      * know if this has changed.
       
  1178      */
       
  1179     {
       
  1180 	struct linger li;
       
  1181 
       
  1182 	li.l_onoff = 1;
       
  1183 	li.l_linger = 120;
       
  1184 	setsockopt(zfsess->dfd, SOL_SOCKET, SO_LINGER,
       
  1185 		   (char *)&li, sizeof(li));
       
  1186     }
       
  1187 #endif
       
  1188 #if defined(IP_TOS) && defined(IPTOS_THROUGHPUT)
       
  1189     /* try to get high throughput, snigger */
       
  1190     {
       
  1191 	int arg = IPTOS_THROUGHPUT;
       
  1192 	setsockopt(zfsess->dfd, IPPROTO_IP, IP_TOS, (char *)&arg, sizeof(arg));
       
  1193     }
       
  1194 #endif
       
  1195 #if defined(F_SETFD) && defined(FD_CLOEXEC)
       
  1196     /* If the shell execs a program, we don't want this fd left open. */
       
  1197     fcntl(zfsess->dfd, F_SETFD, FD_CLOEXEC);
       
  1198 #endif
       
  1199 
       
  1200     return 0;
       
  1201 }
       
  1202 
       
  1203 /*
       
  1204  * Find out about a local or remote file and pass back the information.
       
  1205  *
       
  1206  * We could jigger this to use ls like ncftp does as a backup.
       
  1207  * But if the server is non-standard enough not to have SIZE and MDTM,
       
  1208  * there's a very good chance ls -l isn't going to do great things.
       
  1209  *
       
  1210  * if fd is >= 0, it is used for an fstat when remote is zero:
       
  1211  * this is because on a put we are taking input from fd 0.
       
  1212  */
       
  1213 
       
  1214 /**/
       
  1215 static int
       
  1216 zfstats(char *fnam, int remote, off_t *retsize, char **retmdtm, int fd)
       
  1217 {
       
  1218     off_t sz = -1;
       
  1219     char *mt = NULL;
       
  1220     int ret;
       
  1221 
       
  1222     if (retsize)
       
  1223 	*retsize = -1;
       
  1224     if (retmdtm)
       
  1225 	*retmdtm = NULL;
       
  1226     if (remote) {
       
  1227 	char *cmd;
       
  1228 	if ((zfsess->has_size == ZFCP_NOPE && retsize) ||
       
  1229 	    (zfsess->has_mdtm == ZFCP_NOPE && retmdtm))
       
  1230 	    return 2;
       
  1231 
       
  1232 	/*
       
  1233 	 * File is coming from over there.
       
  1234 	 * Make sure we get the type right.
       
  1235 	 */
       
  1236 	zfsettype(ZFST_TYPE(zfstatusp[zfsessno]));
       
  1237 	if (retsize) {
       
  1238 	    cmd = tricat("SIZE ", fnam, "\r\n");
       
  1239 	    ret = zfsendcmd(cmd);
       
  1240 	    zsfree(cmd);
       
  1241 	    if (ret == 6)
       
  1242 		return 1;
       
  1243 	    else if (lastcode < 300) {
       
  1244 		sz = zstrtol(lastmsg, 0, 10);
       
  1245 		zfsess->has_size = ZFCP_YUPP;
       
  1246 	    } else if (lastcode >= 500 && lastcode <= 504) {
       
  1247 		zfsess->has_size = ZFCP_NOPE;
       
  1248 		return 2;
       
  1249 	    } else if (lastcode == 550)
       
  1250 		return 1;
       
  1251 	    /* if we got a 550 from SIZE, the file doesn't exist */
       
  1252 	}
       
  1253 
       
  1254 	if (retmdtm) {
       
  1255 	    cmd = tricat("MDTM ", fnam, "\r\n");
       
  1256 	    ret = zfsendcmd(cmd);
       
  1257 	    zsfree(cmd);
       
  1258 	    if (ret == 6)
       
  1259 		return 1;
       
  1260 	    else if (lastcode < 300) {
       
  1261 		mt = ztrdup(lastmsg);
       
  1262 		zfsess->has_mdtm = ZFCP_YUPP;
       
  1263 	    } else if (lastcode >= 500 && lastcode <= 504) {
       
  1264 		zfsess->has_mdtm = ZFCP_NOPE;
       
  1265 		return 2;
       
  1266 	    } else if (lastcode == 550)
       
  1267 		return 1;
       
  1268 	}
       
  1269     } else {
       
  1270 	/* File is over here */
       
  1271 	struct stat statbuf;
       
  1272 	struct tm *tm;
       
  1273 	char tmbuf[20];
       
  1274 
       
  1275 	if ((fd == -1 ? stat(fnam, &statbuf) : fstat(fd, &statbuf)) < 0)
       
  1276 	    return 1;
       
  1277 	/* make sure it's off_t, since this has to be a pointer */
       
  1278 	sz = statbuf.st_size;
       
  1279 
       
  1280 	if (retmdtm) {
       
  1281 	    /* use gmtime() rather than localtime() for consistency */
       
  1282 	    tm = gmtime(&statbuf.st_mtime);
       
  1283 	    /*
       
  1284 	     * FTP format for data is YYYYMMDDHHMMSS
       
  1285 	     * Using tm directly is easier than worrying about
       
  1286 	     * incompatible strftime()'s.
       
  1287 	     */
       
  1288 	    sprintf(tmbuf, "%04d%02d%02d%02d%02d%02d",
       
  1289 		    tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday,
       
  1290 		    tm->tm_hour, tm->tm_min, tm->tm_sec);
       
  1291 	    mt = ztrdup(tmbuf);
       
  1292 	}
       
  1293     }
       
  1294     if (retsize)
       
  1295 	*retsize = sz;
       
  1296     if (retmdtm)
       
  1297 	*retmdtm = mt;
       
  1298     return 0;
       
  1299 }
       
  1300 
       
  1301 /* Set parameters to say what's coming */
       
  1302 
       
  1303 /**/
       
  1304 static void
       
  1305 zfstarttrans(char *nam, int recv, off_t sz)
       
  1306 {
       
  1307     off_t cnt = 0;
       
  1308     /*
       
  1309      * sz = -1 signifies error getting size.  don't set ZFTP_SIZE if sz is
       
  1310      * zero, either: it probably came from an fstat() on a pipe, so it
       
  1311      * means we don't know and shouldn't tell the user porkies.
       
  1312      */
       
  1313     if (sz > 0)
       
  1314 	zfsetparam("ZFTP_SIZE", &sz, ZFPM_READONLY|ZFPM_INTEGER);
       
  1315     zfsetparam("ZFTP_FILE", ztrdup(nam), ZFPM_READONLY);
       
  1316     zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "G" : "P"), ZFPM_READONLY);
       
  1317     zfsetparam("ZFTP_COUNT", &cnt, ZFPM_READONLY|ZFPM_INTEGER);
       
  1318 }
       
  1319 
       
  1320 /* Tidy up afterwards */
       
  1321 
       
  1322 /**/
       
  1323 static void
       
  1324 zfendtrans()
       
  1325 {
       
  1326     zfunsetparam("ZFTP_SIZE");
       
  1327     zfunsetparam("ZFTP_FILE");
       
  1328     zfunsetparam("ZFTP_TRANSFER");
       
  1329     zfunsetparam("ZFTP_COUNT");
       
  1330 }
       
  1331 
       
  1332 /* Read with timeout if recv is set. */
       
  1333 
       
  1334 /**/
       
  1335 static int
       
  1336 zfread(int fd, char *bf, off_t sz, int tmout)
       
  1337 {
       
  1338     int ret;
       
  1339 
       
  1340     if (!tmout)
       
  1341 	return read(fd, bf, sz);
       
  1342 
       
  1343     if (setjmp(zfalrmbuf)) {
       
  1344 	alarm(0);
       
  1345 	zwarnnam("zftp", "timeout on network read", NULL, 0);
       
  1346 	return -1;
       
  1347     }
       
  1348     zfalarm(tmout);
       
  1349 
       
  1350     ret = read(fd, bf, sz);
       
  1351 
       
  1352     /* we don't bother turning off the whole alarm mechanism here */
       
  1353     alarm(0);
       
  1354     return ret;
       
  1355 }
       
  1356 
       
  1357 /* Write with timeout if recv is not set. */
       
  1358 
       
  1359 /**/
       
  1360 static int
       
  1361 zfwrite(int fd, char *bf, off_t sz, int tmout)
       
  1362 {
       
  1363     int ret;
       
  1364 
       
  1365     if (!tmout)
       
  1366 	return write(fd, bf, sz);
       
  1367 
       
  1368     if (setjmp(zfalrmbuf)) {
       
  1369 	alarm(0);
       
  1370 	zwarnnam("zftp", "timeout on network write", NULL, 0);
       
  1371 	return -1;
       
  1372     }
       
  1373     zfalarm(tmout);
       
  1374 
       
  1375     ret = write(fd, bf, sz);
       
  1376 
       
  1377     /* we don't bother turning off the whole alarm mechanism here */
       
  1378     alarm(0);
       
  1379     return ret;
       
  1380 }
       
  1381 
       
  1382 static int zfread_eof;
       
  1383 
       
  1384 /* Version of zfread when we need to read in block mode. */
       
  1385 
       
  1386 /**/
       
  1387 static int
       
  1388 zfread_block(int fd, char *bf, off_t sz, int tmout)
       
  1389 {
       
  1390     int n;
       
  1391     struct zfheader hdr;
       
  1392     off_t blksz, cnt;
       
  1393     char *bfptr;
       
  1394     do {
       
  1395 	/* we need the header */
       
  1396 	do {
       
  1397 	    n = zfread(fd, (char *)&hdr, sizeof(hdr), tmout);
       
  1398 	} while (n < 0 && errno == EINTR);
       
  1399 	if (n != 3 && !zfdrrrring) {
       
  1400 	    zwarnnam("zftp", "failure reading FTP block header", NULL, 0);
       
  1401 	    return n;
       
  1402 	}
       
  1403 	/* size is stored in network byte order */
       
  1404 	if (hdr.flags & ZFHD_EOFB)
       
  1405 	    zfread_eof = 1;
       
  1406 	blksz = (hdr.bytes[0] << 8) | hdr.bytes[1];
       
  1407 	if (blksz > sz) {
       
  1408 	    /*
       
  1409 	     * See comments in file headers
       
  1410 	     */
       
  1411 	    zwarnnam("zftp", "block too large to handle", NULL, 0);
       
  1412 	    errno = EIO;
       
  1413 	    return -1;
       
  1414 	}
       
  1415 	bfptr = bf;
       
  1416 	cnt = blksz;
       
  1417 	while (cnt) {
       
  1418 	    n = zfread(fd, bfptr, cnt, tmout);
       
  1419 	    if (n > 0) {
       
  1420 		bfptr += n;
       
  1421 		cnt -= n;
       
  1422 	    } else if (n < 0 && (errflag || zfdrrrring || errno != EINTR))
       
  1423 		return n;
       
  1424 	    else
       
  1425 		break;
       
  1426 	}
       
  1427 	if (cnt) {
       
  1428 	    zwarnnam("zftp", "short data block", NULL, 0);
       
  1429 	    errno = EIO;
       
  1430 	    return -1;
       
  1431 	}
       
  1432     } while ((hdr.flags & ZFHD_MARK) && !zfread_eof);
       
  1433     return (hdr.flags & ZFHD_MARK) ? 0 : blksz;
       
  1434 }
       
  1435 
       
  1436 /* Version of zfwrite when we need to write in block mode. */
       
  1437 
       
  1438 /**/
       
  1439 static int
       
  1440 zfwrite_block(int fd, char *bf, off_t sz, int tmout)
       
  1441 {
       
  1442     int n;
       
  1443     struct zfheader hdr;
       
  1444     off_t cnt;
       
  1445     char *bfptr;
       
  1446     /* we need the header */
       
  1447     do {
       
  1448 	hdr.bytes[0] = (sz & 0xff00) >> 8;
       
  1449 	hdr.bytes[1] = sz & 0xff;
       
  1450 	hdr.flags = sz ? 0 : ZFHD_EOFB;
       
  1451 	n = zfwrite(fd, (char *)&hdr, sizeof(hdr), tmout);
       
  1452     } while (n < 0 && errno == EINTR);
       
  1453     if (n != 3 && !zfdrrrring) {
       
  1454 	zwarnnam("zftp", "failure writing FTP block header", NULL, 0);
       
  1455 	return n;
       
  1456     }
       
  1457     bfptr = bf;
       
  1458     cnt = sz;
       
  1459     while (cnt) {
       
  1460 	n = zfwrite(fd, bfptr, cnt, tmout);
       
  1461 	if (n > 0) {
       
  1462 	    bfptr += n;
       
  1463 	    cnt -= n;
       
  1464 	} else if (n < 0 && (errflag || zfdrrrring || errno != EINTR))
       
  1465 	    return n;
       
  1466     }
       
  1467 
       
  1468     return sz;
       
  1469 }
       
  1470 
       
  1471 /*
       
  1472  * Move stuff from fdin to fdout, tidying up the data connection
       
  1473  * when finished.  The data connection could be either input or output:
       
  1474  * recv is 1 for receiving a file, 0 for sending.
       
  1475  *
       
  1476  * progress is 1 to use a progress meter.
       
  1477  * startat says how far in we're starting with a REST command.
       
  1478  *
       
  1479  * Since we're doing some buffering here anyway, we don't bother
       
  1480  * with a stdio layer.
       
  1481  */
       
  1482 
       
  1483 /**/
       
  1484 static int
       
  1485 zfsenddata(char *name, int recv, int progress, off_t startat)
       
  1486 {
       
  1487 #define ZF_BUFSIZE 32768
       
  1488 #define ZF_ASCSIZE (ZF_BUFSIZE/2)
       
  1489     /* ret = 2 signals the local read/write failed, so send abort */
       
  1490     int n, ret = 0, gotack = 0, fdin, fdout, fromasc = 0, toasc = 0;
       
  1491     int rtmout = 0, wtmout = 0;
       
  1492     char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr;
       
  1493     off_t sofar = 0, last_sofar = 0;
       
  1494     readwrite_t read_ptr = zfread, write_ptr = zfwrite;
       
  1495     Eprog prog;
       
  1496 
       
  1497     if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
       
  1498 	/*
       
  1499 	 * progress to set up:  ZFTP_COUNT is zero.
       
  1500 	 * We do this here in case we needed to wait for a RETR
       
  1501 	 * command to tell us how many bytes are coming.
       
  1502 	 */
       
  1503 	int osc = sfcontext;
       
  1504 
       
  1505 	sfcontext = SFC_HOOK;
       
  1506 	doshfunc("zftp_progress", prog, NULL, 0, 1);
       
  1507 	sfcontext = osc;
       
  1508 	/* Now add in the bit of the file we've got/sent already */
       
  1509 	sofar = last_sofar = startat;
       
  1510     }
       
  1511     if (recv) {
       
  1512 	fdin = zfsess->dfd;
       
  1513 	fdout = 1;
       
  1514 	rtmout = getiparam("ZFTP_TMOUT");
       
  1515 	if (ZFST_CTYP(zfstatusp[zfsessno]) == ZFST_ASCI)
       
  1516 	    fromasc = 1;
       
  1517 	if (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC)
       
  1518 	    read_ptr = zfread_block;
       
  1519     } else {
       
  1520 	fdin = 0;
       
  1521 	fdout = zfsess->dfd;
       
  1522 	wtmout = getiparam("ZFTP_TMOUT");
       
  1523 	if (ZFST_CTYP(zfstatusp[zfsessno]) == ZFST_ASCI)
       
  1524 	    toasc = 1;
       
  1525 	if (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC)
       
  1526 	    write_ptr = zfwrite_block;
       
  1527     }
       
  1528 
       
  1529     if (toasc)
       
  1530 	ascbuf = zalloc(ZF_ASCSIZE);
       
  1531     zfpipe();
       
  1532     zfread_eof = 0;
       
  1533     while (!ret && !zfread_eof) {
       
  1534 	n = (toasc) ? read_ptr(fdin, ascbuf, ZF_ASCSIZE, rtmout)
       
  1535 	    : read_ptr(fdin, lsbuf, ZF_BUFSIZE, rtmout);
       
  1536 	if (n > 0) {
       
  1537 	    char *iptr;
       
  1538 	    if (toasc) {
       
  1539 		/* \n -> \r\n it shouldn't happen to a dog. */
       
  1540 		char *iptr = ascbuf, *optr = lsbuf;
       
  1541 		int cnt = n;
       
  1542 		while (cnt--) {
       
  1543 		    if (*iptr == '\n') {
       
  1544 			*optr++ = '\r';
       
  1545 			n++;
       
  1546 		    }
       
  1547 		    *optr++ = *iptr++;
       
  1548 		}
       
  1549 	    }
       
  1550 	    if (fromasc && (iptr = memchr(lsbuf, '\r', n))) {
       
  1551 		/* \r\n -> \n */
       
  1552 		char *optr = iptr;
       
  1553 		int cnt = n - (iptr - lsbuf);
       
  1554 		while (cnt--) {
       
  1555 		    if (*iptr != '\r' || iptr[1] != '\n') {
       
  1556 			*optr++ = *iptr;
       
  1557 		    } else
       
  1558 			n--;
       
  1559 		    iptr++;
       
  1560 		}
       
  1561 	    }
       
  1562 	    optr = lsbuf;
       
  1563 
       
  1564 	    sofar += n;
       
  1565 
       
  1566 	    for (;;) {
       
  1567 		/*
       
  1568 		 * in principle, write can be interrupted after
       
  1569 		 * safely writing some bytes, and will return the
       
  1570 		 * number already written, which may not be the
       
  1571 		 * complete buffer.  so make this robust.  they call me
       
  1572 		 * `robustness stephenson'.  in my dreams.
       
  1573 		 */
       
  1574 		int newn = write_ptr(fdout, optr, n, wtmout);
       
  1575 		if (newn == n)
       
  1576 		    break;
       
  1577 		if (newn < 0) {
       
  1578 		    /*
       
  1579 		     * The somewhat contorted test here (for write)
       
  1580 		     * and below (for read) means:
       
  1581 		     * real error if
       
  1582 		     *  - errno is set and it's not just an interrupt, or
       
  1583 		     *  - errflag is set, probably due to CTRL-c, or
       
  1584 		     *  - zfdrrrring is set, due to the alarm going off.
       
  1585 		     * print an error message if
       
  1586 		     *  - not a timeout, since that was reported, and
       
  1587 		     *    either
       
  1588 		     *    - a non-interactive shell, where we don't
       
  1589 		     *      know what happened otherwise
       
  1590 		     *    - or both of
       
  1591 		     *      - not errflag, i.e. CTRL-c or what have you,
       
  1592 		     *        since the user probably knows about that, and
       
  1593 		     *      - not a SIGPIPE, since usually people are
       
  1594 		     *        silent about those when going to pagers
       
  1595 		     *        (if you quit less or more in the middle
       
  1596 		     *        and see an error message you think `I
       
  1597 		     *        shouldn't have done that').
       
  1598 		     *
       
  1599 		     * If we didn't print an error message here,
       
  1600 		     * and were going to do an abort (ret == 2)
       
  1601 		     * because the error happened on the local end
       
  1602 		     * of the connection, set ret to 3 and don't print
       
  1603 		     * the 'aborting...' either.
       
  1604 		     *
       
  1605 		     * There must be a better way of doing this.
       
  1606 		     */
       
  1607 		    if (errno != EINTR || errflag || zfdrrrring) {
       
  1608 			if (!zfdrrrring &&
       
  1609 			    (!interact || (!errflag && errno != EPIPE))) {
       
  1610 			    ret = recv ? 2 : 1;
       
  1611 			    zwarnnam(name, "write failed: %e", NULL, errno);
       
  1612 			} else
       
  1613 			    ret = recv ? 3 : 1;
       
  1614 			break;
       
  1615 		    }
       
  1616 		    continue;
       
  1617 		}
       
  1618 		optr += newn;
       
  1619 		n -= newn;
       
  1620 	    }
       
  1621 	} else if (n < 0) {
       
  1622 	    if (errno != EINTR || errflag || zfdrrrring) {
       
  1623 		if (!zfdrrrring &&
       
  1624 		    (!interact || (!errflag && errno != EPIPE))) {
       
  1625 		    ret = recv ? 1 : 2;
       
  1626 		    zwarnnam(name, "read failed: %e", NULL, errno);
       
  1627 		} else
       
  1628 		    ret = recv ? 1 : 3;
       
  1629 		break;
       
  1630 	    }
       
  1631 	} else
       
  1632 	    break;
       
  1633 	if (!ret && sofar != last_sofar && progress &&
       
  1634 	    (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
       
  1635 	    int osc = sfcontext;
       
  1636 
       
  1637 	    zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER);
       
  1638 	    sfcontext = SFC_HOOK;
       
  1639 	    doshfunc("zftp_progress", prog, NULL, 0, 1);
       
  1640 	    sfcontext = osc;
       
  1641 	    last_sofar = sofar;
       
  1642 	}
       
  1643     }
       
  1644     zfunpipe();
       
  1645     /*
       
  1646      * At this point any timeout was on the data connection,
       
  1647      * so we don't need to force the control connection to close.
       
  1648      */
       
  1649     zfdrrrring = 0;
       
  1650     if (!errflag && !ret && !recv &&
       
  1651 	ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC) {
       
  1652 	/* send an end-of-file marker block */
       
  1653 	ret = (zfwrite_block(fdout, lsbuf, 0, wtmout) < 0);
       
  1654     }
       
  1655     if (errflag || ret > 1) {
       
  1656 	/*
       
  1657 	 * some error occurred, maybe a keyboard interrupt, or
       
  1658 	 * a local file/pipe handling problem.
       
  1659 	 * send an abort.
       
  1660 	 *
       
  1661 	 * safest to block all signals here?  can get frustrating if
       
  1662 	 * we're waiting for an abort.  don't I know.  let's start
       
  1663 	 * off just by blocking SIGINT's.
       
  1664 	 *
       
  1665 	 * maybe the timeout for the abort should be shorter than
       
  1666 	 * for normal commands.  and what about aborting after
       
  1667 	 * we had a timeout on the data connection, is that
       
  1668 	 * really a good idea?
       
  1669 	 */
       
  1670 	/* RFC 959 says this is what to send */
       
  1671 	unsigned char msg[4] = { IAC, IP, IAC, SYNCH };
       
  1672 
       
  1673 	if (ret == 2)
       
  1674 	    zwarnnam(name, "aborting data transfer...", NULL, 0);
       
  1675 
       
  1676 	holdintr();
       
  1677 
       
  1678 	/* the following is black magic, as far as I'm concerned. */
       
  1679 	/* what are we going to do if it fails?  not a lot, actually. */
       
  1680 	send(zfsess->control->fd, (char *)msg, 3, 0);
       
  1681 	send(zfsess->control->fd, (char *)msg+3, 1, MSG_OOB);
       
  1682 
       
  1683 	zfsendcmd("ABOR\r\n");
       
  1684 	if (lastcode == 226) {
       
  1685 	    /*
       
  1686 	     * 226 is supposed to mean the transfer got sent OK after
       
  1687 	     * all, and the abort got ignored, at least that's what
       
  1688 	     * rfc959 seems to be saying.  but in fact what can happen
       
  1689 	     * is the transfer finishes (at least as far as the
       
  1690 	     * server's concerned) and it's response is waiting, then
       
  1691 	     * the abort gets sent, and we need to mop up a response to
       
  1692 	     * that.  so actually in most cases we get two replies
       
  1693 	     * anyway.  we could test if we had select() on all hosts.
       
  1694 	     */
       
  1695 	    /* gotack = 1; */
       
  1696 	    /*
       
  1697 	     * we'd better leave errflag, since we don't know
       
  1698 	     * where it came from.  maybe the user wants to abort
       
  1699 	     * a whole script or function.
       
  1700 	     */
       
  1701 	} else
       
  1702 	    ret = 1;
       
  1703 
       
  1704 	noholdintr();
       
  1705     }
       
  1706 	
       
  1707     if (toasc)
       
  1708 	zfree(ascbuf, ZF_ASCSIZE);
       
  1709     zfclosedata();
       
  1710     if (!gotack && zfgetmsg() > 2)
       
  1711 	ret = 1;
       
  1712     return ret != 0;
       
  1713 }
       
  1714 
       
  1715 /* Open a new control connection, i.e. start a new FTP session */
       
  1716 
       
  1717 /**/
       
  1718 static int
       
  1719 zftp_open(char *name, char **args, int flags)
       
  1720 {
       
  1721     struct protoent *zprotop;
       
  1722     struct servent *zservp;
       
  1723     struct hostent *zhostp = NULL;
       
  1724     char **addrp, *fname, *tmpptr, *portnam = "ftp";
       
  1725     char *hostnam, *hostsuffix;
       
  1726     int err, tmout, port = -1;
       
  1727     ZSOCKLEN_T  len;
       
  1728     int herrno, af, hlen;
       
  1729 
       
  1730     if (!*args) {
       
  1731 	if (zfsess->userparams)
       
  1732 	    args = zfsess->userparams;
       
  1733 	else {
       
  1734 	    zwarnnam(name, "no host specified", NULL, 0);
       
  1735 	    return 1;
       
  1736 	}
       
  1737     }
       
  1738 
       
  1739     /*
       
  1740      * Close the existing connection if any.
       
  1741      * Probably this is the safest thing to do.  It's possible
       
  1742      * a `QUIT' will hang, though.
       
  1743      */
       
  1744     if (zfsess->control)
       
  1745 	zfclose(0);
       
  1746 
       
  1747     hostnam = dupstring(args[0]);
       
  1748     /*
       
  1749      * Check for IPv6 address in square brackets (RFC2732).
       
  1750      * We are more lenient and allow any form for the host here.
       
  1751      */
       
  1752     if (hostnam[0] == '[') {
       
  1753 	hostnam++;
       
  1754 	hostsuffix = strchr(hostnam, ']');
       
  1755 	if (!hostsuffix || (hostsuffix[1] && hostsuffix[1] != ':')) {
       
  1756 	    zwarnnam(name, "Invalid host format: %s", hostnam, 0);
       
  1757 	    return 1;
       
  1758 	}
       
  1759 	*hostsuffix++ = '\0';
       
  1760     }
       
  1761     else
       
  1762 	hostsuffix = hostnam;
       
  1763 
       
  1764     if ((tmpptr = strchr(hostsuffix, ':'))) {
       
  1765 	char *endptr;
       
  1766 
       
  1767 	*tmpptr++ = '\0';
       
  1768 	port = (int)zstrtol(tmpptr, &endptr, 10);
       
  1769 	/*
       
  1770 	 * If the port is not numeric, look it up by name below.
       
  1771 	 */
       
  1772 	if (*endptr) {
       
  1773 	    portnam = tmpptr;
       
  1774 	    port = -1;
       
  1775 	}
       
  1776 #if defined(HAVE_NTOHS) && defined(HAVE_HTONS)
       
  1777 	else {
       
  1778 	    port = (int)htons((unsigned short)port);
       
  1779 	}
       
  1780 #endif
       
  1781     }
       
  1782 
       
  1783     /* this is going to give 0.  why bother? */
       
  1784     zprotop = getprotobyname("tcp");
       
  1785     if (!zprotop) {
       
  1786 	zwarnnam(name, "Can't find protocol TCP (is your network functional)?",
       
  1787 		 NULL, 0);
       
  1788 	return 1;
       
  1789     }
       
  1790     if (port < 0)
       
  1791 	zservp = getservbyname(portnam, "tcp");
       
  1792     else
       
  1793 	zservp = getservbyport(port, "tcp");
       
  1794 
       
  1795     if (!zprotop || !zservp) {
       
  1796 	zwarnnam(name, "Can't find port for service `%s'", portnam, 0);
       
  1797 	return 1;
       
  1798     }
       
  1799 
       
  1800     /* don't try talking to server yet */
       
  1801     zcfinish = 2;
       
  1802 
       
  1803     /*
       
  1804      * This sets an alarm for the whole process, getting the host name
       
  1805      * as well as connecting.  Arguably you could time them out separately. 
       
  1806      */
       
  1807     tmout = getiparam("ZFTP_TMOUT");
       
  1808     if (setjmp(zfalrmbuf)) {
       
  1809 	char *hname;
       
  1810 	alarm(0);
       
  1811 	queue_signals();
       
  1812 	if ((hname = getsparam("ZFTP_HOST")) && *hname) 
       
  1813 	    zwarnnam(name, "timeout connecting to %s", hname, 0);
       
  1814 	else
       
  1815 	    zwarnnam(name, "timeout on host name lookup", NULL, 0);
       
  1816 	unqueue_signals();
       
  1817 	zfclose(0);
       
  1818 	return 1;
       
  1819     }
       
  1820     zfalarm(tmout);
       
  1821 
       
  1822 #ifdef SUPPORT_IPV6
       
  1823     for(af=AF_INET6; 1; af = AF_INET)
       
  1824 # define SUCCEEDED() break
       
  1825 # define FAILED() if(af == AF_INET) { } else continue
       
  1826 #else
       
  1827 	af = AF_INET;
       
  1828 # define SUCCEEDED() do { } while(0)
       
  1829 # define FAILED() do { } while(0)
       
  1830 #endif
       
  1831     {
       
  1832 	off_t tcp_port;
       
  1833 
       
  1834 	zhostp = zsh_getipnodebyname(hostnam, af, 0, &herrno);
       
  1835 	if (!zhostp || errflag) {
       
  1836 	    /* should use herror() here if available, but maybe
       
  1837 	     * needs configure test. on AIX it's present but not
       
  1838 	     * in headers.
       
  1839 	     * 
       
  1840 	     * on the other hand, herror() is obsolete
       
  1841 	     */
       
  1842 	    FAILED();
       
  1843 	    zwarnnam(name, "host not found: %s", hostnam, 0);
       
  1844 	    alarm(0);
       
  1845 	    return 1;
       
  1846 	}
       
  1847 	zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY);
       
  1848 	/* careful with pointer types */
       
  1849 #if defined(HAVE_NTOHS) && defined(HAVE_HTONS)
       
  1850 	tcp_port = (off_t)ntohs((unsigned short)zservp->s_port);
       
  1851 #else
       
  1852 	tcp_port = (off_t)zservp->s_port;
       
  1853 #endif
       
  1854 	zfsetparam("ZFTP_PORT", &tcp_port, ZFPM_READONLY|ZFPM_INTEGER);
       
  1855 
       
  1856 #ifdef SUPPORT_IPV6
       
  1857 	if(af == AF_INET6) {
       
  1858 	    hlen = 16;
       
  1859 	} else
       
  1860 #endif /* SUPPORT_IPV6 */
       
  1861 	{
       
  1862 	    hlen = 4;
       
  1863 	}
       
  1864 
       
  1865 	zfsess->control = tcp_socket(af, SOCK_STREAM, 0, ZTCP_ZFTP);
       
  1866 
       
  1867 	if (!(zfsess->control) || (zfsess->control->fd < 0)) {
       
  1868 	    if (zfsess->control) {
       
  1869 		tcp_close(zfsess->control);
       
  1870 		zfsess->control = NULL;
       
  1871 	    }
       
  1872 	    freehostent(zhostp);
       
  1873 	    zfunsetparam("ZFTP_HOST");
       
  1874 	    zfunsetparam("ZFTP_PORT");
       
  1875 	    FAILED();
       
  1876 	    zwarnnam(name, "socket failed: %e", NULL, errno);
       
  1877 	    alarm(0);
       
  1878 	    return 1;
       
  1879 	}
       
  1880 	/* counts as `open' so long as it's not negative */
       
  1881 	zfnopen++;
       
  1882 
       
  1883 	/*
       
  1884 	 * now connect the socket.  manual pages all say things like `this is
       
  1885 	 * all explained oh-so-wonderfully in some other manual page'.  not.
       
  1886 	 */
       
  1887 
       
  1888 	err = 1;
       
  1889 
       
  1890 	/* try all possible IP's */
       
  1891 	for (addrp = zhostp->h_addr_list; err && *addrp; addrp++) {
       
  1892 	    if(hlen != zhostp->h_length)
       
  1893 		zwarnnam(name, "address length mismatch", NULL, 0);
       
  1894 	    do {
       
  1895 		err = tcp_connect(zfsess->control, *addrp, zhostp, zservp->s_port);	    } while (err && errno == EINTR && !errflag);
       
  1896 	    /* you can check whether it's worth retrying here */
       
  1897 	}
       
  1898 
       
  1899 	if (err) {
       
  1900 	    freehostent(zhostp);
       
  1901 	    zfclose(0);
       
  1902 	    FAILED();
       
  1903 	    zwarnnam(name, "connect failed: %e", NULL, errno);
       
  1904 	    alarm(0);
       
  1905 	    return 1;
       
  1906 	}
       
  1907 
       
  1908 	SUCCEEDED();
       
  1909     }
       
  1910     alarm(0);
       
  1911     {
       
  1912 #ifdef SUPPORT_IPV6
       
  1913 	char pbuf[INET6_ADDRSTRLEN];
       
  1914 #else
       
  1915 	char pbuf[INET_ADDRSTRLEN];
       
  1916 #endif
       
  1917 	addrp--;
       
  1918 	zsh_inet_ntop(af, *addrp, pbuf, sizeof(pbuf));
       
  1919 	zfsetparam("ZFTP_IP", ztrdup(pbuf), ZFPM_READONLY);
       
  1920     }
       
  1921     freehostent(zhostp);
       
  1922     /* now we can talk to the control connection */
       
  1923     zcfinish = 0;
       
  1924 
       
  1925     /*
       
  1926      * Move the fd out of the user-visible range.  We need to do
       
  1927      * this after the connect() on some systems.
       
  1928      */
       
  1929     zfsess->control->fd = zfmovefd(zfsess->control->fd);
       
  1930 
       
  1931 #if defined(F_SETFD) && defined(FD_CLOEXEC)
       
  1932     /* If the shell execs a program, we don't want this fd left open. */
       
  1933     fcntl(zfsess->control->fd, F_SETFD, FD_CLOEXEC);
       
  1934 #endif
       
  1935 
       
  1936     len = sizeof(zfsess->control->sock);
       
  1937     if (getsockname(zfsess->control->fd, (struct sockaddr *)&zfsess->control->sock, &len) < 0) {
       
  1938 	zwarnnam(name, "getsockname failed: %e", NULL, errno);
       
  1939 	zfclose(0);
       
  1940 	return 1;
       
  1941     }
       
  1942     /* nice to get some options right, ignore if they don't work */
       
  1943 #ifdef SO_OOBINLINE
       
  1944     /*
       
  1945      * this says we want messages in line.  maybe sophisticated people
       
  1946      * do clever things with SIGURG.
       
  1947      */
       
  1948     len = 1;
       
  1949     setsockopt(zfsess->control->fd, SOL_SOCKET, SO_OOBINLINE,
       
  1950 	       (char *)&len, sizeof(len));
       
  1951 #endif
       
  1952 #if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
       
  1953     /* for control connection we want low delay.  please don't laugh. */
       
  1954     len = IPTOS_LOWDELAY;
       
  1955     setsockopt(zfsess->control->fd, IPPROTO_IP, IP_TOS, (char *)&len, sizeof(len));
       
  1956 #endif
       
  1957 
       
  1958     /*
       
  1959      * We use stdio with line buffering for convenience on input.
       
  1960      * On output, we can just dump a complete message to the fd via write().
       
  1961      */
       
  1962     zfsess->cin = fdopen(zfsess->control->fd, "r");
       
  1963 
       
  1964     if (!zfsess->cin) {
       
  1965 	zwarnnam(name, "file handling error", NULL, 0);
       
  1966 	zfclose(0);
       
  1967 	return 1;
       
  1968     }
       
  1969 
       
  1970 #ifdef _IONBF
       
  1971     setvbuf(zfsess->cin, NULL, _IONBF, 0);
       
  1972 #else
       
  1973     setlinebuf(zfsess->cin);
       
  1974 #endif
       
  1975 
       
  1976     /*
       
  1977      * now see what the remote server has to say about that.
       
  1978      */
       
  1979     if (zfgetmsg() >= 4) {
       
  1980 	zfclose(0);
       
  1981 	return 1;
       
  1982     }
       
  1983 
       
  1984     zfsess->has_size = zfsess->has_mdtm = ZFCP_UNKN;
       
  1985     zfsess->dfd = -1;
       
  1986     /* initial status: open, ASCII data, stream mode 'n' stuff */
       
  1987     zfstatusp[zfsessno] = 0;
       
  1988 
       
  1989     /*
       
  1990      * Open file for saving the current status.
       
  1991      * We keep this open at the end of the session because
       
  1992      * it is used to store the status for all sessions.
       
  1993      * However, it is closed whenever there are no connections open.
       
  1994      */
       
  1995     if (zfstatfd == -1) {
       
  1996 	zfstatfd = gettempfile(NULL, 1, &fname);
       
  1997 	DPUTS(zfstatfd == -1, "zfstatfd not created");
       
  1998 #if defined(F_SETFD) && defined(FD_CLOEXEC)
       
  1999 	/* If the shell execs a program, we don't want this fd left open. */
       
  2000 	fcntl(zfstatfd, F_SETFD, FD_CLOEXEC);
       
  2001 #endif
       
  2002 	unlink(fname);
       
  2003     }
       
  2004 
       
  2005     if (zfsess->control->fd == -1) {
       
  2006 	/* final paranoid check */
       
  2007 	tcp_close(zfsess->control);
       
  2008 	zfsess->control = NULL;
       
  2009 	zfnopen--;
       
  2010     } else {
       
  2011 	zfsetparam("ZFTP_MODE", ztrdup("S"), ZFPM_READONLY);
       
  2012 	/* if remaining arguments, use them to log in. */
       
  2013 	if (*++args)
       
  2014 	    return zftp_login(name, args, flags);
       
  2015     }
       
  2016     /* if something wayward happened, connection was already closed */
       
  2017     return !zfsess->control;
       
  2018 }
       
  2019 
       
  2020 /*
       
  2021  * Read a parameter string, with a prompt if reading from stdin.
       
  2022  * The returned string is on the heap.
       
  2023  * If noecho, turn off ECHO mode while reading.
       
  2024  */
       
  2025 
       
  2026 /**/
       
  2027 static char *
       
  2028 zfgetinfo(char *prompt, int noecho)
       
  2029 {
       
  2030     int resettty = 0;
       
  2031     /* 256 characters should be enough, hardly worth allocating
       
  2032      * a password string byte by byte
       
  2033      */
       
  2034     char instr[256], *strret;
       
  2035     int len;
       
  2036 
       
  2037     /*
       
  2038      * Only print the prompt if getting info from a tty.  Of
       
  2039      * course, we don't know if stderr has been redirected, but
       
  2040      * that seems a minor point.
       
  2041      */
       
  2042     if (isatty(0)) {
       
  2043 	if (noecho) {
       
  2044 	    /* hmmm... all this great big shell and we have to read
       
  2045 	     * something with no echo by ourselves.
       
  2046 	     * bin_read() is far to complicated for our needs.
       
  2047 	     * we could use zread(), but that relies on static
       
  2048 	     * variables, so someone doesn't want that to happen.
       
  2049 	     *
       
  2050 	     * this is modified from setcbreak() in utils.c,
       
  2051 	     * except I don't see any point in using cbreak mode
       
  2052 	     */
       
  2053 	    struct ttyinfo ti;
       
  2054 
       
  2055 	    ti = shttyinfo;
       
  2056 #ifdef HAS_TIO
       
  2057 	    ti.tio.c_lflag &= ~ECHO;
       
  2058 #else
       
  2059 	    ti.sgttyb.sg_flags &= ~ECHO;
       
  2060 #endif
       
  2061 	    settyinfo(&ti);
       
  2062 	    resettty = 1;
       
  2063 	}
       
  2064 	fflush(stdin);
       
  2065 	fputs(prompt, stderr);
       
  2066 	fflush(stderr);
       
  2067     }
       
  2068 
       
  2069     fgets(instr, 256, stdin);
       
  2070     if (instr[len = strlen(instr)-1] == '\n')
       
  2071 	instr[len] = '\0';
       
  2072 
       
  2073     strret = dupstring(instr);
       
  2074 
       
  2075     if (resettty) {
       
  2076 	/* '\n' didn't get echoed */
       
  2077 	fputc('\n', stdout);
       
  2078 	fflush(stdout);
       
  2079 	settyinfo(&shttyinfo);
       
  2080     }
       
  2081 
       
  2082     return strret;
       
  2083 }
       
  2084 
       
  2085 /*
       
  2086  * set params for an open with no arguments.
       
  2087  * this allows easy re-opens.
       
  2088  */
       
  2089 
       
  2090 /**/
       
  2091 static int
       
  2092 zftp_params(UNUSED(char *name), char **args, UNUSED(int flags))
       
  2093 {
       
  2094     char *prompts[] = { "Host: ", "User: ", "Password: ", "Account: " };
       
  2095     char **aptr, **newarr;
       
  2096     int i, j, len;
       
  2097 
       
  2098     if (!*args) {
       
  2099 	if (zfsess->userparams) {
       
  2100 	    for (aptr = zfsess->userparams, i = 0; *aptr; aptr++, i++) {
       
  2101 		if (i == 2) {
       
  2102 		    len = strlen(*aptr);
       
  2103 		    for (j = 0; j < len; j++)
       
  2104 			fputc('*', stdout);
       
  2105 		    fputc('\n', stdout);
       
  2106 		} else
       
  2107 		    fprintf(stdout, "%s\n", *aptr);
       
  2108 	    }
       
  2109 	    return 0;
       
  2110 	} else
       
  2111 	    return 1;
       
  2112     }
       
  2113     if (!strcmp(*args, "-")) {
       
  2114 	if (zfsess->userparams)
       
  2115 	    freearray(zfsess->userparams);
       
  2116 	zfsess->userparams = 0;
       
  2117 	return 0;
       
  2118     }
       
  2119     len = arrlen(args);
       
  2120     newarr = (char **)zshcalloc((len+1)*sizeof(char *));
       
  2121     for (aptr = args, i = 0; *aptr && !errflag; aptr++, i++) {
       
  2122 	char *str;
       
  2123 	if (**aptr == '?')
       
  2124 	    str = zfgetinfo((*aptr)[1] ? (*aptr+1) : prompts[i], i == 2);
       
  2125 	else
       
  2126 	    str = (**aptr == '\\') ? *aptr+1 : *aptr;
       
  2127 	newarr[i] = ztrdup(str);
       
  2128     }
       
  2129     if (errflag) {
       
  2130 	/* maybe user CTRL-c'd in the middle somewhere */
       
  2131 	for (aptr = newarr; *aptr; aptr++)
       
  2132 	    zsfree(*aptr);
       
  2133 	zfree(newarr, len+1);
       
  2134 	return 1;
       
  2135     }
       
  2136     if (zfsess->userparams)
       
  2137 	freearray(zfsess->userparams);
       
  2138     zfsess->userparams = newarr;
       
  2139     return 0;
       
  2140 }
       
  2141 
       
  2142 /* login a user:  often called as part of the open sequence */
       
  2143 
       
  2144 /**/
       
  2145 static int
       
  2146 zftp_login(char *name, char **args, UNUSED(int flags))
       
  2147 {
       
  2148     char *ucmd, *passwd = NULL, *acct = NULL;
       
  2149     char *user, tbuf[2] = "X";
       
  2150     int stopit;
       
  2151 
       
  2152     if ((zfstatusp[zfsessno] & ZFST_LOGI) && zfsendcmd("REIN\r\n") >= 4)
       
  2153 	return 1;
       
  2154 
       
  2155     zfstatusp[zfsessno] &= ~ZFST_LOGI;
       
  2156     if (*args) {
       
  2157 	user = *args++;
       
  2158     } else {
       
  2159 	user = zfgetinfo("User: ", 0);
       
  2160     }
       
  2161 
       
  2162     ucmd = tricat("USER ", user, "\r\n");
       
  2163     stopit = 0;
       
  2164 
       
  2165     if (zfsendcmd(ucmd) == 6)
       
  2166 	stopit = 2;
       
  2167 
       
  2168     while (!stopit && !errflag) {
       
  2169 	switch (lastcode) {
       
  2170 	case 230: /* user logged in */
       
  2171 	case 202: /* command not implemented, don't care */
       
  2172 	    stopit = 1;
       
  2173 	    break;
       
  2174 
       
  2175 	case 331: /* need password */
       
  2176 	    if (*args)
       
  2177 		passwd = *args++;
       
  2178 	    else
       
  2179 		passwd = zfgetinfo("Password: ", 1);
       
  2180 	    zsfree(ucmd);
       
  2181 	    ucmd = tricat("PASS ", passwd, "\r\n");
       
  2182 	    if (zfsendcmd(ucmd) == 6)
       
  2183 		stopit = 2;
       
  2184 	    break;
       
  2185 
       
  2186 	case 332: /* need account */
       
  2187 	case 532:
       
  2188 	    if (*args)
       
  2189 		acct = *args++;
       
  2190 	    else
       
  2191 		acct = zfgetinfo("Account: ", 0);
       
  2192 	    zsfree(ucmd);
       
  2193 	    ucmd = tricat("ACCT ", passwd, "\r\n");
       
  2194 	    if (zfsendcmd(ucmd) == 6)
       
  2195 		stopit = 2;
       
  2196 	    break;
       
  2197 
       
  2198 	case 421: /* service not available, so closed anyway */
       
  2199 	case 501: /* syntax error */
       
  2200 	case 503: /* bad commands */
       
  2201 	case 530: /* not logged in */
       
  2202 	case 550: /* random can't-do-that */
       
  2203 	default:  /* whatever, should flag this as bad karma */
       
  2204 	    /* need more diagnostics here */
       
  2205 	    stopit = 2;
       
  2206 	    break;
       
  2207 	}
       
  2208     }
       
  2209 
       
  2210     zsfree(ucmd);
       
  2211     if (!zfsess->control)
       
  2212 	return 1;
       
  2213     if (stopit == 2 || (lastcode != 230 && lastcode != 202)) {
       
  2214 	zwarnnam(name, "login failed", NULL, 0);
       
  2215 	return 1;
       
  2216     }
       
  2217 
       
  2218     if (*args) {
       
  2219 	int cnt;
       
  2220 	for (cnt = 0; *args; args++)
       
  2221 	    cnt++;
       
  2222 	zwarnnam(name, "warning: %d comand arguments not used\n", NULL, cnt);
       
  2223     }
       
  2224     zfstatusp[zfsessno] |= ZFST_LOGI;
       
  2225     zfsetparam("ZFTP_USER", ztrdup(user), ZFPM_READONLY);
       
  2226     if (acct)
       
  2227 	zfsetparam("ZFTP_ACCOUNT", ztrdup(acct), ZFPM_READONLY);
       
  2228 
       
  2229     /*
       
  2230      * Now find out what system we're connected to. Some systems
       
  2231      * won't let us do this until we're logged in; it's fairly safe
       
  2232      * to delay it here for all systems.
       
  2233      */
       
  2234     if (!(zfprefs & ZFPF_DUMB) && !(zfstatusp[zfsessno] & ZFST_SYST)) {
       
  2235 	if (zfsendcmd("SYST\r\n") == 2) {
       
  2236 	    char *ptr = lastmsg, *eptr, *systype;
       
  2237 	    for (eptr = ptr; *eptr; eptr++)
       
  2238 		;
       
  2239 	    systype = ztrduppfx(ptr, eptr-ptr);
       
  2240 	    if (!strncmp(systype, "UNIX Type: L8", 13)) {
       
  2241 		/*
       
  2242 		 * Use binary for transfers.  This simple test saves much
       
  2243 		 * hassle for all concerned, particularly me.
       
  2244 		 *
       
  2245 		 * We could set this based just on the UNIX part,
       
  2246 		 * but I don't really know the consequences of that.
       
  2247 		 */
       
  2248 		zfstatusp[zfsessno] |= ZFST_IMAG;
       
  2249 	    }
       
  2250 	    zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
       
  2251 	}
       
  2252 	zfstatusp[zfsessno] |= ZFST_SYST;
       
  2253     }
       
  2254     tbuf[0] = (ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI) ? 'A' : 'I';
       
  2255     zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY);
       
  2256 
       
  2257     /*
       
  2258      * Get the directory.  This is possibly an unnecessary overhead, of
       
  2259      * course, but when you're being driven by shell functions there's
       
  2260      * just no way of telling.
       
  2261      */
       
  2262     return zfgetcwd();
       
  2263 }
       
  2264 
       
  2265 /*
       
  2266  * See if the server wants to tell us something.  On a timeout, we usually
       
  2267  * have a `421 Timeout' or something such waiting for us, so we read
       
  2268  * it here.  As well as being called explicitly by the user
       
  2269  * (precmd is a very good place for this, it's cheap since it has
       
  2270  * no network overhead), we call it in the bin_zftp front end if we
       
  2271  * have a connection and weren't going to call it anyway.
       
  2272  *
       
  2273  * Poll-free and select-free systems are few and far between these days,
       
  2274  * but I'm willing to consider suggestions.
       
  2275  */
       
  2276 
       
  2277 /**/
       
  2278 static int
       
  2279 zftp_test(UNUSED(char *name), UNUSED(char **args), UNUSED(int flags))
       
  2280 {
       
  2281 #if defined(HAVE_POLL) || defined(HAVE_SELECT)
       
  2282     int ret;
       
  2283 # ifdef HAVE_POLL
       
  2284     struct pollfd pfd;
       
  2285 # else
       
  2286     fd_set f;
       
  2287     struct timeval tv;
       
  2288 # endif /* HAVE_POLL */
       
  2289 
       
  2290     if (!zfsess->control)
       
  2291 	return 1;
       
  2292 
       
  2293 # ifdef HAVE_POLL
       
  2294 #  ifndef POLLIN
       
  2295     /* safety first, though I think POLLIN is more common */
       
  2296 #   define POLLIN POLLNORM
       
  2297 #  endif /* HAVE_POLL */
       
  2298     pfd.fd = zfsess->control->fd;
       
  2299     pfd.events = POLLIN;
       
  2300     if ((ret = poll(&pfd, 1, 0)) < 0 && errno != EINTR && errno != EAGAIN)
       
  2301 	zfclose(0);
       
  2302     else if (ret > 0 && pfd.revents) {
       
  2303 	/* handles 421 (maybe a bit noisily?) */
       
  2304 	zfgetmsg();
       
  2305     }
       
  2306 # else
       
  2307     FD_ZERO(&f);
       
  2308     FD_SET(zfsess->control->fd, &f);
       
  2309     tv.tv_sec = 0;
       
  2310     tv.tv_usec = 0;
       
  2311     if ((ret = select(zfsess->control->fd +1, (SELECT_ARG_2_T) &f,
       
  2312 		      NULL, NULL, &tv)) < 0
       
  2313 	&& errno != EINTR)
       
  2314 	zfclose(0);
       
  2315     else if (ret > 0) {
       
  2316 	/* handles 421 */
       
  2317 	zfgetmsg();
       
  2318     }
       
  2319 # endif /* HAVE_POLL */
       
  2320     /* if we have no zfsess->control, then we've just been dumped out. */
       
  2321     return zfsess->control ? 0 : 2;
       
  2322 #else
       
  2323     zfwarnnam(name, "not supported on this system.", NULL, 0);
       
  2324     return 3;
       
  2325 #endif /* defined(HAVE_POLL) || defined(HAVE_SELECT) */
       
  2326 }
       
  2327 
       
  2328 
       
  2329 /* do ls or dir on the remote directory */
       
  2330 
       
  2331 /**/
       
  2332 static int
       
  2333 zftp_dir(char *name, char **args, int flags)
       
  2334 {
       
  2335     /* maybe should be cleverer about handling arguments */
       
  2336     char *cmd;
       
  2337     int ret;
       
  2338 
       
  2339     /*
       
  2340      * RFC959 says this must be ASCII or EBCDIC, not image format.
       
  2341      * I rather suspect on a UNIX server we get away handsomely
       
  2342      * with doing everything, including this, as image.
       
  2343      */
       
  2344     zfsettype(ZFST_ASCI);
       
  2345 
       
  2346     cmd = zfargstring((flags & ZFTP_NLST) ? "NLST" : "LIST", args);
       
  2347     ret = zfgetdata(name, NULL, cmd, 0);
       
  2348     zsfree(cmd);
       
  2349     if (ret)
       
  2350 	return 1;
       
  2351 
       
  2352     fflush(stdout);		/* since we're now using fd 1 */
       
  2353     return zfsenddata(name, 1, 0, 0);
       
  2354 }
       
  2355 
       
  2356 /* change the remote directory */
       
  2357 
       
  2358 /**/
       
  2359 static int
       
  2360 zftp_cd(UNUSED(char *name), char **args, int flags)
       
  2361 {
       
  2362     /* change directory --- enhance to allow 'zftp cdup' */
       
  2363     int ret;
       
  2364 
       
  2365     if ((flags & ZFTP_CDUP) || !strcmp(*args, "..") ||
       
  2366 	!strcmp(*args, "../")) {
       
  2367 	ret = zfsendcmd("CDUP\r\n");
       
  2368     } else {
       
  2369 	char *cmd = tricat("CWD ", *args, "\r\n");
       
  2370 	ret = zfsendcmd(cmd);
       
  2371 	zsfree(cmd);
       
  2372     }
       
  2373     if (ret > 2)
       
  2374 	return 1;
       
  2375     /* sometimes the directory may be in the response. usually not. */
       
  2376     if (zfgetcwd())
       
  2377 	return 1;
       
  2378 
       
  2379     return 0;
       
  2380 }
       
  2381 
       
  2382 /* get the remote directory */
       
  2383 
       
  2384 /**/
       
  2385 static int
       
  2386 zfgetcwd(void)
       
  2387 {
       
  2388     char *ptr, *eptr;
       
  2389     int endc;
       
  2390     Eprog prog;
       
  2391 
       
  2392     if (zfprefs & ZFPF_DUMB)
       
  2393 	return 1;
       
  2394     if (zfsendcmd("PWD\r\n") > 2) {
       
  2395 	zfunsetparam("ZFTP_PWD");
       
  2396 	return 1;
       
  2397     }
       
  2398     ptr = lastmsg;
       
  2399     while (*ptr == ' ')
       
  2400 	ptr++;
       
  2401     if (!*ptr)			/* ultra safe */
       
  2402 	return 1;
       
  2403     if (*ptr == '"') {
       
  2404 	ptr++;
       
  2405 	endc = '"';
       
  2406     } else 
       
  2407 	endc = ' ';
       
  2408     for (eptr = ptr; *eptr && *eptr != endc; eptr++)
       
  2409 	;
       
  2410     zfsetparam("ZFTP_PWD", ztrduppfx(ptr, eptr-ptr), ZFPM_READONLY);
       
  2411 
       
  2412     /*
       
  2413      * This isn't so necessary if we're going to have a shell function
       
  2414      * front end.  By putting it here, and in close when ZFTP_PWD is unset,
       
  2415      * we at least cover the bases.
       
  2416      */
       
  2417     if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
       
  2418 	int osc = sfcontext;
       
  2419 
       
  2420 	sfcontext = SFC_HOOK;
       
  2421 	doshfunc("zftp_chpwd", prog, NULL, 0, 1);
       
  2422 	sfcontext = osc;
       
  2423     }
       
  2424     return 0;
       
  2425 }
       
  2426 
       
  2427 /*
       
  2428  * Set the type for the next transfer, usually image (binary) or ASCII.
       
  2429  */
       
  2430 
       
  2431 /**/
       
  2432 static int
       
  2433 zfsettype(int type)
       
  2434 {
       
  2435     char buf[] = "TYPE X\r\n";
       
  2436     if (ZFST_TYPE(type) == ZFST_CTYP(zfstatusp[zfsessno]))
       
  2437 	return 0;
       
  2438     buf[5] = (ZFST_TYPE(type) == ZFST_ASCI) ? 'A' : 'I';
       
  2439     if (zfsendcmd(buf) > 2)
       
  2440 	return 1;
       
  2441     zfstatusp[zfsessno] &= ~(ZFST_TMSK << ZFST_TBIT);
       
  2442     /* shift the type left to set the current type bits */;
       
  2443     zfstatusp[zfsessno] |= type << ZFST_TBIT;
       
  2444     return 0;
       
  2445 }
       
  2446 
       
  2447 /*
       
  2448  * Print or get a new type for the transfer.
       
  2449  * We don't actually set the type at this point.
       
  2450  */
       
  2451 
       
  2452 /**/
       
  2453 static int
       
  2454 zftp_type(char *name, char **args, int flags)
       
  2455 {
       
  2456     char *str, nt, tbuf[2] = "A";
       
  2457     if (flags & (ZFTP_TBIN|ZFTP_TASC)) {
       
  2458 	nt = (flags & ZFTP_TBIN) ? 'I' : 'A';
       
  2459     } else if (!(str = *args)) {
       
  2460 	/*
       
  2461 	 * Since this is supposed to be a low-level basis for
       
  2462 	 * an FTP system, just print the single code letter.
       
  2463 	 */
       
  2464 	printf("%c\n", (ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI) ?
       
  2465 	       'A' : 'I');
       
  2466 	fflush(stdout);
       
  2467 	return 0;
       
  2468     } else {
       
  2469 	nt = toupper(STOUC(*str));
       
  2470 	/*
       
  2471 	 * RFC959 specifies other types, but these are the only
       
  2472 	 * ones we know what to do with.
       
  2473 	 */
       
  2474 	if (str[1] || (nt != 'A' && nt != 'B' && nt != 'I')) {
       
  2475 	    zwarnnam(name, "transfer type %s not recognised", str, 0);
       
  2476 	    return 1;
       
  2477 	}
       
  2478 	
       
  2479 	if (nt == 'B')		/* binary = image */
       
  2480 	    nt = 'I';
       
  2481     }
       
  2482 
       
  2483     zfstatusp[zfsessno] &= ~ZFST_TMSK;
       
  2484     zfstatusp[zfsessno] |= (nt == 'I') ? ZFST_IMAG : ZFST_ASCI;
       
  2485     tbuf[0] = nt;
       
  2486     zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY);
       
  2487     return 0;
       
  2488 }
       
  2489 
       
  2490 /**/
       
  2491 static int
       
  2492 zftp_mode(char *name, char **args, UNUSED(int flags))
       
  2493 {
       
  2494     char *str, cmd[] = "MODE X\r\n";
       
  2495     int nt;
       
  2496 
       
  2497     if (!(str = *args)) {
       
  2498 	printf("%c\n", (ZFST_MODE(zfstatusp[zfsessno]) == ZFST_STRE) ?
       
  2499 	       'S' : 'B');
       
  2500 	fflush(stdout);
       
  2501 	return 0;
       
  2502     }
       
  2503     nt = str[0] = toupper(STOUC(*str));
       
  2504     if (str[1] || (nt != 'S' && nt != 'B')) {
       
  2505 	zwarnnam(name, "transfer mode %s not recognised", str, 0);
       
  2506 	return 1;
       
  2507     }
       
  2508     cmd[5] = (char) nt;
       
  2509     if (zfsendcmd(cmd) > 2)
       
  2510 	return 1;
       
  2511     zfstatusp[zfsessno] &= ZFST_MMSK;
       
  2512     zfstatusp[zfsessno] |= (nt == 'S') ? ZFST_STRE : ZFST_BLOC;
       
  2513     zfsetparam("ZFTP_MODE", ztrdup(str), ZFPM_READONLY);
       
  2514     return 0;
       
  2515 }
       
  2516 
       
  2517 /**/
       
  2518 static int
       
  2519 zftp_local(UNUSED(char *name), char **args, int flags)
       
  2520 {
       
  2521     int more = !!args[1], ret = 0, dofd = !*args;
       
  2522     while (*args || dofd) {
       
  2523 	off_t sz;
       
  2524 	char *mt;
       
  2525 	int newret = zfstats(*args, !(flags & ZFTP_HERE), &sz, &mt,
       
  2526 			     dofd ? 0 : -1);
       
  2527 	if (newret == 2)	/* at least one is not implemented */
       
  2528 	    return 2;
       
  2529 	else if (newret) {
       
  2530 	    ret = 1;
       
  2531 	    if (mt)
       
  2532 		zsfree(mt);
       
  2533 	    args++;
       
  2534 	    continue;
       
  2535 	}
       
  2536 	if (more) {
       
  2537 	    fputs(*args, stdout);
       
  2538 	    fputc(' ', stdout);
       
  2539 	}
       
  2540 #ifdef OFF_T_IS_64_BIT
       
  2541 	printf("%s %s\n", output64(sz), mt);
       
  2542 #else
       
  2543 	DPUTS(sizeof(sz) > 4, "Shell compiled with wrong off_t size");
       
  2544 	printf("%ld %s\n", sz, mt);
       
  2545 #endif
       
  2546 	zsfree(mt);
       
  2547 	if (dofd)
       
  2548 	    break;
       
  2549 	args++;
       
  2550     }
       
  2551     fflush(stdout);
       
  2552 
       
  2553     return ret;
       
  2554 }
       
  2555 
       
  2556 /*
       
  2557  * Generic transfer for get, put and append.
       
  2558  *
       
  2559  * Get sends all files to stdout, i.e. this is basically cat. It's up to a
       
  2560  * shell function driver to turn this into standard FTP-like commands.
       
  2561  *
       
  2562  * Put/append sends everything from stdin down the drai^H^H^Hata connection. 
       
  2563  * Slightly weird with multiple files in that it tries to read
       
  2564  * a separate complete file from stdin each time, which is
       
  2565  * only even potentially useful interactively.  But the only
       
  2566  * real alternative is just to allow one file at a time.
       
  2567  */
       
  2568 
       
  2569 /**/
       
  2570 static int
       
  2571 zftp_getput(char *name, char **args, int flags)
       
  2572 {
       
  2573     int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1;
       
  2574     char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR ";
       
  2575     Eprog prog;
       
  2576 
       
  2577     /*
       
  2578      * At this point I'd like to set progress to 0 if we're
       
  2579      * backgrounded, since it's hard for the user to find out.
       
  2580      * It turns out it's hard enough for us to find out.
       
  2581      * The problem is that zsh clears it's job table, so we
       
  2582      * just don't know if we're some forked shell in a pipeline
       
  2583      * somewhere or in the background.  This seems to me a problem.
       
  2584      */
       
  2585 
       
  2586     zfsettype(ZFST_TYPE(zfstatusp[zfsessno]));
       
  2587 
       
  2588     if (recv)
       
  2589 	fflush(stdout);		/* since we may be using fd 1 */
       
  2590     for (; *args; args++) {
       
  2591 	char *ln, *rest = NULL;
       
  2592 	off_t startat = 0;
       
  2593 	if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
       
  2594 	    off_t sz;
       
  2595 	    /*
       
  2596 	     * This calls the SIZE command to get the size for remote
       
  2597 	     * files.  Some servers send the size with the reply to
       
  2598 	     * the transfer command (i.e. RETR), in which
       
  2599 	     * case we note the fact and don't call this
       
  2600 	     * next time.  For that reason, the first call
       
  2601 	     * of zftp_progress is delayed until zfsenddata().
       
  2602 	     */
       
  2603 	    if ((!(zfprefs & ZFPF_DUMB) &&
       
  2604 		 (zfstatusp[zfsessno] & (ZFST_NOSZ|ZFST_TRSZ)) != ZFST_TRSZ)
       
  2605 		|| !recv) {
       
  2606 		/* the final 0 is a local fd to fstat if recv is zero */
       
  2607 		zfstats(*args, recv, &sz, NULL, 0);
       
  2608 		/* even if it doesn't support SIZE, it may tell us */
       
  2609 		if (recv && sz == -1)
       
  2610 		    getsize = 1;
       
  2611 	    } else
       
  2612 		getsize = 1;
       
  2613 	    zfstarttrans(*args, recv, sz);
       
  2614 	}
       
  2615 
       
  2616 	if (flags & ZFTP_REST) {
       
  2617 	    startat = zstrtol(args[1], NULL, 10);
       
  2618 	    rest = tricat("REST ", args[1], "\r\n");
       
  2619 	}
       
  2620 
       
  2621 	ln = tricat(cmd, *args, "\r\n");
       
  2622 	/* note zfsess->dfd doesn't exist till zfgetdata() creates it */
       
  2623 	if (zfgetdata(name, rest, ln, getsize))
       
  2624 	    ret = 2;
       
  2625 	else if (zfsenddata(name, recv, progress, startat))
       
  2626 	    ret = 1;
       
  2627 	zsfree(ln);
       
  2628 	/*
       
  2629 	 * The progress report isn't started till zfsenddata(), where
       
  2630 	 * it's the first item.  Hence we send a final progress report
       
  2631 	 * if and only if we called zfsenddata();
       
  2632 	 */
       
  2633 	if (progress && ret != 2 &&
       
  2634 	    (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
       
  2635 	    /* progress to finish: ZFTP_TRANSFER set to GF or PF */
       
  2636 	    int osc = sfcontext;
       
  2637 
       
  2638 	    zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"),
       
  2639 		       ZFPM_READONLY);
       
  2640 	    sfcontext = SFC_HOOK;
       
  2641 	    doshfunc("zftp_progress", prog, NULL, 0, 1);
       
  2642 	    sfcontext = osc;
       
  2643 	}
       
  2644 	if (rest) {
       
  2645 	    zsfree(rest);
       
  2646 	    args++;
       
  2647 	}
       
  2648 	if (errflag)
       
  2649 	    break;
       
  2650     }
       
  2651     zfendtrans();
       
  2652     return ret != 0;
       
  2653 }
       
  2654 
       
  2655 /*
       
  2656  * Delete a list of files on the server.  We allow a list by analogy with
       
  2657  * `rm'.
       
  2658  */
       
  2659 
       
  2660 /**/
       
  2661 static int
       
  2662 zftp_delete(UNUSED(char *name), char **args, UNUSED(int flags))
       
  2663 {
       
  2664     int ret = 0;
       
  2665     char *cmd, **aptr;
       
  2666     for (aptr = args; *aptr; aptr++) {
       
  2667 	cmd = tricat("DELE ", *aptr, "\r\n");
       
  2668 	if (zfsendcmd(cmd) > 2)
       
  2669 	    ret = 1;
       
  2670 	zsfree(cmd);
       
  2671     }
       
  2672     return ret;
       
  2673 }
       
  2674 
       
  2675 /* Create or remove a directory on the server */
       
  2676 
       
  2677 /**/
       
  2678 static int
       
  2679 zftp_mkdir(UNUSED(char *name), char **args, int flags)
       
  2680 {
       
  2681     int ret;
       
  2682     char *cmd = tricat((flags & ZFTP_DELE) ? "RMD " : "MKD ",
       
  2683 		       *args, "\r\n");
       
  2684     ret = (zfsendcmd(cmd) > 2);
       
  2685     zsfree(cmd);
       
  2686     return ret;
       
  2687 }
       
  2688 
       
  2689 /* Rename a file on the server */
       
  2690 
       
  2691 /**/
       
  2692 static int
       
  2693 zftp_rename(UNUSED(char *name), char **args, UNUSED(int flags))
       
  2694 {
       
  2695     int ret;
       
  2696     char *cmd;
       
  2697 
       
  2698     cmd = tricat("RNFR ", args[0], "\r\n");
       
  2699     ret = 1;
       
  2700     if (zfsendcmd(cmd) == 3) {
       
  2701 	zsfree(cmd);
       
  2702 	cmd = tricat("RNTO ", args[1], "\r\n");
       
  2703 	if (zfsendcmd(cmd) == 2)
       
  2704 	    ret = 0;
       
  2705     }
       
  2706     zsfree(cmd);
       
  2707     return ret;
       
  2708 }
       
  2709 
       
  2710 /*
       
  2711  * Send random commands, either with SITE or literal.
       
  2712  * In the second case, the user better know what they're doing.
       
  2713  */
       
  2714 
       
  2715 /**/
       
  2716 static int
       
  2717 zftp_quote(UNUSED(char *name), char **args, int flags)
       
  2718 {
       
  2719     int ret = 0;
       
  2720     char *cmd;
       
  2721 
       
  2722     cmd = (flags & ZFTP_SITE) ? zfargstring("SITE", args)
       
  2723 	: zfargstring(args[0], args+1);
       
  2724     ret = (zfsendcmd(cmd) > 2);
       
  2725     zsfree(cmd);
       
  2726 
       
  2727     return ret;
       
  2728 }
       
  2729 
       
  2730 /*
       
  2731  * Close the connection, ending the session.  With leaveparams,
       
  2732  * don't do anything to the external status (parameters, zftp_chpwd),
       
  2733  * probably because this isn't the current session.
       
  2734  */
       
  2735 
       
  2736 /**/
       
  2737 static void
       
  2738 zfclose(int leaveparams)
       
  2739 {
       
  2740     char **aptr;
       
  2741     Eprog prog;
       
  2742 
       
  2743     if (!zfsess->control)
       
  2744 	return;
       
  2745 
       
  2746     zfclosing = 1;
       
  2747     if (zcfinish != 2) {
       
  2748 	/*
       
  2749 	 * haven't had EOF from server, so send a QUIT and get the response.
       
  2750 	 * maybe we should set a shorter timeout for this to avoid
       
  2751 	 * CTRL-c rage.
       
  2752 	 */
       
  2753 	zfsendcmd("QUIT\r\n");
       
  2754     }
       
  2755     if (zfsess->cin) {
       
  2756 	/*
       
  2757 	 * We fdopen'd the TCP control fd; since we can't fdclose it,
       
  2758 	 * we need to perform a full fclose, which invalidates the
       
  2759 	 * TCP fd.  We need to do this before closing the FILE, since
       
  2760 	 * it's not usable afterwards.
       
  2761 	 */
       
  2762 	if (fileno(zfsess->cin) == zfsess->control->fd)
       
  2763 	    zfsess->control->fd = -1;
       
  2764 	fclose(zfsess->cin);
       
  2765 	zfsess->cin = NULL;
       
  2766     }
       
  2767     if (zfsess->control) {
       
  2768 	zfnopen--;
       
  2769 	tcp_close(zfsess->control);
       
  2770 	/* We leak if the above failed */
       
  2771 	zfsess->control = NULL;
       
  2772     }
       
  2773 
       
  2774     if (zfstatfd != -1) {
       
  2775 	zfstatusp[zfsessno] |= ZFST_CLOS;
       
  2776 	if (!zfnopen) {
       
  2777 	    /* Write the final status in case this is a subshell */
       
  2778 	    lseek(zfstatfd, zfsessno*sizeof(int), 0);
       
  2779 	    write(zfstatfd, (char *)zfstatusp+zfsessno, sizeof(int));
       
  2780 
       
  2781 	    close(zfstatfd);
       
  2782 	    zfstatfd = -1;
       
  2783 	}
       
  2784     }
       
  2785 
       
  2786     if (!leaveparams) {
       
  2787 	/* Unset the non-special parameters */
       
  2788 	for (aptr = zfparams; *aptr; aptr++)
       
  2789 	    zfunsetparam(*aptr);
       
  2790 
       
  2791 	/* Now ZFTP_PWD is unset.  It's up to zftp_chpwd to notice. */
       
  2792 	if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
       
  2793 	    int osc = sfcontext;
       
  2794 
       
  2795 	    sfcontext = SFC_HOOK;
       
  2796 	    doshfunc("zftp_chpwd", prog, NULL, 0, 1);
       
  2797 	    sfcontext = osc;
       
  2798 	}
       
  2799     }
       
  2800 
       
  2801     /* tidy up status variables, because mess is bad */
       
  2802     zfclosing = zfdrrrring = 0;
       
  2803 }
       
  2804 
       
  2805 /* Safe front end to zftp_close() from within the package */
       
  2806 
       
  2807 /**/
       
  2808 static int
       
  2809 zftp_close(UNUSED(char *name), UNUSED(char **args), UNUSED(int flags))
       
  2810 {
       
  2811     zfclose(0);
       
  2812     return 0;
       
  2813 }
       
  2814 
       
  2815 
       
  2816 /*
       
  2817  * Session management routines.  A session consists of various
       
  2818  * internal variables describing the connection, the set of shell
       
  2819  * parameters --- the same set which is unset by closing a connection ---
       
  2820  * and the set of host/user parameters if set by zftp params.
       
  2821  */
       
  2822 
       
  2823 /*
       
  2824  * Switch to a new session, creating it if necessary.
       
  2825  * Sets zfsessno, zfsess and $ZFTP_SESSION; updates zfsesscnt and zfstatusp.
       
  2826  */
       
  2827 
       
  2828 /**/
       
  2829 static void
       
  2830 newsession(char *nm)
       
  2831 {
       
  2832     LinkNode nptr;
       
  2833 
       
  2834     for (zfsessno = 0, nptr = firstnode(zfsessions);
       
  2835 	 nptr; zfsessno++, incnode(nptr)) {
       
  2836 	zfsess = (Zftp_session) nptr->dat;
       
  2837 	if (!strcmp(zfsess->name, nm))
       
  2838 	    break;
       
  2839     }
       
  2840 
       
  2841     if (!nptr) {
       
  2842 	zfsess = (Zftp_session) zshcalloc(sizeof(struct zftp_session));
       
  2843 	zfsess->name = ztrdup(nm);
       
  2844 	zfsess->dfd = -1;
       
  2845 	zfsess->params = (char **) zshcalloc(sizeof(zfparams));
       
  2846 	zaddlinknode(zfsessions, zfsess);
       
  2847 
       
  2848 	zfsesscnt++;
       
  2849 	zfstatusp = (int *)zrealloc(zfstatusp, sizeof(int)*zfsesscnt);
       
  2850 	zfstatusp[zfsessno] = 0;
       
  2851     }
       
  2852 
       
  2853     zfsetparam("ZFTP_SESSION", ztrdup(zfsess->name), ZFPM_READONLY);
       
  2854 }
       
  2855 
       
  2856 /* Save the existing session: this just means saving the parameters. */
       
  2857 
       
  2858 static void
       
  2859 savesession()
       
  2860 {
       
  2861     char **ps, **pd, *val;
       
  2862 
       
  2863     for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++) {
       
  2864 	if (*pd)
       
  2865 	    zsfree(*pd);
       
  2866 	queue_signals();
       
  2867 	if ((val = getsparam(*ps)))
       
  2868 	    *pd = ztrdup(val);
       
  2869 	else
       
  2870 	    *pd = NULL;
       
  2871 	unqueue_signals();
       
  2872     }
       
  2873     *pd = NULL;
       
  2874 }
       
  2875 
       
  2876 /*
       
  2877  * Switch to session nm, creating it if necessary.
       
  2878  * Just call newsession, then set up the session-specific parameters.
       
  2879  */
       
  2880 
       
  2881 /**/
       
  2882 static void
       
  2883 switchsession(char *nm)
       
  2884 {
       
  2885     char **ps, **pd;
       
  2886 
       
  2887     newsession(nm);
       
  2888 
       
  2889     for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++) {
       
  2890 	if (*pd) {
       
  2891 	    /* Use the permanently allocated string for the parameter */
       
  2892 	    zfsetparam(*ps, *pd, ZFPM_READONLY);
       
  2893 	    *pd = NULL;
       
  2894 	} else
       
  2895 	    zfunsetparam(*ps);
       
  2896     }
       
  2897 }
       
  2898 
       
  2899 /**/
       
  2900 static void
       
  2901 freesession(Zftp_session sptr)
       
  2902 {
       
  2903     char **ps, **pd;
       
  2904     zsfree(sptr->name);
       
  2905     for (ps = zfparams, pd = zfsess->params; *ps; ps++, pd++)
       
  2906 	if (*pd)
       
  2907 	    zsfree(*pd);
       
  2908     zfree(zfsess->params, sizeof(zfparams));
       
  2909     if (sptr->userparams)
       
  2910 	freearray(sptr->userparams);
       
  2911     zfree(sptr, sizeof(struct zftp_session));
       
  2912 }
       
  2913 
       
  2914 /**/
       
  2915 static int
       
  2916 zftp_session(UNUSED(char *name), char **args, UNUSED(int flags))
       
  2917 {
       
  2918     if (!*args) {
       
  2919 	LinkNode nptr;
       
  2920 
       
  2921 	for (nptr = firstnode(zfsessions); nptr; incnode(nptr))
       
  2922 	    printf("%s\n", ((Zftp_session)nptr->dat)->name);
       
  2923 	return 0;
       
  2924     }
       
  2925 
       
  2926     /*
       
  2927      * Check if we are already in the required session: if so,
       
  2928      * it's a no-op, not an error.
       
  2929      */
       
  2930     if (!strcmp(*args, zfsess->name))
       
  2931 	return 0;
       
  2932 
       
  2933     savesession();
       
  2934     switchsession(*args);
       
  2935     return 0;
       
  2936 }
       
  2937 
       
  2938 /* Remove a session and free it */
       
  2939 
       
  2940 /**/
       
  2941 static int
       
  2942 zftp_rmsession(UNUSED(char *name), char **args, UNUSED(int flags))
       
  2943 {
       
  2944     int no;
       
  2945     LinkNode nptr;
       
  2946     Zftp_session sptr = NULL;
       
  2947     char *newsess = NULL;
       
  2948 
       
  2949     /* Find the session in the list: either the current one, or by name */
       
  2950     for (no = 0, nptr = firstnode(zfsessions); nptr; no++, incnode(nptr)) {
       
  2951 	sptr = (Zftp_session) nptr->dat;
       
  2952 	if ((!*args && sptr == zfsess) ||
       
  2953 	    (*args && !strcmp(sptr->name, *args)))
       
  2954 	    break;
       
  2955     }
       
  2956     if (!nptr)
       
  2957 	return 1;
       
  2958 
       
  2959     if (sptr == zfsess) {
       
  2960 	/* Freeing current session: make sure it's closed */
       
  2961 	zfclosedata();
       
  2962 	zfclose(0);
       
  2963 
       
  2964 	/*
       
  2965 	 * Choose new session to switch to if any: first in list
       
  2966 	 * excluding the one just freed.
       
  2967 	 */
       
  2968 	if (zfsesscnt > 1) {
       
  2969 	    LinkNode newn = firstnode(zfsessions);
       
  2970 	    if (newn == nptr)
       
  2971 		incnode(newn);
       
  2972 	    newsess = ((Zftp_session)newn->dat)->name;
       
  2973 	}
       
  2974     } else {
       
  2975 	Zftp_session oldsess = zfsess;
       
  2976 	zfsess = sptr;
       
  2977 	/*
       
  2978 	 * Freeing another session: don't need to switch, just
       
  2979 	 * tell zfclose() not to delete parameters etc.
       
  2980 	 */
       
  2981 	zfclosedata();
       
  2982 	zfclose(1);
       
  2983 	zfsess = oldsess;
       
  2984     }
       
  2985     remnode(zfsessions, nptr);
       
  2986     freesession(sptr);
       
  2987 
       
  2988     /*
       
  2989      * Fix up array of status pointers.
       
  2990      */
       
  2991     if (--zfsesscnt) {
       
  2992 	/*
       
  2993 	 * Some remaining, so just shift up
       
  2994 	 */
       
  2995 	int *newstatusp = (int *)zalloc(sizeof(int)*zfsesscnt);
       
  2996 	int *src, *dst, i;
       
  2997 	for (i = 0, src = zfstatusp, dst = newstatusp; i < zfsesscnt;
       
  2998 	     i++, src++, dst++) {
       
  2999 	    if (i == no)
       
  3000 		src++;
       
  3001 	    *dst = *src;
       
  3002 	}
       
  3003 	zfree(zfstatusp, sizeof(int)*(zfsesscnt+1));
       
  3004 	zfstatusp = newstatusp;
       
  3005 
       
  3006 	/*
       
  3007 	 * Maybe we need to switch to one of the remaining sessions.
       
  3008 	 */
       
  3009 	if (newsess)
       
  3010 	    switchsession(newsess);
       
  3011     } else {
       
  3012 	zfree(zfstatusp, sizeof(int));
       
  3013 	zfstatusp = NULL;
       
  3014 
       
  3015 	/*
       
  3016 	 * We've just deleted the last session, so we need to
       
  3017 	 * start again from scratch.
       
  3018 	 */
       
  3019 	newsession("default");
       
  3020     }
       
  3021 
       
  3022     return 0;
       
  3023 }
       
  3024 
       
  3025 /* The builtin command frontend to the rest of the package */
       
  3026 
       
  3027 /**/
       
  3028 static int
       
  3029 bin_zftp(char *name, char **args, UNUSED(Options ops), UNUSED(int func))
       
  3030 {
       
  3031     char fullname[20] = "zftp ";
       
  3032     char *cnam = *args++, *prefs, *ptr;
       
  3033     Zftpcmd zptr;
       
  3034     int n, ret = 0;
       
  3035 
       
  3036     for (zptr = zftpcmdtab; zptr->nam; zptr++)
       
  3037 	if (!strcmp(zptr->nam, cnam))
       
  3038 	    break;
       
  3039 
       
  3040     if (!zptr->nam) {
       
  3041 	zwarnnam(name, "no such subcommand: %s", cnam, 0);
       
  3042 	return 1;
       
  3043     }
       
  3044 
       
  3045     /* check number of arguments */
       
  3046     for (n = 0; args[n]; n++)
       
  3047 	;
       
  3048     if (n < zptr->min || (zptr->max != -1 && n > zptr->max)) {
       
  3049 	zwarnnam(name, "wrong no. of arguments for %s", cnam, 0);
       
  3050 	return 1;
       
  3051     }
       
  3052 
       
  3053     strcat(fullname, cnam);
       
  3054     if (zfstatfd != -1 && !(zptr->flags & ZFTP_SESS)) {
       
  3055 	/* Get the status in case it was set by a forked process */
       
  3056 	int oldstatus = zfstatusp[zfsessno];
       
  3057 	lseek(zfstatfd, 0, 0);
       
  3058 	read(zfstatfd, (char *)zfstatusp, sizeof(int)*zfsesscnt);
       
  3059 	if (zfsess->control && (zfstatusp[zfsessno] & ZFST_CLOS)) {
       
  3060 	    /* got closed in subshell without us knowing */
       
  3061 	    zcfinish = 2;
       
  3062 	    zfclose(0);
       
  3063 	} else {
       
  3064 	    /*
       
  3065 	     * fix up status types: unfortunately they may already
       
  3066 	     * have been looked at between being changed in the subshell
       
  3067 	     * and now, but we can't help that.
       
  3068 	     */
       
  3069 	    if (ZFST_TYPE(oldstatus) != ZFST_TYPE(zfstatusp[zfsessno]))
       
  3070 		zfsetparam("ZFTP_TYPE",
       
  3071 			   ztrdup(ZFST_TYPE(zfstatusp[zfsessno]) == ZFST_ASCI ?
       
  3072 				  "A" : "I"), ZFPM_READONLY);
       
  3073 	    if (ZFST_MODE(oldstatus) != ZFST_MODE(zfstatusp[zfsessno]))
       
  3074 		zfsetparam("ZFTP_MODE",
       
  3075 			   ztrdup(ZFST_MODE(zfstatusp[zfsessno]) == ZFST_BLOC ?
       
  3076 				  "B" : "S"), ZFPM_READONLY);
       
  3077 	}
       
  3078     }
       
  3079 #if defined(HAVE_SELECT) || defined (HAVE_POLL)
       
  3080     if (zfsess->control && !(zptr->flags & (ZFTP_TEST|ZFTP_SESS))) {
       
  3081 	/*
       
  3082 	 * Test the connection for a bad fd or incoming message, but
       
  3083 	 * only if the connection was last heard of open, and
       
  3084 	 * if we are not about to call the test command anyway.
       
  3085 	 * Not worth it unless we have select() or poll().
       
  3086 	 */
       
  3087 	ret = zftp_test("zftp test", NULL, 0);
       
  3088     }
       
  3089 #endif
       
  3090     if ((zptr->flags & ZFTP_CONN) && !zfsess->control) {
       
  3091 	if (ret != 2) {
       
  3092 	    /*
       
  3093 	     * with ret == 2, we just got dumped out in the test,
       
  3094 	     * so enough messages already.
       
  3095 	     */	       
       
  3096 	    zwarnnam(fullname, "not connected.", NULL, 0);
       
  3097 	}
       
  3098 	return 1;
       
  3099     }
       
  3100 
       
  3101     queue_signals();
       
  3102     if ((prefs = getsparam("ZFTP_PREFS"))) {
       
  3103 	zfprefs = 0;
       
  3104 	for (ptr = prefs; *ptr; ptr++) {
       
  3105 	    switch (toupper(STOUC(*ptr))) {
       
  3106 	    case 'S':
       
  3107 		/* sendport */
       
  3108 		zfprefs |= ZFPF_SNDP;
       
  3109 		break;
       
  3110 
       
  3111 	    case 'P':
       
  3112 		/*
       
  3113 		 * passive
       
  3114 		 * If we have already been told to use sendport mode,
       
  3115 		 * we're never going to use passive mode.
       
  3116 		 */
       
  3117 		if (!(zfprefs & ZFPF_SNDP))
       
  3118 		    zfprefs |= ZFPF_PASV;
       
  3119 		break;
       
  3120 
       
  3121 	    case 'D':
       
  3122 		/* dumb */
       
  3123 		zfprefs |= ZFPF_DUMB;
       
  3124 		break;
       
  3125 
       
  3126 	    default:
       
  3127 		zwarnnam(name, "preference %c not recognized", NULL, *ptr);
       
  3128 		break;
       
  3129 	    }
       
  3130 	}
       
  3131     }
       
  3132     unqueue_signals();
       
  3133 
       
  3134     ret = (*zptr->fun)(fullname, args, zptr->flags);
       
  3135 
       
  3136     if (zfalarmed)
       
  3137 	zfunalarm();
       
  3138     if (zfdrrrring) {
       
  3139 	/* had a timeout, close the connection */
       
  3140 	zcfinish = 2;		/* don't try sending QUIT */
       
  3141 	zfclose(0);
       
  3142     }
       
  3143     if (zfstatfd != -1) {
       
  3144 	/*
       
  3145 	 * Set the status in case another process needs to know,
       
  3146 	 * but only for the active session.
       
  3147 	 */
       
  3148 	lseek(zfstatfd, zfsessno*sizeof(int), 0);
       
  3149 	write(zfstatfd, (char *)zfstatusp+zfsessno, sizeof(int));
       
  3150     }
       
  3151     return ret;
       
  3152 }
       
  3153 
       
  3154 static void
       
  3155 zftp_cleanup(void)
       
  3156 {
       
  3157     /*
       
  3158      * There are various parameters hanging around, but they're
       
  3159      * all non-special so are entirely non-life-threatening.
       
  3160      */
       
  3161     LinkNode nptr;
       
  3162     Zftp_session cursess = zfsess;
       
  3163     for (zfsessno = 0, nptr = firstnode(zfsessions); nptr;
       
  3164 	 zfsessno++, incnode(nptr)) {
       
  3165 	zfsess = (Zftp_session)nptr->dat;
       
  3166 	zfclosedata();
       
  3167 	/*
       
  3168 	 * When closing the current session, do the usual unsetting,
       
  3169 	 * otherwise don't.
       
  3170 	 */
       
  3171 	zfclose(zfsess != cursess);
       
  3172     }
       
  3173     zsfree(lastmsg);
       
  3174     zfunsetparam("ZFTP_SESSION");
       
  3175     freelinklist(zfsessions, (FreeFunc) freesession);
       
  3176     zfree(zfstatusp, sizeof(int)*zfsesscnt);
       
  3177     deletebuiltins("zftp", bintab, sizeof(bintab)/sizeof(*bintab));
       
  3178 }
       
  3179 
       
  3180 static int
       
  3181 zftpexithook(UNUSED(Hookdef d), UNUSED(void *dummy))
       
  3182 {
       
  3183     zftp_cleanup();
       
  3184     return 0;
       
  3185 }
       
  3186 
       
  3187 /* The load/unload routines required by the zsh library interface */
       
  3188 
       
  3189 /**/
       
  3190 int
       
  3191 setup_(UNUSED(Module m))
       
  3192 {
       
  3193     /* setup_ returns 0 for success. require_module returns 1 for success. */
       
  3194     return !require_module("", "zsh/net/tcp", 0, 0);
       
  3195 }
       
  3196 
       
  3197 /**/
       
  3198 int
       
  3199 boot_(UNUSED(Module m))
       
  3200 {
       
  3201     int ret;
       
  3202     if ((ret = addbuiltins("zftp", bintab,
       
  3203 			   sizeof(bintab)/sizeof(*bintab))) == 1) {
       
  3204 	/* if successful, set some default parameters */
       
  3205 	off_t tmout_def = 60;
       
  3206 	zfsetparam("ZFTP_VERBOSE", ztrdup("450"), ZFPM_IFUNSET);
       
  3207 	zfsetparam("ZFTP_TMOUT", &tmout_def, ZFPM_IFUNSET|ZFPM_INTEGER);
       
  3208 	zfsetparam("ZFTP_PREFS", ztrdup("PS"), ZFPM_IFUNSET);
       
  3209 	/* default preferences if user deletes variable */
       
  3210 	zfprefs = ZFPF_SNDP|ZFPF_PASV;
       
  3211     
       
  3212 	zfsessions = znewlinklist();
       
  3213 	newsession("default");
       
  3214 
       
  3215 	addhookfunc("exit", zftpexithook);
       
  3216     }
       
  3217 
       
  3218     return !ret;
       
  3219 }
       
  3220 
       
  3221 /**/
       
  3222 int
       
  3223 cleanup_(UNUSED(Module m))
       
  3224 {
       
  3225     deletehookfunc("exit", zftpexithook);
       
  3226     zftp_cleanup();
       
  3227     return 0;
       
  3228 }
       
  3229 
       
  3230 /**/
       
  3231 int
       
  3232 finish_(UNUSED(Module m))
       
  3233 {
       
  3234     return 0;
       
  3235 }