www.pudn.com > socks5.zip > cmds.c


/* Copyright (c) 1985, 1989 Regents of the University of California.         */ 
/* All rights reserved.                                                      */ 
/*                                                                           */ 
/* Redistribution and use in source and binary forms, with or without        */ 
/* modification, are permitted provided that the following conditions        */ 
/* are met:                                                                  */ 
/*                                                                           */ 
/* 1. Redistributions of source code must retain the above copyright         */ 
/*    notice, this list of conditions and the following disclaimer.          */ 
/* 2. Redistributions in binary form must reproduce the above copyright      */ 
/*    notice, this list of conditions and the following disclaimer in the    */ 
/*    documentation and/or other materials provided with the distribution.   */ 
/* 3. All advertising materials mentioning features or use of this software  */ 
/*    must display the following acknowledgement:                            */ 
/*      This product includes software developed by the University of        */ 
/*      California, Berkeley and its contributors.                           */ 
/* 4. Neither the name of the University nor the names of its contributors   */ 
/*    may be used to endorse or promote products derived from this software  */ 
/*    without specific prior written permission.                             */ 
/*                                                                           */ 
/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */ 
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */ 
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE*/ 
/* ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  */ 
/* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL*/ 
/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   */ 
/* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     */ 
/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT*/ 
/* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY */ 
/* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF    */ 
/* SUCH DAMAGE.                                                              */ 
 
/* FTP User Program -- Command Routines.                                     */ 
#include "ftp_var.h" 
 
#define DONT_NEED_SIGBLOCK 
#define DONT_NEED_SIGPAUSE 
#define DONT_NEED_SIGUNBLOCK 
#define DONT_NEED_SIGPENDING 
#include "sigfix.h" 
 
#include  
#include  
#include "pathnames.h" 
 
#ifndef HAVE_GETCWD 
extern char *getwd(); 
#endif 
 
extern int command(); 
 
extern	char *home; 
extern	char *globerr; 
extern	char **ftpglob(); 
extern	char *remglob(); 
extern	int  errno; 
extern off_t restart_point; 
extern char reply_string[]; 
 
char *mname; 
jmp_buf jabort; 
char *dotrans(), *domap(); 
 
/* 
 * Options and other state info. 
 */ 
int	trace;			/* trace packets exchanged */ 
int	hash;			/* print # for each buffer transferred */ 
int	sendport;		/* use PORT cmd for each data connection */ 
int	verbose;		/* print messages coming back from server */ 
int	connected;		/* connected to server */ 
int	fromatty;		/* input is from a terminal */ 
int	interactive;		/* interactively prompt on m* cmds */ 
int	debug;			/* debugging level */ 
int	bell;			/* ring bell on cmd completion */ 
int	doglob;			/* glob local file names */ 
int	autologin;		/* establish user account on connection */ 
int	proxy;			/* proxy server connection active */ 
int	proxflag;		/* proxy connection exists */ 
int	sunique;		/* store files on server with unique name */ 
int	runique;		/* store local files with unique name */ 
int	mcase;			/* map upper to lower case for mget names */ 
int	ntflag;			/* use ntin ntout tables for name translation */ 
int	mapflag;		/* use mapin mapout templates on file names */ 
int	code;			/* return/reply code for ftp command */ 
int	crflag;			/* if 1, strip car. rets. on ascii gets */ 
char	pasv[64];		/* passive port for proxy data connection */ 
char	*altarg;		/* argv[1] with no shell-like preprocessing  */ 
char	ntin[17];		/* input translation table */ 
char	ntout[17];		/* output translation table */ 
 
char	mapin[MAXPATHLEN];	/* input map template */ 
char	mapout[MAXPATHLEN];	/* output map template */ 
char	typename[32];		/* name of file transfer type */ 
int	type;			/* requested file transfer type */ 
int	curtype;		/* current file transfer type */ 
char	structname[32];		/* name of file transfer structure */ 
int	stru;			/* file transfer structure */ 
char	formname[32];		/* name of file transfer format */ 
int	form;			/* file transfer format */ 
char	modename[32];		/* name of file transfer mode */ 
int	mode;			/* file transfer mode */ 
char	bytename[32];		/* local byte size in ascii */ 
int	bytesize;		/* local byte size in binary */ 
 
char	*hostname;		/* name of host connected to */ 
int	unix_server;		/* server is unix, can use binary for ascii */ 
int	unix_proxy;		/* proxy is unix, can use binary for ascii */ 
 
struct	servent *sp;		/* service spec for tcp/ftp */ 
int	ftp_s_port;	        /* save ftp's sp->s_port value here */ 
char	line[200];		/* input line buffer */ 
char	*stringbase;		/* current scan point in line buffer */ 
char	argbuf[200];		/* argument storage buffer */ 
char	*argbase;		/* current storage point in arg buffer */ 
int	margc;			/* count of arguments on input line */ 
char	*margv[20];		/* args parsed from input line */ 
int     cpend;                  /* flag: if != 0, then pending server reply */ 
int	mflag;			/* flag: if != 0, then active multi command */ 
int	options;		/* used during socket creation */ 
 
jmp_buf	toplevel;		/* non-local goto stuff for cmd scanner */ 
 
int macnum;			/* number of defined macros */ 
struct macel macros[16]; 
char macbuf[4096]; 
 
/* `Another' gets another argument, and stores the new argc and argv.        */ 
/* It reverts to the top level (via main.c's intr()) on EOF/error.           */ 
/* Returns false if no new arguments have been added.                        */ 
int another(int *pargc, char ***pargv, char *prompt) { 
  int len = strlen(line), ret; 
  extern sig_t intr(); 
 
  if (len >= sizeof(line) - 3) { 
    printf("sorry, arguments too long\n"); 
    intr(); 
  } 
 
  printf("(%s) ", prompt); 
  line[len++] = ' '; 
 
  if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) intr(); 
 
  len += strlen(&line[len]); 
  if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0'; 
 
  makeargv(); 
  ret = margc > *pargc; 
 
  *pargc = margc; 
  *pargv = margv; 
 
  return ret; 
} 
 
/* Connect to peer server and auto-login, if possible.                       */ 
void setpeer(int argc, char *argv[]) { 
  char *host, *hookup(); 
  short port; 
 
  if (connected) { 
    printf("Already connected to %s, use close first.\n", hostname); 
    code = -1; 
    return; 
  } 
  if (argc < 2) 
    another(&argc, &argv, "to"); 
 
  if (argc < 2 || argc > 3) { 
    printf("usage: %s host-name [port]\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  /* port = sp->s_port; */ 
  port = ftp_s_port; 
 
  if (argc > 2) { 
    port = atoi(argv[2]); 
    if (port <= 0) { 
      printf("%s: bad port number-- %s\n", argv[1], argv[2]); 
      printf ("usage: %s host-name [port]\n", argv[0]); 
      code = -1; 
      return; 
    } 
    port = htons(port); 
  } 
 
  host = hookup(argv[1], port); 
  if (host) { 
#if NBBY == 8 
    int overbose; 
#endif 
	 
    connected = 1; 
    /* Set up defaults for FTP.                                          */ 
    strcpy(typename, "ascii"), type = TYPE_A; 
    curtype = TYPE_A; 
    strcpy(formname, "non-print"), form = FORM_N; 
    strcpy(modename, "stream"), mode = MODE_S; 
    strcpy(structname, "file"), stru = STRU_F; 
    strcpy(bytename, "8"), bytesize = 8; 
 
    if (autologin)  
      login(argv[1]); 
	 
#if NBBY == 8 
    /* this ifdef is to keep someone form "porting" this to an           */ 
    /* incompatible system and not checking this out. This way they have */ 
    /* to think about it.                                                */ 
    overbose = verbose; 
 
    if (debug == 0) 
      verbose = -1; 
    if (command("SYST") == COMPLETE && overbose) { 
      register char *cp, c; 
      cp = index(reply_string+4, ' '); 
      if (cp == NULL) cp = index(reply_string+4, '\r'); 
 
      if (cp) { 
	if (cp[-1] == '.') cp--; 
	c = *cp; 
	*cp = '\0'; 
      } 
	     
      printf("Remote system type is %s.\n", reply_string+4); 
      if (cp) *cp = c; 
    } 
 
    if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { 
      if (proxy) unix_proxy = 1; 
      else       unix_server = 1; 
 
      /* Set type to 0 (not specified by user), meaning binary by      */ 
      /* default, but don't bother telling server.  We can use binary  */ 
      /* for text files unless changed by the user.                    */ 
      type = 0; 
      strcpy(typename, "binary"); 
      if (overbose) 
	printf("Using %s mode to transfer files.\n", typename); 
    } else { 
      if (proxy) unix_proxy = 0; 
      else       unix_server = 0; 
 
      if (overbose && !strncmp(reply_string, "215 TOPS20", 10)) 
	printf("Remember to set tenex mode when transfering binary files from this machine.\n"); 
    } 
 
    verbose = overbose; 
#endif  
  } 
} 
 
struct	types { 
  char	*t_name; 
  char	*t_mode; 
  int	         t_type; 
  char	*t_arg; 
} types[] = { 
  { "ascii",	"A",	TYPE_A,	0 }, 
  { "binary",	"I",	TYPE_I,	0 }, 
  { "image",	"I",	TYPE_I,	0 }, 
  { "ebcdic",	"E",	TYPE_E,	0 }, 
  { "tenex",	"L",	TYPE_L,	bytename }, 
  { NULL,	NULL,	0,	NULL } 
}; 
 
/* Set transfer type.                                                        */ 
void settype(int argc, char *argv[]) { 
  register struct types *p; 
  int comret; 
     
  if (argc > 2) { 
    char *sep; 
 
    printf("usage: %s [", argv[0]); 
    sep = " "; 
    for (p = types; p->t_name; p++) { 
      printf("%s%s", sep, p->t_name); 
      sep = " | "; 
    } 
 
    printf(" ]\n"); 
    code = -1; 
    return; 
  } 
 
  if (argc < 2) { 
    printf("Using %s mode to transfer files.\n", typename); 
    code = 0; 
    return; 
  } 
 
  for (p = types; p->t_name; p++) 
    if (strcmp(argv[1], p->t_name) == 0) 
      break; 
 
  if (p->t_name == 0) { 
    printf("%s: unknown mode\n", argv[1]); 
    code = -1; 
    return; 
  } 
 
  if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 
    comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 
  else 
    comret = command("TYPE %s", p->t_mode); 
 
  if (comret == COMPLETE) { 
    strcpy(typename, p->t_name); 
    curtype = type = p->t_type; 
  } 
} 
 
/* Internal form of settype; changes current type in use with server         */ 
/* without changing our notion of the type for data transfers.               */ 
/* Used to change to and from ascii for listings.                            */ 
void changetype(int newtype, int show) { 
  register struct types *p; 
  int comret, oldverbose = verbose; 
     
  if (newtype == 0) 
    newtype = TYPE_I; 
 
  if (newtype == curtype) 
    return; 
 
  if (debug == 0 && show == 0) 
    verbose = 0; 
 
  for (p = types; p->t_name; p++) 
    if (newtype == p->t_type) 
      break; 
 
  if (p->t_name == 0) { 
    printf("ftp: internal error: unknown type %d\n", newtype); 
    return; 
  } 
 
  if (newtype == TYPE_L && bytename[0] != '\0') 
    comret = command("TYPE %s %s", p->t_mode, bytename); 
  else 
    comret = command("TYPE %s", p->t_mode); 
 
  if (comret == COMPLETE) 
    curtype = newtype; 
 
  verbose = oldverbose; 
} 
 
char *stype[] = { 
  "type", 
  "", 
  0 
}; 
 
/* Set binary transfer type.                                                 */ 
void setbinary() { 
  stype[1] = "binary"; 
  settype(2, stype); 
} 
 
/* Set ascii transfer type.                                                  */ 
void setascii() { 
  stype[1] = "ascii"; 
  settype(2, stype); 
} 
 
/* Set tenex transfer type.                                                  */ 
void settenex() { 
  stype[1] = "tenex"; 
  settype(2, stype); 
} 
 
/* Set file transfer mode.                                                   */ 
void setftpmode(int argc, char *argv[]) { 
  printf("We only support %s mode, sorry.\n", modename); 
  code = -1; 
} 
 
/* Set file transfer format.                                                 */ 
void setform(int argc, char *argv[]) { 
  printf("We only support %s format, sorry.\n", formname); 
  code = -1; 
} 
 
/* Set file transfer structure.                                              */ 
void setstruct(int argc, char *argv[]) { 
  printf("We only support %s structure, sorry.\n", structname); 
  code = -1; 
} 
 
/* Glob a local file name specification with the expectation of a single     */ 
/* return value.  Can't control multiple values being expanded from the      */ 
/* expression, we return only the first.                                     */ 
int globulize(char **cpp) { 
  char **globbed; 
 
  if (!doglob) return (1); 
  globbed = ftpglob(*cpp); 
 
     
  if (globerr != NULL) { 
    printf("%s: %s\n", *cpp, globerr); 
 
    if (globbed) { 
      blkfree(globbed); 
      free((char *)globbed); 
    } 
 
    return 0; 
  } 
 
  if (globbed) { 
    *cpp = *globbed++; 
 
    /* don't waste too much memory */ 
 
    if (*globbed) { 
      blkfree(globbed); 
      free((char *)globbed); 
    } 
  } 
 
  return 1; 
} 
 
/* Send a single file.                                                       */ 
void put(int argc, char *argv[]) { 
  char *cmd; 
  int loc = 0; 
  char *oldargv1, *oldargv2; 
 
  if (argc == 2) { 
    argc++; 
    argv[2] = argv[1]; 
    loc++; 
  } 
 
  if (argc < 2 && !another(&argc, &argv, "local-file")) 
    goto usage; 
 
  if (argc < 3 && !another(&argc, &argv, "remote-file")) { 
  usage: 
    printf("usage: %s local-file remote-file\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  oldargv1 = argv[1]; 
  oldargv2 = argv[2]; 
 
  if (!globulize(&argv[1])) { 
    code = -1; 
    return; 
  } 
 
  /* If "globulize" modifies argv[1], and argv[2] is a copy of             */ 
  /* the old argv[1], make it a copy of the new argv[1].                   */ 
  if (argv[1] != oldargv1 && argv[2] == oldargv1)  
    argv[2] = argv[1]; 
 
  cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 
 
  if (loc && ntflag)  
    argv[2] = dotrans(argv[2]); 
 
  if (loc && mapflag)  
    argv[2] = domap(argv[2]); 
 
  sendrequest(cmd, argv[1], argv[2], argv[1] != oldargv1 || argv[2] != oldargv2); 
} 
 
int confirm(char *cmd, char *file) { 
  char bline[BUFSIZ]; 
 
  if (!interactive) return (1); 
  printf("%s %s? ", cmd, file); 
  fflush(stdout); 
 
  if (fgets(bline, sizeof(bline), stdin) == NULL) return (0); 
  return (*bline != 'n' && *bline != 'N'); 
} 
 
/* Send multiple files.                                                      */ 
void mabort() { 
  int ointer; 
  extern jmp_buf jabort; 
     
  printf("\n"); 
  fflush(stdout); 
 
  if (mflag && fromatty) { 
    ointer = interactive; 
    interactive = 1; 
 
    if (confirm("Continue with", mname)) { 
      interactive = ointer; 
      longjmp(jabort,0); 
    } 
 
    interactive = ointer; 
  } 
 
  mflag = 0; 
  longjmp(jabort,0); 
} 
 
void mput(int argc, char **argv) { 
  extern jmp_buf jabort; 
  register int i; 
  sig_t oldintr; 
  int ointer; 
  char *tp; 
  void mabort(); 
     
  if (argc < 2 && !another(&argc, &argv, "local-files")) { 
    printf("usage: %s local-files\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  mname = argv[0]; 
  mflag = 1; 
  oldintr = (sig_t)Signal(SIGINT, mabort); 
  setjmp(jabort); 
 
  if (proxy) { 
    char *cp, *tp2, tmpbuf[MAXPATHLEN]; 
	 
    while ((cp = remglob(argv,0)) != NULL) { 
      if (*cp == 0) { 
	mflag = 0; 
	continue; 
      } 
 
      if (mflag && confirm(argv[0], cp)) { 
	tp = cp; 
	if (mcase) { 
	  while (*tp && !islower(*tp)) { 
	    tp++; 
	  } 
 
	  if (!*tp) { 
	    tp = cp; 
	    tp2 = tmpbuf; 
 
	    while ((*tp2 = *tp)) { 
	      if (isupper(*tp2)) { 
		*tp2 = 'a' + *tp2 - 'A'; 
	      } 
 
	      tp++; 
	      tp2++; 
	    } 
	  } 
	  tp = tmpbuf; 
	} 
 
	if (ntflag) { 
	  tp = dotrans(tp); 
	} 
 
	if (mapflag) { 
	  tp = domap(tp); 
	} 
 
	sendrequest((sunique) ? "STOU" : "STOR", cp, tp, cp != tp || !interactive); 
 
	if (!mflag && fromatty) { 
	  ointer = interactive; 
	  interactive = 1; 
 
	  if (confirm("Continue with","mput")) { 
	    mflag++; 
	  } 
 
	  interactive = ointer; 
	} 
      } 
    } 
 
    Signal(SIGINT, oldintr); 
    mflag = 0; 
    return; 
  } 
 
  for (i = 1; i < argc; i++) { 
    register char **cpp, **gargs; 
 
    if (!doglob) { 
      if (mflag && confirm(argv[0], argv[i])) { 
	tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 
	tp = (mapflag) ? domap(tp) : tp; 
	sendrequest((sunique) ? "STOU" : "STOR", argv[i], tp, tp != argv[i] || !interactive); 
	if (!mflag && fromatty) { 
	  ointer = interactive; 
	  interactive = 1; 
 
	  if (confirm("Continue with","mput")) { 
	    mflag++; 
	  } 
 
	  interactive = ointer; 
	} 
      } 
      continue; 
    } 
 
    gargs = ftpglob(argv[i]); 
 
    if (globerr != NULL) { 
      printf("%s\n", globerr); 
      if (gargs) { 
	blkfree(gargs); 
	free((char *)gargs); 
      } 
      continue; 
    } 
 
    for (cpp = gargs; cpp && *cpp != NULL; cpp++) { 
      if (mflag && confirm(argv[0], *cpp)) { 
	tp = (ntflag) ? dotrans(*cpp) : *cpp; 
	tp = (mapflag) ? domap(tp) : tp; 
	sendrequest((sunique) ? "STOU" : "STOR", *cpp, tp, *cpp != tp || !interactive); 
	if (!mflag && fromatty) { 
	  ointer = interactive; 
	  interactive = 1; 
	  if (confirm("Continue with","mput")) { 
	    mflag++; 
	  } 
	  interactive = ointer; 
	} 
      } 
    } 
 
    if (gargs != NULL) { 
      blkfree(gargs); 
      free((char *)gargs); 
    } 
  } 
 
  Signal(SIGINT, oldintr); 
  mflag = 0; 
} 
 
/* Receive one file.                                                         */ 
int getit(int argc, char *argv[], int restartit, char *mode) { 
  int loc = 0; 
  char *oldargv1, *oldargv2; 
 
  if (argc == 2) { 
    argc++; 
    argv[2] = argv[1]; 
    loc++; 
  } 
 
  if (argc < 2 && !another(&argc, &argv, "remote-file")) 
    goto usage; 
 
  if (argc < 3 && !another(&argc, &argv, "local-file")) { 
  usage: 
    printf("usage: %s remote-file [ local-file ]\n", argv[0]); 
    code = -1; 
    return (0); 
  } 
 
  oldargv1 = argv[1]; 
  oldargv2 = argv[2]; 
 
  if (!globulize(&argv[2])) { 
    code = -1; 
    return (0); 
  } 
 
  if (loc && mcase) { 
    char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; 
	 
    while (*tp && !islower(*tp)) tp++; 
 
    if (!*tp) { 
      tp = argv[2]; 
      tp2 = tmpbuf; 
 
      while ((*tp2 = *tp)) { 
	if (isupper(*tp2)) *tp2 = tolower(*tp2); 
	tp2++; 
	tp++; 
      } 
 
      argv[2] = tmpbuf; 
    } 
  } 
 
  if (loc && ntflag) 
    argv[2] = dotrans(argv[2]); 
  if (loc && mapflag) 
    argv[2] = domap(argv[2]); 
 
  if (restartit) { 
    struct stat stbuf; 
    int ret; 
	 
    ret = stat(argv[2], &stbuf); 
    if (restartit == 1) { 
      if (ret < 0) { 
	fprintf(stderr, "local: %s: %s\n", argv[2], 
		strerror(errno)); 
	return (0); 
      } 
      restart_point = stbuf.st_size; 
    } else { 
      if (ret == 0) { 
	int overbose; 
		 
	overbose = verbose; 
	if (debug == 0) 
	  verbose = -1; 
	if (command("MDTM %s", argv[1]) == COMPLETE) { 
	  int yy, mo, day, hour, min, sec; 
	  struct tm *tm; 
	  verbose = overbose; 
	  sscanf(reply_string, 
		 "%*s %04d%02d%02d%02d%02d%02d", 
		 &yy, &mo, &day, &hour, &min, &sec); 
	  tm = gmtime(&stbuf.st_mtime); 
	  tm->tm_mon++; 
	  if (tm->tm_year > yy%100) 
	    return (1); 
	  else if (tm->tm_year == yy%100) { 
	    if (tm->tm_mon > mo) 
	      return (1); 
	  } else if (tm->tm_mon == mo) { 
	    if (tm->tm_mday > day) 
	      return (1); 
	  } else if (tm->tm_mday == day) { 
	    if (tm->tm_hour > hour) 
	      return (1); 
	  } else if (tm->tm_hour == hour) { 
	    if (tm->tm_min > min) 
	      return (1); 
	  } else if (tm->tm_min == min) { 
	    if (tm->tm_sec > sec) 
	      return (1); 
	  } 
	} else { 
	  printf("%s\n", reply_string); 
	  verbose = overbose; 
	  return (0); 
	} 
      } 
    } 
  } 
     
  recvrequest("RETR", argv[2], argv[1], mode, 
	      argv[1] != oldargv1 || argv[2] != oldargv2); 
  restart_point = 0; 
  return (0); 
} 
 
void reget(int argc, char *argv[]) { 
  getit(argc, argv, 1, "r+w"); 
} 
 
void get(int argc, char *argv[]){ 
  getit(argc, argv, 0, restart_point ? "r+w" : "w" ); 
} 
 
/* Get multiple files.                                                       */ 
void mget(int argc, char **argv) { 
  extern jmp_buf jabort; 
  sig_t oldintr; 
  int ointer; 
 
  char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; 
  void mabort(); 
 
  if (argc < 2 && !another(&argc, &argv, "remote-files")) { 
    printf("usage: %s remote-files\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  mname = argv[0]; 
  mflag = 1; 
  oldintr = (sig_t)Signal(SIGINT,mabort); 
  setjmp(jabort); 
 
  while ((cp = remglob(argv,proxy)) != NULL) { 
    if (*cp == '\0') { 
      mflag = 0; 
      continue; 
    } 
 
    if (mflag && confirm(argv[0], cp)) { 
      tp = cp; 
      if (mcase) { 
	while (*tp && !islower(*tp)) { 
	  tp++; 
	} 
	if (!*tp) { 
	  tp = cp; 
	  tp2 = tmpbuf; 
		     
	  while ((*tp2 = *tp)) { 
	    if (isupper(*tp2)) *tp2 = tolower(*tp2); 
	    tp2++; 
	    tp++; 
	  } 
	} 
	tp = tmpbuf; 
      } 
 
      if (ntflag) { 
	tp = dotrans(tp); 
      } 
 
      if (mapflag) { 
	tp = domap(tp); 
      } 
 
      recvrequest("RETR", tp, cp, "w", tp != cp || !interactive); 
 
      if (!mflag && fromatty) { 
	ointer = interactive; 
	interactive = 1; 
 
	if (confirm("Continue with","mget")) { 
	  mflag++; 
	} 
	interactive = ointer; 
      } 
    } 
  } 
 
  Signal(SIGINT,oldintr); 
  mflag = 0; 
} 
 
char *remglob(char *argv[], int doswitch) { 
  char temp[16]; 
  static char buf[MAXPATHLEN]; 
  static FILE *ftemp = NULL; 
  static char **args; 
  int oldverbose, oldhash; 
  char *cp, *mode; 
 
  if (!mflag) { 
    if (!doglob) { 
      args = NULL; 
    } 
    else { 
      if (ftemp) { 
	fclose(ftemp); 
	ftemp = NULL; 
      } 
    } 
    return(NULL); 
  } 
  if (!doglob) { 
    if (args == NULL) 
      args = argv; 
    if ((cp = *++args) == NULL) 
      args = NULL; 
    return (cp); 
  } 
  if (ftemp == NULL) { 
    strcpy(temp, _PATH_TMP); 
    mktemp(temp); 
    oldverbose = verbose, verbose = 0; 
    oldhash = hash, hash = 0; 
    if (doswitch) { 
      pswitch(!proxy); 
    } 
    for (mode = "w"; *++argv != NULL; mode = "a") 
      recvrequest ("NLST", temp, *argv, mode, 0); 
    if (doswitch) { 
      pswitch(!proxy); 
    } 
    verbose = oldverbose; hash = oldhash; 
    ftemp = fopen(temp, "r"); 
    unlink(temp); 
    if (ftemp == NULL) { 
      printf("can't find list of remote files, oops\n"); 
      return (NULL); 
    } 
  } 
  if (fgets(buf, sizeof (buf), ftemp) == NULL) { 
    fclose(ftemp), ftemp = NULL; 
    return (NULL); 
  } 
  if ((cp = index(buf, '\n')) != NULL) 
    *cp = '\0'; 
  return (buf); 
} 
 
char *onoff(int bool) { 
  return (bool ? "on" : "off"); 
} 
 
/* Show status.                                                              */ 
/*                                                                           */ 
/* ARGSUSED                                                                  */ 
void status(int argc, char *argv[]) { 
  int i; 
 
  if (connected) { 
    printf("Connected to %s.\n", hostname); 
  } else { 
    printf("Not connected.\n"); 
  } 
 
  if (!proxy) { 
    pswitch(1); 
    if (connected) { 
      printf("Connected for proxy commands to %s.\n", hostname); 
    } else { 
      printf("No proxy connection.\n"); 
    } 
    pswitch(0); 
  } 
 
  printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 
	 modename, typename, formname, structname); 
  printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",  
	 onoff(verbose), onoff(bell), onoff(interactive), 
	 onoff(doglob)); 
  printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 
	 onoff(runique)); 
  printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); 
 
  if (ntflag) { 
    printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); 
  } else { 
    printf("Ntrans: off\n"); 
  } 
 
  if (mapflag) { 
    printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 
  } else { 
    printf("Nmap: off\n"); 
  } 
     
  printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 
	 onoff(hash), onoff(sendport)); 
 
  if (macnum > 0) { 
    printf("Macros:\n"); 
    for (i=0; i 1) { 
    val = atoi(argv[1]); 
    if (val < 0) { 
      printf("%s: bad debugging value.\n", argv[1]); 
      code = -1; 
      return; 
    } 
  } else 
    val = !debug; 
  debug = val; 
  if (debug) 
    options |= SO_DEBUG; 
  else 
    options &= ~SO_DEBUG; 
 
  printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 
  code = debug > 0; 
} 
 
/* Set current working directory on remote machine.                          */ 
void cd(int argc, char **argv) { 
  if (argc < 2 && !another(&argc, &argv, "remote-directory")) { 
    printf("usage: %s remote-directory\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  if (command("CWD %s", argv[1]) == ERROR && code == 500) { 
    if (verbose) printf("CWD command not recognized, trying XCWD\n"); 
    command("XCWD %s", argv[1]); 
  } 
} 
 
/* Set current working directory on local machine.                           */ 
void lcd(int argc, char **argv) { 
  char buf[MAXPATHLEN]; 
 
  if (argc < 2) 
    argc++, argv[1] = home; 
  if (argc != 2) { 
    printf("usage: %s local-directory\n", argv[0]); 
    code = -1; 
    return; 
  } 
  if (!globulize(&argv[1])) { 
    code = -1; 
    return; 
  } 
  if (chdir(argv[1]) < 0) { 
    fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno)); 
    code = -1; 
    return; 
  } 
#ifdef HAVE_GETCWD 
  printf("Local directory now %s\n", getcwd(buf, MAXPATHLEN-1)); 
#else 
  printf("Local directory now %s\n", getwd(buf)); 
#endif 
  code = 0; 
} 
 
/* Delete a single file.                                                     */ 
void delete(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "remote-file")) { 
    printf("usage: %s remote-file\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  command("DELE %s", argv[1]); 
} 
 
/* Delete multiple files.                                                    */ 
void mdelete(int argc, char *argv[]) { 
  extern jmp_buf jabort; 
  sig_t oldintr; 
  int ointer; 
  char *cp; 
  void mabort(); 
     
  if (argc < 2 && !another(&argc, &argv, "remote-files")) { 
    printf("usage: %s remote-files\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  mflag = 1; 
  mname = argv[0]; 
  oldintr = (sig_t)Signal(SIGINT, mabort); 
  setjmp(jabort); 
 
  while ((cp = remglob(argv,0)) != NULL) { 
    if (*cp == '\0') { 
      mflag = 0; 
      continue; 
    } 
 
    if (mflag && confirm(argv[0], cp)) { 
      command("DELE %s", cp); 
      if (!mflag && fromatty) { 
	ointer = interactive; 
	interactive = 1; 
	if (confirm("Continue with", "mdelete")) { 
	  mflag++; 
	} 
	interactive = ointer; 
      } 
    } 
  } 
 
  Signal(SIGINT, oldintr); 
  mflag = 0; 
} 
 
/* Rename a remote file.                                                     */ 
void renamefile(int argc, char *argv[]) { 
 
  if (argc < 2 && !another(&argc, &argv, "from-name")) 
    goto usage; 
  if (argc < 3 && !another(&argc, &argv, "to-name")) { 
  usage: 
    printf("%s from-name to-name\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  if (command("RNFR %s", argv[1]) == CONTINUE) 
    command("RNTO %s", argv[2]); 
} 
 
/* Get a directory listing                                                   */ 
/* of remote files.                                                          */ 
void ls(int argc, char *argv[]) { 
  char *cmd; 
 
  if (argc < 2) argc++, argv[1] = NULL; 
  if (argc < 3) argc++, argv[2] = "-"; 
 
  if (argc > 3) { 
    printf("usage: %s remote-directory local-file\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; 
 
  if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 
    code = -1; 
    return; 
  } 
 
  if (strcmp(argv[2], "-") && *argv[2] != '|') 
    if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { 
      code = -1; 
      return; 
    } 
 
  recvrequest(cmd, argv[2], argv[1], "w", 0); 
} 
 
/* Get a directory listing                                                   */ 
/* of multiple remote files.                                                 */ 
void mls(int argc, char **argv) { 
  extern jmp_buf jabort; 
  sig_t oldintr; 
  int ointer, i; 
  char *cmd, mode[1], *dest; 
  void mabort(); 
 
  if (argc < 2 && !another(&argc, &argv, "remote-files")) 
    goto usage; 
  if (argc < 3 && !another(&argc, &argv, "local-file")) { 
  usage: 
    printf("usage: %s remote-files local-file\n", argv[0]); 
    code = -1; 
    return; 
  } 
  dest = argv[argc - 1]; 
  argv[argc - 1] = NULL; 
  if (strcmp(dest, "-") && *dest != '|') 
    if (!globulize(&dest) || 
	!confirm("output to local-file:", dest)) { 
      code = -1; 
      return; 
    } 
  cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 
  mname = argv[0]; 
  mflag = 1; 
  oldintr = (sig_t)Signal(SIGINT, mabort); 
  setjmp(jabort); 
  for (i = 1; mflag && i < argc-1; ++i) { 
    *mode = (i == 1) ? 'w' : 'a'; 
    recvrequest(cmd, dest, argv[i], mode, 0); 
    if (!mflag && fromatty) { 
      ointer = interactive; 
      interactive = 1; 
      if (confirm("Continue with", argv[0])) { 
	mflag ++; 
      } 
      interactive = ointer; 
    } 
  } 
  Signal(SIGINT, oldintr); 
  mflag = 0; 
} 
 
/* Do a shell escape                                                         */ 
/*                                                                           */ 
/* ARGSUSED                                                                  */ 
int shell(int argc, char **argv) { 
  int pid; 
  sig_t old1, old2; 
  char shellnam[40], *shell, *namep;  
  int  status; 
  old1 = (sig_t)Signal (SIGINT, SIG_IGN); 
  old2 = (sig_t)Signal (SIGQUIT, SIG_IGN); 
  if ((pid = fork()) == 0) { 
    for (pid = 3; pid < 20; pid++) 
      close(pid); 
    Signal(SIGINT, SIG_DFL); 
    Signal(SIGQUIT, SIG_DFL); 
    shell = getenv("SHELL"); 
    if (shell == NULL) 
      shell = _PATH_BSHELL; 
    namep = rindex(shell,'/'); 
    if (namep == NULL) 
      namep = shell; 
    strcpy(shellnam,"-"); 
    strcat(shellnam, ++namep); 
    if (strcmp(namep, "sh") != 0) 
      shellnam[0] = '+'; 
    if (debug) { 
      printf ("%s\n", shell); 
      fflush (stdout); 
    } 
    if (argc > 1) { 
      execl(shell,shellnam,"-c",altarg,(char *)0); 
    } 
    else { 
      execl(shell,shellnam,(char *)0); 
    } 
    perror(shell); 
    code = -1; 
    exit(1); 
  } 
  if (pid > 0) 
    while (wait(&status) != pid) ; 
  Signal(SIGINT, old1); 
  Signal(SIGQUIT, old2); 
  if (pid == -1) { 
    perror("Try again later"); 
    code = -1; 
  } 
  else { 
    code = 0; 
  } 
  return (0); 
} 
 
/* Send new user information (re-login)                                      */ 
int user(int argc, char **argv) { 
  char acct[80], *getpass(); 
  int n, aflag = 0; 
 
  if (argc < 2) { 
    another(&argc, &argv, "username"); 
  } 
 
  if (argc < 2 || argc > 4) { 
    printf("usage: %s username [password] [account]\n", argv[0]); 
    code = -1; 
    return (0); 
  } 
 
  if ((n = command("USER %s", argv[1])) == CONTINUE) { 
    if (argc < 3 ){ 
      if (!strcmp(argv[1], "anonymous") || !strcmp(argv[1], "ftp")) { 
	printf("Password: "); fflush(stdout); 
	fgets(acct, sizeof(acct) - 1, stdin); 
	acct[strlen(acct) - 1] = '\0'; 
	argv[2] = acct; 
      } else 
	argv[2] = getpass("Password: "); 
      argc++; 
    } 
    n = command("PASS %s", argv[2]); 
  } 
 
  if (n == CONTINUE) { 
    if (argc < 4) { 
      printf("Account: "); fflush(stdout); 
      fgets(acct, sizeof(acct) - 1, stdin); 
      acct[strlen(acct) - 1] = '\0'; 
      argv[3] = acct; argc++; 
    } 
    n = command("ACCT %s", argv[3]); 
    aflag++; 
  } 
  if (n != COMPLETE) { 
    fprintf(stdout, "Login failed.\n"); 
    return (0); 
  } 
  if (!aflag && argc == 4) { 
    command("ACCT %s", argv[3]); 
  } 
  return (1); 
} 
 
/* Print working directory.                                                  */ 
/*                                                                           */ 
/* VARARGS                                                                   */ 
void pwd() { 
  int oldverbose = verbose; 
 
  /* If we aren't verbose, this doesn't do anything!                         */ 
  verbose = 1; 
  if (command("PWD") == ERROR && code == 500) { 
    printf("PWD command not recognized, trying XPWD\n"); 
    command("XPWD"); 
  } 
  verbose = oldverbose; 
} 
 
/* Make a directory.                                                         */ 
void makedir(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "directory-name")) { 
    printf("usage: %s directory-name\n", argv[0]); 
    code = -1; 
    return; 
  } 
  if (command("MKD %s", argv[1]) == ERROR && code == 500) { 
    if (verbose) 
      printf("MKD command not recognized, trying XMKD\n"); 
    command("XMKD %s", argv[1]); 
  } 
} 
 
/* Remove a directory.                                                       */ 
void removedir(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "directory-name")) { 
    printf("usage: %s directory-name\n", argv[0]); 
    code = -1; 
    return; 
  } 
  if (command("RMD %s", argv[1]) == ERROR && code == 500) { 
    if (verbose) 
      printf("RMD command not recognized, trying XRMD\n"); 
    command("XRMD %s", argv[1]); 
  } 
} 
 
/* Turn argv[1..argc) into a space-separated string, then prepend initial    */ 
/* text.  Send the result as a one-line command and get response.            */ 
void quote1(char *initial, int argc, char **argv) { 
  register int i, len; 
  char buf[BUFSIZ];		/* must be >= sizeof(line) */ 
 
  strcpy(buf, initial); 
  if (argc > 1) { 
    len = strlen(buf); 
    len += strlen(strcpy(&buf[len], argv[1])); 
    for (i = 2; i < argc; i++) { 
      buf[len++] = ' '; 
      len += strlen(strcpy(&buf[len], argv[i])); 
    } 
  } 
  if (command(buf) == PRELIM) { 
    while (getreply(0) == PRELIM); 
  } 
} 
 
/* Send a line, verbatim, to the remote machine.                             */ 
void quote(int argc, char *argv[]) {  
  if (argc < 2 && !another(&argc, &argv, "command line to send")) { 
    printf("usage: %s line-to-send\n", argv[0]); 
    code = -1; 
    return; 
  } 
  quote1("", argc, argv); 
} 
 
/* Send a SITE command to the remote machine.  The line                      */ 
/* is sent verbatim to the remote machine, except that the                   */ 
/* word "SITE" is added at the front.                                        */ 
void site(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 
    printf("usage: %s line-to-send\n", argv[0]); 
    code = -1; 
    return; 
  } 
  quote1("SITE ", argc, argv); 
} 
 
void do_chmod(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "mode")) 
    goto usage; 
  if (argc < 3 && !another(&argc, &argv, "file-name")) { 
  usage: 
    printf("usage: %s mode file-name\n", argv[0]); 
    code = -1; 
    return; 
  } 
  command("SITE CHMOD %s %s", argv[1], argv[2]); 
} 
 
void do_umask(int argc, char *argv[]) { 
  int oldverbose = verbose; 
 
  verbose = 1; 
  command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 
  verbose = oldverbose; 
} 
 
void idletime(int argc, char *argv[]) { 
  int oldverbose = verbose; 
 
  verbose = 1; 
  command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 
  verbose = oldverbose; 
} 
 
/* Ask the other side for help.                                              */ 
void rmthelp(int argc, char *argv[]) { 
  int oldverbose = verbose; 
 
  verbose = 1; 
  command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 
  verbose = oldverbose; 
} 
 
/* Terminate session, but don't exit.                                        */ 
void disconnect() { 
  extern FILE *cout; 
  extern int data; 
 
  if (!connected) 
    return; 
  command("QUIT"); 
  if (cout) { 
    fclose(cout); 
  } 
  cout = NULL; 
  connected = 0; 
  data = -1; 
  if (!proxy) { 
    macnum = 0; 
  } 
} 
 
/* Terminate session and exit.                                               */ 
/*                                                                           */ 
/* VARARGS                                                                   */ 
int quit() { 
  if (connected) disconnect(); 
  pswitch(1); 
 
  if (connected) disconnect(); 
  exit(0); 
 
  return -1; 
} 
 
void fatal(char *msg) { 
  fprintf(stderr, "ftp: %s\n", msg); 
  exit(1); 
} 
 
void account(int argc, char **argv) { 
  char acct[50], *getpass(), *ap; 
 
  if (argc > 1) { 
    ++argv; 
    --argc; 
    strncpy(acct,*argv,49); 
    acct[49] = '\0'; 
    while (argc > 1) { 
      --argc; 
      ++argv; 
      strncat(acct,*argv, 49-strlen(acct)); 
    } 
    ap = acct; 
  } 
  else { 
    ap = getpass("Account:"); 
  } 
  command("ACCT %s", ap); 
} 
 
jmp_buf abortprox; 
 
void proxabort() { 
  extern int proxy; 
 
  if (!proxy) { 
    pswitch(1); 
  } 
  if (connected) { 
    proxflag = 1; 
  } 
  else { 
    proxflag = 0; 
  } 
  pswitch(0); 
  longjmp(abortprox,1); 
} 
 
void doproxy(int argc, char *argv[]) { 
  extern jmp_buf abortprox; 
  register struct cmd *c; 
  struct cmd *getcmd(); 
  sig_t oldintr; 
  void proxabort(); 
     
  if (argc < 2 && !another(&argc, &argv, "command")) { 
    printf("usage: %s command\n", argv[0]); 
    code = -1; 
    return; 
  } 
  c = getcmd(argv[1]); 
  if (c == (struct cmd *) -1) { 
    printf("?Ambiguous command\n"); 
    fflush(stdout); 
    code = -1; 
    return; 
  } 
  if (c == 0) { 
    printf("?Invalid command\n"); 
    fflush(stdout); 
    code = -1; 
    return; 
  } 
  if (!c->c_proxy) { 
    printf("?Invalid proxy command\n"); 
    fflush(stdout); 
    code = -1; 
    return; 
  } 
  if (setjmp(abortprox)) { 
    code = -1; 
    return; 
  } 
  oldintr = (sig_t)Signal(SIGINT, proxabort); 
  pswitch(1); 
  if (c->c_conn && !connected) { 
    printf("Not connected\n"); 
    fflush(stdout); 
    pswitch(0); 
    Signal(SIGINT, oldintr); 
    code = -1; 
    return; 
  } 
  (*c->c_handler)(argc-1, argv+1); 
  if (connected) { 
    proxflag = 1; 
  } 
  else { 
    proxflag = 0; 
  } 
  pswitch(0); 
  Signal(SIGINT, oldintr); 
} 
 
void setcase() { 
  mcase = !mcase; 
  printf("Case mapping %s.\n", onoff(mcase)); 
  code = mcase; 
} 
 
void setcr() { 
  crflag = !crflag; 
  printf("Carriage Return stripping %s.\n", onoff(crflag)); 
  code = crflag; 
} 
 
void setntrans(int argc, char *argv[]) { 
  if (argc == 1) { 
    ntflag = 0; 
    printf("Ntrans off.\n"); 
    code = ntflag; 
    return; 
  } 
  ntflag++; 
  code = ntflag; 
  strncpy(ntin, argv[1], 16); 
  ntin[16] = '\0'; 
  if (argc == 2) { 
    ntout[0] = '\0'; 
    return; 
  } 
  strncpy(ntout, argv[2], 16); 
  ntout[16] = '\0'; 
} 
 
char * 
dotrans(char *name) 
{ 
  static char new[MAXPATHLEN]; 
  char *cp1, *cp2 = new; 
  register int i, ostop, found; 
 
  for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); 
  for (cp1 = name; *cp1; cp1++) { 
    found = 0; 
    for (i = 0; *(ntin + i) && i < 16; i++) { 
      if (*cp1 == *(ntin + i)) { 
	found++; 
	if (i < ostop) { 
	  *cp2++ = *(ntout + i); 
	} 
	break; 
      } 
    } 
    if (!found) { 
      *cp2++ = *cp1; 
    } 
  } 
  *cp2 = '\0'; 
  return(new); 
} 
 
void setnmap(int argc, char *argv[]) { 
  char *cp; 
     
  if (argc == 1) { 
    mapflag = 0; 
    printf("Nmap off.\n"); 
    code = mapflag; 
    return; 
  } 
 
  if (argc < 3 && !another(&argc, &argv, "mapout")) { 
    printf("Usage: %s [mapin mapout]\n",argv[0]); 
    code = -1; 
    return; 
  } 
 
  mapflag = 1; 
  code = 1; 
  cp = index(altarg, ' '); 
 
  if (proxy) { 
    while(*++cp == ' '); 
    altarg = cp; 
    cp = index(altarg, ' '); 
  } 
 
  *cp = '\0'; 
  strncpy(mapin, altarg, MAXPATHLEN - 1); 
  while (*++cp == ' '); 
  strncpy(mapout, cp, MAXPATHLEN - 1); 
} 
 
char *domap(char *name) { 
  static char new[MAXPATHLEN]; 
  register char *cp1 = name, *cp2 = mapin; 
  char *tp[9], *te[9]; 
  int i, toks[9], toknum = 0, match = 1; 
 
  for (i=0; i < 9; ++i) { 
    toks[i] = 0; 
  } 
 
  while (match && *cp1 && *cp2) { 
    switch (*cp2) { 
      case '\\': 
	if (*++cp2 != *cp1) { 
	  match = 0; 
	} 
	break; 
      case '$': 
	if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 
	  if (*cp1 != *(++cp2+1)) { 
	    toks[toknum = *cp2 - '1']++; 
	    tp[toknum] = cp1; 
	    while (*++cp1 && *(cp2+1) != *cp1); 
	    te[toknum] = cp1; 
	  } 
	  cp2++; 
	  break; 
	} 
	/* FALLTHROUGH */ 
      default: 
	if (*cp2 != *cp1) { 
	  match = 0; 
	} 
	break; 
    } 
 
    if (match && *cp1) { 
      cp1++; 
    } 
    if (match && *cp2) { 
      cp2++; 
    } 
  } 
 
  if (!match && *cp1) { 
    /* last token mismatch */ 
    toks[toknum] = 0; 
  } 
 
  cp1  = new; 
  *cp1 = '\0'; 
  cp2  = mapout; 
 
  while (*cp2) { 
    match = 0; 
    switch (*cp2) { 
      case '\\': 
	if (*(cp2 + 1)) { 
	  *cp1++ = *++cp2; 
	} 
	break; 
      case '[': 
    LOOP: 
      if (*++cp2 == '$' && isdigit(*(cp2+1))) {  
	if (*++cp2 == '0') { 
	  char *cp3 = name; 
			 
	  while (*cp3) { 
	    *cp1++ = *cp3++; 
	  } 
	  match = 1; 
	} else if (toks[toknum = *cp2 - '1']) { 
	  char *cp3 = tp[toknum]; 
			 
	  while (cp3 != te[toknum]) { 
	    *cp1++ = *cp3++; 
	  } 
	  match = 1; 
	} 
      } else { 
	while (*cp2 && *cp2 != ',' && *cp2 != ']') { 
	  if (*cp2 == '\\') { 
	    cp2++; 
	  } else if (*cp2 == '$' && isdigit(*(cp2+1))) { 
	    if (*++cp2 == '0') { 
	      char *cp3 = name; 
				 
	      while (*cp3) { 
		*cp1++ = *cp3++; 
	      } 
	    } else if (toks[toknum = *cp2 - '1']) { 
	      char *cp3=tp[toknum]; 
				 
	      while (cp3 != te[toknum]) { 
		*cp1++ = *cp3++; 
	      } 
	    } 
	  } else if (*cp2) { 
	    *cp1++ = *cp2++; 
	  } 
	} 
 
	if (!*cp2) { 
	  printf("nmap: unbalanced brackets\n"); 
	  return(name); 
	} 
 
	match = 1; 
	cp2--; 
      } 
 
      if (match) { 
	while (*++cp2 && *cp2 != ']') { 
	  if (*cp2 == '\\' && *(cp2 + 1)) { 
	    cp2++; 
	  } 
	} 
 
	if (!*cp2) { 
	  printf("nmap: unbalanced brackets\n"); 
	  return(name); 
	} 
 
	break; 
      } 
		 
      switch (*++cp2) { 
	case ',': 
	  goto LOOP; 
	case ']': 
	  break; 
	default: 
	  cp2--; 
	  goto LOOP; 
      } 
 
			 
      break; 
      case '$': 
	if (isdigit(*(cp2 + 1))) { 
	  if (*++cp2 == '0') { 
	    char *cp3 = name; 
			 
	    while (*cp3) { 
	      *cp1++ = *cp3++; 
	    } 
	  } else if (toks[toknum = *cp2 - '1']) { 
	    char *cp3 = tp[toknum]; 
			 
	    while (cp3 != te[toknum]) { 
	      *cp1++ = *cp3++; 
	    } 
	  } 
	  break; 
	} 
 
	/* intentional drop through */ 
      default: 
	*cp1++ = *cp2; 
	break; 
    } 
 
    cp2++; 
  } 
 
  *cp1 = '\0'; 
 
  if (!*new) { 
    return(name); 
  } 
 
  return(new); 
} 
 
void setsunique() { 
  sunique = !sunique; 
  printf("Store unique %s.\n", onoff(sunique)); 
  code = sunique; 
} 
 
void setrunique() { 
  runique = !runique; 
  printf("Receive unique %s.\n", onoff(runique)); 
  code = runique; 
} 
 
/* change directory to perent directory                                      */ 
void cdup() { 
  if (command("CDUP") == ERROR && code == 500) { 
    if (verbose) printf("CDUP command not recognized, trying XCUP\n"); 
    command("XCUP"); 
  } 
} 
 
/* restart transfer at specific point                                        */ 
void restart(int argc, char *argv[]) { 
  extern long atol(); 
 
  if (argc != 2) { 
    printf("restart: offset not specified\n"); 
  } else { 
    restart_point = atol(argv[1]); 
    printf("restarting at %ld. execute get, put or append to initiate transfer\n", (long)restart_point); 
  } 
} 
 
/* show remote system type                                                   */ 
void syst() { 
  command("SYST"); 
} 
 
void macdef(int argc, char *argv[]) { 
  char *tmp; 
  int c; 
 
  if (macnum == 16) { 
    printf("Limit of 16 macros have already been defined\n"); 
    code = -1; 
    return; 
  } 
 
  if (argc < 2 && !another(&argc, &argv, "macro name")) { 
    printf("Usage: %s macro_name\n",argv[0]); 
    code = -1; 
    return; 
  } 
 
  if (interactive) { 
    printf("Enter macro line by line, terminating it with a null line\n"); 
  } 
 
  strncpy(macros[macnum].mac_name, argv[1], 8); 
 
  if (macnum == 0) { 
    macros[macnum].mac_start = macbuf; 
  } else { 
    macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 
  } 
 
  tmp = macros[macnum].mac_start; 
 
  while (tmp != macbuf+4096) { 
    if ((c = getchar()) == EOF) { 
      printf("macdef:end of file encountered\n"); 
      code = -1; 
      return; 
    } 
 
    if ((*tmp = c) == '\n') { 
      if (tmp == macros[macnum].mac_start) { 
	macros[macnum++].mac_end = tmp; 
	code = 0; 
	return; 
      } 
 
      if (*(tmp-1) == '\0') { 
	macros[macnum++].mac_end = tmp - 1; 
	code = 0; 
	return; 
      } 
	     
      *tmp = '\0'; 
    } 
 
    tmp++; 
  } 
 
  while (1) { 
    while ((c = getchar()) != '\n' && c != EOF) /* LOOP */; 
	 
    if (c == EOF || getchar() == '\n') { 
      printf("Macro not defined - 4k buffer exceeded\n"); 
      code = -1; 
      return; 
    } 
  } 
} 
 
/* get size of file on remote machine                                        */ 
void sizecmd(int argc, char *argv[]) { 
  if (argc < 2 && !another(&argc, &argv, "filename")) { 
    printf("usage: %s filename\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  command("SIZE %s", argv[1]); 
} 
 
/* get last modification time of file on remote machine                      */ 
void modtime(int argc, char *argv[]) { 
  int overbose; 
 
  if (argc < 2 && !another(&argc, &argv, "filename")) { 
    printf("usage: %s filename\n", argv[0]); 
    code = -1; 
    return; 
  } 
 
  overbose = verbose; 
     
  if (debug == 0) { 
    verbose = -1; 
  } 
     
  if (command("MDTM %s", argv[1]) == COMPLETE) { 
    int yy, mo, day, hour, min, sec; 
	 
    sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, &day, &hour, &min, &sec); 
    /* might want to print this in local time */ 
    printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], mo, day, yy, hour, min, sec); 
  } else { 
    printf("%s\n", reply_string); 
  } 
 
  verbose = overbose; 
} 
 
/* show status on reomte machine                                             */ 
void rmtstatus(int argc, char *argv[]) { 
  command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 
} 
 
/* get file if modtime is more recent than current file                      */ 
void newer(int argc, char *argv[]) { 
  if (!getit(argc, argv, -1, "w")) return; 
  printf("Local file \"%s\" is newer than remote file \"%s\"\n", argv[1], argv[2]); 
}