home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / ncftp / part01 < prev    next >
Encoding:
Text File  |  1993-11-02  |  60.8 KB  |  2,467 lines

  1. Newsgroups: comp.sources.misc
  2. From: mgleason@cse.unl.edu (Mike Gleason)
  3. Subject: v40i076:  ncftp - Alternative User Interface for FTP, v1.6, Part01/06
  4. Message-ID: <csm-v40i076=ncftp.172127@sparky.Sterling.COM>
  5. X-Md4-Signature: fc310f282b2429355117ad2b56e180f7
  6. Keywords: ncftp
  7. Sender: kent@sparky.sterling.com (Kent Landfield)
  8. Organization: NCEMRSoft
  9. Date: Tue, 2 Nov 1993 23:21:57 GMT
  10. Approved: kent@sparky.sterling.com
  11.  
  12. Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
  13. Posting-number: Volume 40, Issue 76
  14. Archive-name: ncftp/part01
  15. Environment: UNIX, ANSI-C, !SVR4
  16. Supersedes: ncftp: Volume 39, Issue 53-57
  17.  
  18. NcFTP - Alternative user interface for FTP
  19. Version 1.6.0 by Mike Gleason, NCEMRSoft.
  20.  
  21. I used to list the features of ncftp in this blurb, but there are just
  22. too many to list.  Even if you only ftp occasionally, it is worth your
  23. time to install ncftp (or atleast bug your sysadmin to).  If you won't take
  24. my word for it, just ask around, or extract this archive and read the
  25. man page.
  26.  
  27. 1.6.0 is an "evolutionary" upgrade, which consolidates all the previous
  28. patches and adds a little.  1.6 and 1.5 are "interim" versions between
  29. 2.0 which has been suspended indefinitely due to time constraints.
  30.  
  31. Major changes since 1.5.6:
  32.  
  33. * Built-in support for the "term" package, used by Linux, etc.
  34.  
  35. * SCO Xenix, Besta, AIX 2, AIX 3, Dynix/PTX support
  36.  
  37. * Better ISC Unix support.
  38.  
  39. * Several bug fixes.
  40.  
  41. Major changes since 1.0.2:
  42.  
  43. * Supports the Getline (input-edit) and GNU Readline command-line
  44.   editing and history libraries.
  45.  
  46. * Supports the Socks firewall library, and another firewall gateway
  47.   implementation.
  48.  
  49. * Terrific new "recent-sites" file that automatically saves the
  50.   sites you call;  when you open a site in the recent-sites file
  51.   (of course you can abbreviate the names), you start in the
  52.   same directory you were in last time.
  53.  
  54. * Improved on-line help, and tips on how to use the program better
  55.   are printed each time you run the program.
  56.  
  57. * Rewritten man page.
  58.  
  59. * Faster ascii transfers.
  60.  
  61. * Typing 'open' by itself lists all the sites the program knows
  62.   about (the ones in your .netrc and the recent-sites list) so
  63.   you can just pick one.
  64.  
  65. * Enhanced colon-mode, that can dump a file to stdout (ftpcat mode)
  66.   or to a pager.  (i.e. ncftp -c wu:/README >/dev/null).
  67.  
  68. * You can choose whether an open is anonymous by default (like it
  69.   had always been) or a user login by default by setting a new
  70.   program variable.
  71.  
  72. * Bugs fixed.
  73.  
  74. Read the enclosed file, v2_Notes, which explains why I won't be
  75. able to work on the nearly finished, and much improved v2.0.
  76. ---------
  77. #! /bin/sh
  78. # This is a shell archive.  Remove anything before this line, then feed it
  79. # into a shell via "sh file" or similar.  To overwrite existing files,
  80. # type "sh file -c".
  81. # Contents:  README cmds.c
  82. # Wrapped by kent@sparky on Mon Nov  1 16:19:16 1993
  83. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  84. echo If this archive is complete, you will see the following message:
  85. echo '          "shar: End of archive 1 (of 6)."'
  86. if test -f 'README' -a "${1}" != "-c" ; then 
  87.   echo shar: Will not clobber existing file \"'README'\"
  88. else
  89.   echo shar: Extracting \"'README'\" \(15291 characters\)
  90.   sed "s/^X//" >'README' <<'END_OF_FILE'
  91. XIf you are a novice user, and don't know how to compile things, try
  92. Xcontacting your local guru first (get them to do it for you :-).  Please
  93. Xunderstand that I don't have time to walk newbies through the whole
  94. Xinstallation procedure.
  95. X
  96. XOne of these months, I will write a Configure script that does all this for
  97. Xyou. I just don't have time to learn another language (dist-3.0) just to
  98. Xwrite the script! Perhaps for 2.0.
  99. X
  100. X1. READ this entire file.  Part A, below, tells what to do if you want to
  101. X   use NcFTP with a command-line editor.  Part B tells you how to configure
  102. X   the Makefile to compile the program for your system.  Part C tells you
  103. X   how to configure NcFTP's optional features.  Part D tells you how to
  104. X   contact me if you want to report a bug or submit new code to the
  105. X   program.
  106. X
  107. X2. EDIT the Makefile, making any necessary changes described in parts
  108. X   A, B, or C.  Don't forget to read the directions in the Makefile,
  109. X   so you don't forget any needed libraries, etcetera.
  110. X
  111. X3. You can also change the program's default behavior by editing defaults.h.
  112. X   99% of the time you don't need to do this, so you can skip this step.
  113. X
  114. XIf you have problems, you can mail me, but please try your best to install
  115. Xit without my help.  I'm quite tired of responding to lazy SunOS users
  116. Xbecause they didn't bother reading the directions so that they would have
  117. Xknown that they needed to use GCC.  
  118. X
  119. XI _do_ want to hear from you if you have comments or bug reports/fixes.  I
  120. Xwould also like to hear from you if you had a system that wasn't covered
  121. Xin sys.h, so I can add an entry for other users of your system.
  122. X
  123. XThe latest version of ncftp is available in the directory:
  124. X    cse.unl.edu:/pub/mgleason
  125. XThis machine is heavily used by students and faculty alike, so please
  126. Xdo not call during working hours (9AM - 5PM American Central time).  In fact,
  127. XI have a cron entry that changes all the file permissions to public
  128. Xunreadable during that period, so you won't be able to download anyway.
  129. X
  130. XI am grateful to Shari Deiana and the University of Nebraska for making this
  131. Xpossible!
  132. X
  133. X
  134. XPart A.  Installing with a command line editor:
  135. X----------------------------------------------
  136. X
  137. XAs of this release, GNU Readline and Chris Thewalt's Getline command-line
  138. Xediting and history facilities are supported.  Neither are included with the
  139. Xncftp sources.  You can find Getline at:
  140. X  ce.berkeley.edu:/pub/thewalt/getline.tar.Z  (note: use 'ls', not 'dir!')
  141. Xand Readline is in the directory:
  142. X  prep.ai.mit.edu:/pub/gnu
  143. X
  144. XTo install Readline, you will need to know where libreadline.a and the
  145. Xheader <readline/readline.h> are.  You will need to link libreadline.a and
  146. Xlibcurses.a (or libtermcap.a) with ncftp (see the Makefile).  Good luck on
  147. Xtrying to compile it.  It is not an easy thing to do!  In the Makefile, you
  148. Xwill need to add -DREADLINE to PDEFS, add -lreadline -lcurses to LIBS, and
  149. Xedit the HDRDIRS and LIBDIRS lines.  This stuff is already in the Makefile,
  150. Xso you can just uncomment it.
  151. X
  152. XTo install Getline, you need to know where libgetline.a and it's header
  153. X(getline.h) are.  In the Makefile, you'll need to add -lgetline to LIBS and
  154. Xedit the HDRDIRS and LIBDIRS lines.  This stuff is already in the Makefile,
  155. Xso you can just uncomment it.
  156. X
  157. XDO NOT bug me if you can't figure out how to compile Getline or Readline.
  158. XContact their respective authors instead.  It is not essential that you use
  159. Xthem.
  160. X
  161. X
  162. XPart B.  System Dependencies:
  163. X----------------------------
  164. X
  165. XNcFTP may need work-arounds for some things due to the differences
  166. Xin implementations of unix.  The following systems are taken care
  167. Xof automatically.  For these systems, you should just be able to type
  168. X'make' (but proceed to part C):
  169. X
  170. X   Silicon Graphics IRIX
  171. X   AIX
  172. X   SINIX
  173. X   Ultrix
  174. X   NeXT
  175. X   Pyramid OSx
  176. X
  177. XOtherwise you will have to configure ncftp manually.
  178. X
  179. XImportant for "Yellow Pages" users:  Don't forget to link the library
  180. Xthat includes the YP/NIS version of getpwuid(), etc.  Otherwise the program
  181. Xwon't be able to expand ~username/path/name type pathnames, and maybe even
  182. X~/path/name types of pathnames.  If you're wondering why the program isn't
  183. Xopening your rc file, this could be the cause.
  184. X
  185. XYou will need to add these things to the SDEFS line in the Makefile
  186. Xas applicable.  As an example, if I say 'add -DFoobar to SDEFS,' find
  187. Xthe line in the Makefile that reads 'SDEFS=' (or 'SDEFS=-DFoo2') and
  188. Xchange it to 'SDEFS=-DFoobar' (or 'SDEFS=-DFoo2 -DFoobar).  If your
  189. Xsystem is listed below, follow the directions and then you ready to
  190. Xgo to part C, below.
  191. X
  192. X    Sun Microsystems' SunOS/Solaris:  Use an ANSI compiler such as
  193. X      gcc (set CC=gcc in the Makefile), or acc (set CC=acc).
  194. X      The regular 'cc' is not an ANSI compiler.  You could also run
  195. X      something like 'ansi2knr' on the sources and hope it works.
  196. X      You will probably need to link both the curses and termcap
  197. X      libraries if you use -DCURSES (see below).
  198. X
  199. X    Hewlett-Packard HP-UX:  If you have 7.0, you'll need to find
  200. X      a copy of <ftp.h> from somewhere (8.0 has it though). Then
  201. X      set CFLAGS= -Aa.  You may also need to use gcc if your
  202. X      compiler is non-ANSI.  Note that for HP-UX, the default
  203. X      terminal escape codes are for HP terminals, so you should
  204. X      probably link termcap/curses in so it will get the ANSI
  205. X      sequences if you're on a vt100, etc., terminal connected
  206. X      to your HP-UX machine.
  207. X
  208. X    Linux:  For 'term' support, from what I can tell just add
  209. X      the path of 'client.a' to LIBS, and add -DTERM_FTP to SDEFS,
  210. X      to turn on the term specific ftp code.  srivasta@pilgrim.umass.edu
  211. X      supplied the term patch.
  212. X      
  213. X    SCO Unix:  Add -DSCO324 or -DSCO322 (as appropriate) to SDEFS,
  214. X      and -lsocket to LIBS.
  215. X
  216. X    SCO Xenix 2.3.4: Add -DSCOXNX to SDEFS;
  217. X        Try adding -DLINGER if puts don't work.
  218. X        Add "-lsocket -ldir" to LIBS.
  219. X
  220. X    Bull DPX/2: Add -DBULL to SDEFS, add -linet to LIBS, and
  221. X      use gcc.
  222. X
  223. X    Sequent's DYNIX: Use gcc and add -DDYNIX (if necessary) to SDEFS.
  224. X      You may also be short several string functions which you will
  225. X      have to get elsewhere, and perhaps mktime and strftime.
  226. X      You can get all that stuff from the BSD sources (like ftp.uu.net).
  227. X      Please bug Sequent to update their libc library!
  228. X
  229. X    Sequent's Dynix/PTX:  Add -DDYNIXPTX to SDEFS.
  230. X      Add -lsocket -linet -lnsl -lseq to LIBS.
  231. X
  232. X    DEC OSF1/1.3:  Use gcc, Add -DGETCWDSIZET to SDEFS.
  233. X
  234. XIf your system doesn't fit any of those, things will be trickier.  Answer
  235. Xall these questions and add to the SDEFS line.  You may want to try
  236. Xeach option one at a time until everything works.
  237. X
  238. X*  Is your system closer to System V or BSD?  Your SDEFS line should have
  239. Xeither -DBSD or -DSYSV.  If you don't know, try leaving it blank first;
  240. Xsome compilers automatically define it for you.
  241. X
  242. X*  Add -DNO_CONST if your compiler chokes on the const directive.  You
  243. Xwill know if you need to add this if the compiler spits out errors saying
  244. Xit doesn't know what 'const' is.
  245. X
  246. X*  As I said above, you will need to link special libraries if your system
  247. Xis running Yellow Pages.
  248. X
  249. X*  Add -DSYSSELECTH if you need <sys/select.h> included for definitions
  250. Xof fd_set, etc.
  251. X
  252. X*  Add -DNO_UNISTDH if you don't have <unistd.h>.  If the compiler complains
  253. Xabout not being able to open <unistd.h> add this.
  254. X
  255. X*  Add -DNO_STDLIBH if you don't have <stdlib.h>.  If the compiler complains
  256. Xabout not being able to open <stdlib.h> add this.
  257. X
  258. X*  Add -DNO_UTIMEH if you don't have <utime.h>.  If the compiler complains
  259. Xabout not being able to open <utime.h> add this.
  260. X
  261. X*  Add -DNO_MKTIME if you don't have the mktime() system call, and don't
  262. Xfeel like getting the source for it and compiling it in with the program.
  263. XIf you define this, the program will not set the file modification times
  264. Xto match the ones on the remote host (no big deal).
  265. X
  266. X*  Add -DGETPASS if you would rather use the standard getpass() system
  267. Xcall, instead of our version, Getpass(), which takes more than 8
  268. Xcharacters.  You may want to define this if you are having problems
  269. Xcompiling getpass.c.
  270. X
  271. XIf you haven't given up on our Getpass(), you can try adding -DSGTTYB
  272. Xif you want to use a struct sgttyb instead of a struct termio.  By default,
  273. XBSD systems define SGTTYB automatically.  You can also try adding -DTERMIOS
  274. Xto use a POSIX compliant struct termios instead.  Don't pull your hair out
  275. Xtrying to get the Getpass code to compile;  if it gives you problems just
  276. Xdefine -DGETPASS and hope your system's getpass can handle passwords
  277. Xlonger than 8 characters.
  278. X
  279. X*  Add -DBAD_INETADDR if your inet_addr() function returns a struct in_addr
  280. Xinstead of a u_long, as it should (in DG/UX 5.4.1).
  281. X
  282. X*  Add -DBROKEN_MEMCPY if ncftp mysteriously dumps core when trying to open
  283. Xa remote host.  I'm told that this happens because of some problem in System
  284. XV's sockets don't like fprintf (and memcpy).
  285. X
  286. X*  Add -DPTRTYPE=char if your pre-ANSI compiler complains about the
  287. Xway malloc() or free() are used, and in general does not like (void *)
  288. Xas a generic pointer type.
  289. X
  290. X*  Add -DNO_STRFTIME if your system does not have strftime().  If you do,
  291. Xwe won't try to use it.  This means, however, you cannot use ``%'' values
  292. Xin your prompt.
  293. X
  294. X*  Add -DNO_RENAME if your system does not have rename() (or the one it
  295. Xhas is broken).  If you do, we will use our own.
  296. X
  297. X*  Add -DNO_STRSTR if your system does not have strstr().  If you do, we
  298. Xwill use our own.
  299. X
  300. X*  Add -DLINGER if puts to the remote system are incomplete.
  301. X
  302. X*  Add -DNET_ERRNO_H if you need to include <net/errno.h> for definitions
  303. X   of ECONNREFUSED, etcetera.
  304. X
  305. X*  (Optional) Add -DGETCWDSIZET if your system's getcwd() takes a size_t
  306. Xas the second parameter instead of an int.
  307. X
  308. X*  (Optional) Add -DHERROR if you know you have the herror() system
  309. Xcall.
  310. X
  311. X*  (Optional) Add -DU_WAIT if you know your wait system call takes
  312. Xa pointer to a 'union wait.'  Defined automatically if you define
  313. XBSD.
  314. X
  315. X*  (Optional) Add -DHOSTNAME=\"machine.domain.nam\" if your system
  316. Xdoesn't generate it's own hostname.  To check this, compile ncftp
  317. Xthen run it and type 'set.'  Look at the variable anon-password.
  318. XIf the hostname is wrong, or if it is in the form of 'yourlogin' or
  319. X'yourlogin@machine' instead of 'yourlogin@machine.xxx.yyy,'
  320. Xre-compile it with HOSTNAME set to your machine's address, in the
  321. Xform of 'machine.xxx.yyy.'
  322. X
  323. X*  (Optional) Add -DSTRICT_PROTOS if your compiler wants function prototypes
  324. Xfor all functions, not just non-int-returning ones.
  325. X
  326. X
  327. XPart C.  Program Options:
  328. X------------------------
  329. X
  330. XAdd these as applicable to the PDEFS line in the Makefile.
  331. X
  332. X* -DGZCAT=\"path\": If you have the GNU gzip package installed on your system,
  333. X    the program can try paging remote files compressed with gzip _and_ 
  334. X    compress (instead of just compress).  Add -DGZCAT=\"/full/path/to/zcat\"
  335. X    with GZCAT set to the path name of GNU's zcat/gzcat.
  336. X
  337. X*   -DCURSES:  Uses curses library to display boldface, underline, etc.
  338. X    By default ncftp uses hard-coded ANSI escapes (^[[1m etc.) to
  339. X    save the 100k or so the curses library adds.  You will also need
  340. X    to edit the LIBS line in the Makefile to add -lcurses.  You may
  341. X    need to add -ltermcap instead, or both -lcurses and -ltermcap.
  342. X    If you choose to use the termcap library, you may want to also add
  343. X    -DNO_CURSES_H so it does not try to include <curses.h>.
  344. X
  345. X*   -DSYSLOG:  Define this to have ncftp log connections and transfers
  346. X    to the syslog.
  347. X
  348. X*   -DNO_TIPS:  Define if you want to cut a little fat at the expense of
  349. X     novice users.
  350. X
  351. X*   -DGETLINE: If you want to use Chris Thewalt's getline input line editor
  352. X    and history facility, add this (and see below).
  353. X
  354. X*   -DREADLINE:  If you want to use GNU's readline input line editor and
  355. X    history facility, add this (and see the Makefile). If you do this, you
  356. X    also need to add -DCURSES (see above).
  357. X
  358. X*    -DSOCKS: NcFTP is now compatible with the Socks library by David Koblas,
  359. X    at koblas@sgi.com.  This lets you use NcFTP with a "firewall" gateway
  360. X    for enhanced site security.  You can get the latest version from
  361. X    netcom.com:/pub/koblas.  After you have compiled it, compile NcFTP
  362. X    with -DSOCKS added to PDEFS, and the pathname of the Rconnect.o file
  363. X    added to LIBS.
  364. X    
  365. X*    -DTRY_ABOR:  Define if you want to try the 'ABOR' command from ncftp;
  366. X    The aborting code has had some problems, so by default the program
  367. X    'aborts' by continuing to read input but not echoing output.
  368. X
  369. X*   -DDB_ERRS:  Define this if you want my Perror() function to be more
  370. X    verbose.  You may want to do this if you are a programmer examining this
  371. X    code, and want to know where in the source the Perror's are coming
  372. X    from.
  373. X
  374. XPart D.  Sending me patches:
  375. X---------------------------
  376. X
  377. XI apologize in advance for problems that my coding style may cause.  The code
  378. Xitself is formatted such that each indent-level is a tab (intended to be
  379. Xequivalent to 4 spaces), and not spaces nor a combination of tabs and spaces.
  380. XThe reason for this, besides being more logical to me, is that I use a
  381. XMacintosh editor to compose the code and I prefer it's indenting method.
  382. XAnother problem in my coding-style is that I write C-code intended for ANSI
  383. XC compilers.  This means that I will use the new-style function declarations
  384. Xand function prototypes, like:
  385. X
  386. X
  387. X   long Foobar(long, long, char *);
  388. X   long Foobar(long t0, long t1, char *str)
  389. X   {
  390. X   }
  391. X
  392. Xas opposed to:
  393. X
  394. X   long Foobar();
  395. X   long Foobar(t0, t1, str)
  396. X       long t0, t1;
  397. X       char *str;
  398. X   {
  399. X   }
  400. X
  401. XAnother thing may annoy you is that I always use function prototypes for any
  402. Xfunction I call, including functions that return an int.  This is a good
  403. Xpractice that I learned from the Macintosh programming world.  
  404. X
  405. XSo if you send me patches, please conform to my coding style so that 'patch'
  406. Xwon't screw up, and also that some continuity will be preserved.
  407. X
  408. XBefore you make your patch, you should be sure that you are using the most
  409. Xcurrent version of the program.  This is especially important if you are
  410. Xreporting a bug; I may have already fixed it!  See the above info to get it
  411. Xvia ftp.  Major versions are always posted to comp.sources.misc.  Bug reports
  412. Xare posted to comp.sources.bugs.  Patches that need to be posted ASAP are
  413. Xposted to this group first, so it is advisable that you check this group.
  414. X
  415. XIf you make changes to the code, surround your code in #ifdef/#endif blocks.
  416. XInstead of doing things like #ifdef SunOS, use a name that describes the
  417. Xbug fix or feature, and not your system type, like #ifdef NO_UNISTDH,
  418. Xor #ifdef GETLINE.  That way in case another system has the same problem,
  419. Xit can be added to sys.h without cluttering up the source code.  Then, add
  420. Xthe symbol you used to the end of cmds.c, in the 'CPP Hell' part of the
  421. Xversion() command.  You'll see a list of CPP symbols, so just add yours in
  422. Xa similar fashion, like #ifdef GETLINE/DStrs[nDStrs++] = "GETLINE";/#endif.
  423. X
  424. XIf you don't know how to make a patch, here's how to do it.  Things are easy
  425. Xif you've only changed one file.  Then all you need to do pipe the output of
  426. Xdiff -c into a file and send it to me, i.e. "diff -c cmds.c cmds.c.hack >pch."
  427. XIf you've hacked several files, the way I do it is to keep the originals in
  428. Xone directory (you did make a copy of everything first didn't you?) and the
  429. Xrevisions in another directory.  Then you change directory to the one with the
  430. Xoriginals and do "diff -c . ../revisions > ../pch."
  431. X
  432. X--mg (mgleason@cse.unl.edu)
  433. END_OF_FILE
  434.   if test 15291 -ne `wc -c <'README'`; then
  435.     echo shar: \"'README'\" unpacked with wrong size!
  436.   fi
  437.   # end of 'README'
  438. fi
  439. if test -f 'cmds.c' -a "${1}" != "-c" ; then 
  440.   echo shar: Will not clobber existing file \"'cmds.c'\"
  441. else
  442.   echo shar: Extracting \"'cmds.c'\" \(40489 characters\)
  443.   sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
  444. X/* cmds.c */
  445. X
  446. X/*  $RCSfile: cmds.c,v $
  447. X *  $Revision: 14020.14 $
  448. X *  $Date: 93/07/09 11:31:53 $
  449. X */
  450. X
  451. X#include "sys.h"
  452. X
  453. X#include <sys/wait.h>
  454. X
  455. X#include <sys/stat.h>
  456. X#include <arpa/ftp.h>
  457. X#include <setjmp.h>
  458. X#include <signal.h>
  459. X#include <errno.h>
  460. X#include <netdb.h>
  461. X#include <netinet/in.h>
  462. X#include <arpa/inet.h>
  463. X#include <ctype.h>
  464. X
  465. X#ifdef SYSLOG
  466. X#    include <syslog.h>
  467. X#endif
  468. X
  469. X#include "util.h"
  470. X#include "cmds.h"
  471. X#include "main.h"
  472. X#include "ftp.h"
  473. X#include "ftprc.h"
  474. X#include "getpass.h"
  475. X#include "glob.h"
  476. X#include "open.h"
  477. X#include "set.h"
  478. X#include "defaults.h"
  479. X#include "copyright.h"
  480. X
  481. X/* cmds.c globals */
  482. Xint                    curtype;            /* file transfer type */
  483. Xchar                *typeabbrs = "abiet";
  484. Xstr32                curtypename;        /* name of file transfer type */
  485. Xint                    verbose;             /* verbosity level of output */
  486. Xint                    mprompt;            /* interactively prompt on m* cmds */
  487. Xint                    debug;                /* debugging level */
  488. Xint                    options;            /* used during socket creation */
  489. Xint                    macnum;                /* number of defined macros */
  490. Xint                    paging = 0;
  491. Xint                    creating = 0;
  492. Xstruct macel        macros[MAXMACROS];
  493. Xchar                *macbuf;            /* holds ALL macros */
  494. Xjmp_buf                jabort;
  495. Xchar                *mname;                /* name of current m* command */
  496. Xint                    activemcmd;            /* flag: if != 0, then active multi command */
  497. Xint                    warnNoLSFlagsWithWildcards = 0;
  498. X                                        /* Tells whether the user has been
  499. X                                         * warned about not being able to use
  500. X                                         * flags with ls when using wildcards.
  501. X                                         */
  502. Xlongstring            cwd;                /* current remote directory */
  503. Xlongstring            lcwd;                /* current local directory */
  504. XHostname            lasthostname;        /* name of last host w/ lookup(). */
  505. Xint                    logged_in = 0;        /* TRUE if connected and user/pw OK. */
  506. Xint                    is_ls = 0;            /* are we doing an ls?  if so, then
  507. X                                           read input into a line buffer
  508. X                                           for re-use. */
  509. Xextern int                    buffer_only;
  510. Xstruct lslist               *lshead = NULL;    /* hold last output from host */
  511. Xstruct lslist               *lstail = NULL;
  512. X
  513. X/* cmds.c externs */
  514. Xextern char                    *globerr, *home, *reply_string;
  515. Xextern int                    margc, connected, ansi_escapes;
  516. Xextern int                    code, connected;
  517. Xextern int                    toatty, fromatty;
  518. Xextern int                    data, progress_meter, remote_is_unix;
  519. Xextern int                    parsing_rc, keep_recent;
  520. Xextern char                    *altarg, *line, *margv[];
  521. Xextern char                    *globchars;
  522. Xextern Hostname                hostname;
  523. Xextern string                progname, pager, anon_password;
  524. Xextern string                prompt, version, indataline;
  525. Xextern longstring            logfname;
  526. Xextern long                    logsize;
  527. Xextern size_t                xferbufsize;
  528. Xextern struct servent        serv;
  529. Xextern struct cmd            cmdtab[];
  530. Xextern struct userinfo        uinfo;
  531. Xextern FILE                    *cin, *cout, *logf;
  532. Xextern int                    Optind;
  533. Xextern char                    *Optarg;
  534. Xextern int                    Optind;
  535. Xextern char                    *Optarg;
  536. X
  537. X#ifdef STRICT_PROTOS
  538. Xextern int gethostname(char *, int), getdomainname(char *, int);
  539. X#endif
  540. X
  541. X
  542. Xstruct types types[] = {
  543. X    { "ascii",  "A",    TYPE_A, 0 },
  544. X    { "binary", "I",    TYPE_I, 0 },
  545. X    { "image",  "I",    TYPE_I, 0 },
  546. X    { "ebcdic", "E",    TYPE_E, 0 },
  547. X    { "tenex",  "L",    TYPE_L, "8" },
  548. X    { 0 }
  549. X};
  550. X
  551. X
  552. X
  553. Xlong GetDateAndSize(char *fName, unsigned long *mod_time)
  554. X{
  555. X    char *cp, *np;
  556. X    string lsline;
  557. X    long size = 0L;
  558. X    int n, v;
  559. X    struct lslist *savedh, *savedt;
  560. X    
  561. X    *mod_time = 0;
  562. X    v = verbose; verbose = V_QUIET;
  563. X    is_ls = 1;
  564. X    buffer_only = 1;
  565. X    savedh = lshead;
  566. X    savedt = lstail;
  567. X    lshead = NULL;
  568. X    (void) recvrequest("LIST", "-", fName, "w");
  569. X    is_ls = 0;
  570. X    buffer_only = 0;
  571. X    verbose = v;
  572. X    if (lshead == NULL) {
  573. X        PurgeLineBuffer();
  574. X        lshead = savedh;
  575. X        lstail = savedt;
  576. X        goto aa;
  577. X    }
  578. X    (void) Strncpy(lsline, lshead->string);
  579. X    PurgeLineBuffer();
  580. X    lshead = savedh;
  581. X    lstail = savedt;
  582. X
  583. X    if (code >= 400 && code < 500)
  584. X        goto aa;
  585. X
  586. X    /* See if this line looks like a unix-style ls line. 
  587. X     * If so, we can grab the date and size from it.
  588. X     */    
  589. X    if (strpbrk(lsline, "-dlsbcp") == lsline) {
  590. X        /* See if it looks like a typical '-rwxrwxrwx' line. */
  591. X        cp = lsline + 1;
  592. X        if (*cp != 'r' && *cp != '-')
  593. X            goto aa;
  594. X        ++cp;
  595. X        if (*cp != 'w' && *cp != '-')
  596. X            goto aa;
  597. X        cp += 2;
  598. X        if (*cp != 'r' && *cp != '-')
  599. X            goto aa;
  600. X         /* skip mode, links, owner (and possibly group) */
  601. X         for (n = 0; n < 4; n++) {
  602. X             np = cp;
  603. X             while (*cp != '\0' && !isspace(*cp))
  604. X                 cp++;
  605. X             while (*cp != '\0' &&  isspace(*cp))
  606. X                 cp++;
  607. X         }
  608. X         if (!isdigit(*cp))
  609. X             cp = np;    /* back up (no group) */
  610. X         (void) sscanf(cp, "%ld%n", &size, &n);
  611. X         *mod_time = UnLSDate(cp + n + 1);
  612. X
  613. X        if (size < 100) {
  614. X            /* May be the size of a link to the file, instead of the file. */
  615. X            if ((cp = strstr(lsline, " -> ")) != NULL) {
  616. X                /* Yes, it was a link. */
  617. X                size = GetDateAndSize(cp + 4, mod_time); /* Try the file. */
  618. X            }
  619. X        }
  620. X    }    
  621. Xaa:
  622. X    return (size);
  623. X}    /* GetDateAndSize */
  624. X
  625. X
  626. X
  627. X
  628. Xint _settype(char *typename)
  629. X{
  630. X    register struct types    *p;
  631. X    int                        comret, c;
  632. X    string                    cmd;
  633. X    char                    *cp;
  634. X    c = isupper(*typename) ? tolower(*typename) : (*typename);
  635. X    if ((cp = index(typeabbrs, c)) != NULL)
  636. X        p = &types[(int) (cp - typeabbrs)];
  637. X    else {
  638. X        (void) printf("%s: unknown type\n", typename);
  639. X        return USAGE;
  640. X    }
  641. X    if (c == 't')
  642. X        (void) strcpy(cmd, "TYPE L 8");
  643. X    else    
  644. X        (void) sprintf(cmd, "TYPE %s", p->t_mode);
  645. X    comret = command(cmd);
  646. X    if (comret == COMPLETE) {
  647. X        (void) Strncpy(curtypename, p->t_name);
  648. X        curtype = p->t_type;
  649. X    }
  650. X    return NOERR;
  651. X}    /* _settype */
  652. X
  653. X
  654. X
  655. X
  656. Xint SetTypeByNumber(int i)
  657. X{
  658. X    char tstr[4], *tp = tstr, c;
  659. X
  660. X    tp[1] = c = 0;
  661. X    switch (i) {
  662. X        case TYPE_A: c = 'a'; break;
  663. X        case TYPE_I: c = 'b'; break;
  664. X        case TYPE_E: c = 'e'; break;
  665. X        case TYPE_L: c = 't';
  666. X    }
  667. X    *tp = c;
  668. X    return (_settype(tp));
  669. X}    /* SetTypeByNumber */
  670. X
  671. X
  672. X
  673. X
  674. X/*
  675. X * Set transfer type.
  676. X */
  677. Xint settype(int argc, char **argv)
  678. X{
  679. X    int result = NOERR;
  680. X
  681. X    if (argc > 2) {
  682. X        result = USAGE;
  683. X    } else {
  684. X        if (argc < 2)
  685. X            goto xx;
  686. X        result = _settype(argv[1]);
  687. X        if (IS_VVERBOSE)
  688. Xxx:            (void) printf("Using %s mode to transfer files.\n", curtypename);
  689. X    }
  690. X    return result;
  691. X}    /* settype */
  692. X
  693. X
  694. X
  695. X
  696. X/*ARGSUSED*/
  697. Xint setbinary(int argc, char **argv) {    return (_settype("binary")); }
  698. X/*ARGSUSED*/
  699. Xint setascii(int argc, char **argv) {    return (_settype("ascii")); }
  700. X
  701. X
  702. X
  703. X/*
  704. X * Send a single file.
  705. X */
  706. Xint put(int argc, char **argv)
  707. X{
  708. X    char *cmd;
  709. X
  710. X    if (argc == 2) {
  711. X        argc++;
  712. X        argv[2] = argv[1];
  713. X    }
  714. X    if (argc < 2)
  715. X        argv = re_makeargv("(local-file) ", &argc);
  716. X    if (argc < 2) {
  717. Xusage:
  718. X        return USAGE;
  719. X    }
  720. X    if (argc < 3)
  721. X        argv = re_makeargv("(remote-file) ", &argc);
  722. X    if (argc < 3) 
  723. X        goto usage;
  724. X    cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
  725. X    (void) sendrequest(cmd, argv[1], argv[2]);
  726. X    return NOERR;
  727. X}    /* put */
  728. X
  729. X
  730. X
  731. X
  732. X/*
  733. X * Send multiple files.
  734. X */
  735. Xint mput(int argc, char **argv)
  736. X{
  737. X    register int i;
  738. X    Sig_t oldintr;
  739. X    char *tp;
  740. X
  741. X    if (argc < 2)
  742. X        argv = re_makeargv("(local-files) ", &argc);
  743. X    if (argc < 2) {
  744. X        return USAGE;
  745. X    }
  746. X    mname = argv[0];
  747. X    activemcmd = 1;
  748. X    oldintr = Signal(SIGINT, mabort);
  749. X    (void) setjmp(jabort);
  750. X    for (i = 1; i < argc; i++) {
  751. X        register char **cpp, **gargs;
  752. X        char *icopy;
  753. X        
  754. X        /* Make a copy of the argument, because glob() will just copy
  755. X         * the pointer you give it to the glob-arg vector, and blkfree()
  756. X         * will want to free each element of the glob-arg vector
  757. X         * later.
  758. X         */
  759. X        if ((icopy = NewString(argv[i])) == NULL)
  760. X            break;
  761. X        gargs = glob(icopy);
  762. X        if (globerr != NULL) {
  763. X            (void) printf("%s\n", globerr);
  764. X            if (gargs) {
  765. X                blkfree(gargs);
  766. X                Free(gargs);
  767. X            }
  768. X            continue;
  769. X        }
  770. X        for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  771. X            if (activemcmd && confirm(argv[0], *cpp)) {
  772. X                tp = *cpp;
  773. X                (void) sendrequest("STOR", *cpp, tp);
  774. X                if (!activemcmd && fromatty) {
  775. X                    if (confirm("Continue with","mput")) {
  776. X                        activemcmd++;
  777. X                    }
  778. X                }
  779. X            }
  780. X        }
  781. X        if (gargs != NULL) {
  782. X            blkfree(gargs);
  783. X            Free(gargs);
  784. X        }
  785. X    }
  786. X    (void) Signal(SIGINT, oldintr);
  787. X    activemcmd = 0;
  788. X    return NOERR;
  789. X}    /* mput */
  790. X
  791. X
  792. X
  793. X
  794. Xint rem_glob_one(char *pattern)
  795. X{
  796. X    int            oldverbose, result = 0;
  797. X    char        *cp;
  798. X    string        str, tname;
  799. X    FILE        *ftemp;
  800. X
  801. X    /* Check for wildcard characters. */
  802. X    if (*pattern == '|' || strpbrk(pattern, globchars) == NULL)
  803. X        return 0;
  804. X
  805. X    (void) tmp_name(tname);
  806. X    oldverbose = verbose;
  807. X    verbose = V_QUIET;
  808. X    (void) recvrequest ("NLST", tname, pattern, "w");
  809. X    verbose = oldverbose;
  810. X    ftemp = fopen(tname, "r");
  811. X    if (ftemp == NULL || FGets(str, ftemp) == NULL) {
  812. X        if (NOT_VQUIET)
  813. X            (void) printf("%s: no match.\n", pattern);
  814. X        result = -1;
  815. X        goto done;
  816. X    }
  817. X    if ((cp = index(str, '\n')) != NULL)
  818. X        *cp = '\0';
  819. X    (void) strcpy(pattern, str);
  820. X    cp = FGets(str, ftemp);
  821. X    /* It is an error if the pattern matched more than one file. */
  822. X    if (cp != NULL) {
  823. X        if (NOT_VQUIET)
  824. X            (void) printf("?Ambiguous remote file name.\n");
  825. X        result = -2;
  826. X    }
  827. Xdone:
  828. X    if (ftemp != NULL)
  829. X        (void) fclose(ftemp);
  830. X    (void) unlink(tname);
  831. X    return (result);
  832. X}    /* rem_glob_one */
  833. X
  834. X
  835. X
  836. X
  837. X/*
  838. X * Receive (and maybe page) one file.
  839. X */
  840. Xint get(int argc, char **argv)
  841. X{
  842. X    string local_file;
  843. X    char remote_file[256];
  844. X    char *cp;
  845. X    int oldtype = curtype, try_zcat;
  846. X    size_t len;
  847. X
  848. X    /* paging mode is set if the command name is 'page' or 'more.' */
  849. X    paging = (**argv != 'g');
  850. X
  851. X    if (argc < 2)
  852. X        argv = re_makeargv("(remote-file) ", &argc);
  853. X
  854. X    if (argc < 2) {
  855. X        return USAGE;
  856. X    }
  857. X    cp = Strncpy(remote_file, argv[1]);
  858. X    argv[1] = cp;
  859. X    if (rem_glob_one(argv[1]) < 0)
  860. X        return CMDERR;
  861. X
  862. X    if (paging) {
  863. X        try_zcat = 0;
  864. X        len = strlen(remote_file);
  865. X
  866. X        if (len > (size_t) 2) {
  867. X             if (remote_file[len-2] == '.') {
  868. X                /* Check for .Z files. */
  869. X                if (remote_file[len-1] == 'Z')
  870. X                    try_zcat = 1;
  871. X#ifdef GZCAT
  872. X                /* Check for .z (gzip) files. */
  873. X                if (remote_file[len-1] == 'z')
  874. X                    try_zcat = 1;
  875. X#endif    /* GZCAT */
  876. X            }
  877. X        }
  878. X
  879. X#ifdef GZCAT
  880. X        if (len > (size_t) 3) {
  881. X            /* Check for ".gz" (gzip) files. */
  882. X            if (strcmp(remote_file + len - 3, ".gz") == 0)
  883. X                try_zcat = 1;
  884. X        }
  885. X#endif    /* GZCAT */
  886. X
  887. X        /* Run compressed remote files through zcat, then the pager.
  888. X         * If GZCAT was defined, we also try paging gzipped files.
  889. X         * Note that ZCAT is defined to be GZCAT if you defined
  890. X         * GZCAT.
  891. X         */
  892. X        
  893. X         if (try_zcat) {
  894. X            (void) _settype("b");
  895. X            (void) sprintf(local_file, "|%s ", ZCAT);
  896. X            argv[2] = Strncat(local_file, pager);
  897. X        } else {
  898. X            /* Try to use text mode for paging, so newlines get converted. */
  899. X            (void) _settype("a");
  900. X            argv[2] = pager;
  901. X        }
  902. X    } else {
  903. X        /* normal get */
  904. X        if (argc == 2) {
  905. X            (void) Strncpy(local_file, argv[1]);
  906. X            argv[2] = local_file;
  907. X        } else {
  908. X            if (argc < 3)
  909. X                argv = re_makeargv("(local-file) ", &argc);
  910. X            if (argc < 3) 
  911. X                return USAGE;
  912. X            (void) LocalDotPath(argv[2]);
  913. X        }
  914. X    }
  915. X    (void) recvrequest("RETR", argv[2], argv[1], "w");
  916. X    if (paging) {
  917. X        (void) SetTypeByNumber(oldtype);    /* Restore it to what it was. */
  918. X        paging = 0;
  919. X    }
  920. X    return NOERR;
  921. X}    /* get */
  922. X
  923. X
  924. X
  925. X/*ARGSUSED*/
  926. Xvoid mabort SIG_PARAMS
  927. X{
  928. X    (void) printf("\n");
  929. X    (void) fflush(stdout);
  930. X    if (activemcmd && fromatty) {
  931. X        if (confirm("Continue with", mname)) {
  932. X            longjmp(jabort,0);
  933. X        }
  934. X    }
  935. X    activemcmd = 0;
  936. X    longjmp(jabort,0);
  937. X}    /* mabort */
  938. X
  939. X
  940. X
  941. X
  942. X/*
  943. X * Get multiple files.
  944. X */
  945. Xint mget(int argc, char **argv)
  946. X{
  947. X    char *cp;
  948. X    longstring local;
  949. X    Sig_t oldintr;
  950. X
  951. X    if (argc < 2)
  952. X        argv = re_makeargv("(remote-files) ", &argc);
  953. X    if (argc < 2) {
  954. X        return USAGE;
  955. X    }
  956. X    mname = argv[0];
  957. X    activemcmd = 1;
  958. X    oldintr = Signal(SIGINT, mabort);
  959. X    (void) setjmp(jabort);
  960. X    while ((cp = remglob(argv)) != NULL) {
  961. X        if (*cp == '\0') {
  962. X            activemcmd = 0;
  963. X            continue;
  964. X        }
  965. X        if (activemcmd && confirm(argv[0], cp)) {
  966. X            (void) Strncpy(local, cp);
  967. X            (void) recvrequest("RETR", local, cp, "w");
  968. X            if (!activemcmd && fromatty) {
  969. X                if (confirm("Continue with","mget")) {
  970. X                    activemcmd++;
  971. X                }
  972. X            }
  973. X        }
  974. X    }
  975. X    (void) Signal(SIGINT,oldintr);
  976. X    activemcmd = 0;
  977. X    return NOERR;
  978. X}    /* mget */
  979. X
  980. X
  981. X
  982. X
  983. Xchar *remglob(char *argv[])
  984. X{
  985. X    static FILE            *ftemp = NULL;
  986. X    int                    oldverbose, i;
  987. X    char                *cp, *mode;
  988. X    static string        tmpname, str;
  989. X    int                    result, errs;
  990. X
  991. X    if (!activemcmd) {
  992. Xxx:
  993. X        if (ftemp) {
  994. X            (void) fclose(ftemp);
  995. X            ftemp = NULL;
  996. X            (void) unlink(tmpname);
  997. X        }
  998. X        return(NULL);
  999. X    }
  1000. X    if (ftemp == NULL) {
  1001. X        (void) tmp_name(tmpname);
  1002. X        oldverbose = verbose, verbose = V_QUIET;
  1003. X        errs = 0;
  1004. X        for (mode = "w", i=1; argv[i] != NULL; i++, mode = "a") {
  1005. X            result = recvrequest ("NLST", tmpname, argv[i], mode);
  1006. X            if (result < 0) {
  1007. X                fprintf(stderr, "%s: %s.\n",
  1008. X                    argv[i],
  1009. X                    (strpbrk(argv[i], globchars) != NULL) ? "No match" :
  1010. X                        "No such file"
  1011. X                );
  1012. X                errs++;
  1013. X            }
  1014. X        }
  1015. X        if (errs == (i - 1)) {
  1016. X            /* Every pattern was in error, so we can't try anything. */
  1017. X            (void) unlink(tmpname);        /* Shouldn't be there anyway. */
  1018. X            return NULL;
  1019. X        }
  1020. X        verbose = oldverbose;
  1021. X        ftemp = fopen(tmpname, "r");
  1022. X        if (ftemp == NULL) {
  1023. X            PERROR("remglob", tmpname);
  1024. X            return (NULL);
  1025. X        }
  1026. X    }
  1027. X    if (FGets(str, ftemp) == NULL) 
  1028. X        goto xx;
  1029. X    if ((cp = index(str, '\n')) != NULL)
  1030. X        *cp = '\0';
  1031. X    return (str);
  1032. X}    /* remglob */
  1033. X
  1034. X
  1035. X/*
  1036. X * Turn on/off printing of server echo's, messages, and statistics.
  1037. X */
  1038. Xint setverbose(int argc, char **argv)
  1039. X{
  1040. X    if (argc > 1)
  1041. X        set_verbose(argv[1], 0);
  1042. X    else set_verbose(argv[1], -1);
  1043. X    return NOERR;
  1044. X}    /* setverbose */
  1045. X
  1046. X
  1047. X
  1048. X/*
  1049. X * Toggle interactive prompting
  1050. X * during mget, mput, and mdelete.
  1051. X */
  1052. Xint setprompt(int argc, char **argv)
  1053. X{
  1054. X    if (argc > 1)
  1055. X        mprompt = StrToBool(argv[1]);
  1056. X    else mprompt = !mprompt;
  1057. X    if (IS_VVERBOSE)
  1058. X        (void) printf("Interactive prompting for m* commmands %s.\n", onoff(mprompt));
  1059. X    return NOERR;
  1060. X}    /* setprompt */
  1061. X
  1062. X
  1063. X
  1064. X
  1065. Xvoid fix_options(void)
  1066. X{
  1067. X    if (debug)
  1068. X        options |= SO_DEBUG;
  1069. X    else
  1070. X    options &= ~SO_DEBUG;
  1071. X}   /* fix_options */
  1072. X
  1073. X
  1074. X/*
  1075. X * Set debugging mode on/off and/or
  1076. X * set level of debugging.
  1077. X */
  1078. Xint setdebug(int argc, char **argv)
  1079. X{
  1080. X    int val;
  1081. X
  1082. X    if (argc > 1) {
  1083. X        val = StrToBool(argv[1]);
  1084. X        if (val < 0) {
  1085. X            (void) printf("%s: bad debugging value.\n", argv[1]);
  1086. X            return USAGE;
  1087. X        }
  1088. X    } else
  1089. X        val = !debug;
  1090. X    debug = val;
  1091. X    fix_options();
  1092. X    if (IS_VVERBOSE)
  1093. X        (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  1094. X    return NOERR;
  1095. X}    /* debug */
  1096. X
  1097. X
  1098. X
  1099. X/*
  1100. X * Set current working directory
  1101. X * on remote machine.
  1102. X */
  1103. Xint cd(int argc, char **argv)
  1104. X{
  1105. X    if (argc < 2)
  1106. X        argv = re_makeargv("(remote-directory) ", &argc);
  1107. X    if (argc < 2) {
  1108. X        return USAGE;
  1109. X    }
  1110. X    (void) _cd(argv[1]);
  1111. X    return NOERR;
  1112. X}    /* cd */
  1113. X
  1114. X
  1115. X
  1116. X
  1117. Xint implicit_cd(char *dir)
  1118. X{
  1119. X    int i, j = 0;
  1120. X    
  1121. X    if (connected) {
  1122. X        i = verbose;
  1123. X        /* Special verbosity level that ignores errors and prints other stuff,
  1124. X         * so you will get just the unknown command message and not an error
  1125. X         * message from cd.
  1126. X         */
  1127. X        verbose = V_IMPLICITCD;
  1128. X        j = _cd(dir);
  1129. X        verbose = i;
  1130. X    }
  1131. X    return j;
  1132. X}    /* implicit_cd */
  1133. X
  1134. X
  1135. X
  1136. X
  1137. Xint _cd(char *dir)
  1138. X{
  1139. X    register char *cp;
  1140. X    int result = 0;
  1141. X    string str;
  1142. X
  1143. X    if (dir == NULL)
  1144. X        goto getrwd;
  1145. X    /* Won't work because glob really is a ls, so 'cd pu*' will match
  1146. X     * pub/README, pub/file2, etc.
  1147. X     *    if (result = rem_glob_one(dir) < 0)
  1148. X     *    return result;
  1149. X     */
  1150. X    if (strncmp(dir, "CDUP", (size_t) 4) == 0)
  1151. X        (void) Strncpy(str, dir);
  1152. X    else
  1153. X        (void) sprintf(str, "CWD %s", dir);
  1154. X    if (command(str) != 5) {
  1155. Xgetrwd:
  1156. X        (void) quiet_command("PWD");
  1157. X        cp = rindex(reply_string, '\"');
  1158. X        if (cp != NULL) {
  1159. X            result = 1;
  1160. X            *cp = '\0';
  1161. X            cp = index(reply_string, '\"');
  1162. X            if (cp != NULL)
  1163. X                (void) Strncpy(cwd, ++cp);
  1164. X        }
  1165. X    }
  1166. X    dbprintf("Current remote directory is \"%s\"\n", cwd);
  1167. X    return (result);
  1168. X}    /* _cd */
  1169. X
  1170. X
  1171. X
  1172. X
  1173. X/*
  1174. X * Set current working directory
  1175. X * on local machine.
  1176. X */
  1177. Xint lcd(int argc, char **argv)
  1178. X{
  1179. X    if (argc < 2)
  1180. X        argc++, argv[1] = home;
  1181. X    if (argc != 2) {
  1182. X        return USAGE;
  1183. X    }
  1184. X    if (chdir(LocalDotPath(argv[1])) < 0) {
  1185. X        PERROR("lcd", argv[1]);
  1186. X        return CMDERR;
  1187. X    }
  1188. X    (void) get_cwd(lcwd, (int) sizeof(lcwd));
  1189. X    if (NOT_VQUIET) 
  1190. X        (void) printf("Local directory now %s\n", lcwd);
  1191. X    return NOERR;
  1192. X}    /* lcd */
  1193. X
  1194. X
  1195. X
  1196. X
  1197. X/*
  1198. X * Delete a single file.
  1199. X */
  1200. Xint do_delete(int argc, char **argv)
  1201. X{
  1202. X    string str;
  1203. X
  1204. X    if (argc < 2)
  1205. X        argv = re_makeargv("(remote file to delete) ", &argc);
  1206. X    if (argc < 2) {
  1207. X        return USAGE;
  1208. X    }
  1209. X    if (rem_glob_one(argv[1]) == 0) {
  1210. X        (void) sprintf(str, "DELE %s", argv[1]);
  1211. X        (void) command(str);
  1212. X    }
  1213. X    return NOERR;
  1214. X}    /* do_delete */
  1215. X
  1216. X
  1217. X
  1218. X
  1219. X/*
  1220. X * Delete multiple files.
  1221. X */
  1222. Xint mdelete(int argc, char **argv)
  1223. X{
  1224. X    char *cp;
  1225. X    Sig_t oldintr;
  1226. X    string str;
  1227. X
  1228. X    if (argc < 2)
  1229. X        argv = re_makeargv("(remote-files) ", &argc);
  1230. X    if (argc < 2) {
  1231. X        return USAGE;
  1232. X    }
  1233. X    mname = argv[0];
  1234. X    activemcmd = 1;
  1235. X    oldintr = Signal(SIGINT, mabort);
  1236. X    (void) setjmp(jabort);
  1237. X    while ((cp = remglob(argv)) != NULL) {
  1238. X        if (*cp == '\0') {
  1239. X            activemcmd = 0;
  1240. X            continue;
  1241. X        }
  1242. X        if (activemcmd && confirm(argv[0], cp)) {
  1243. X            (void) sprintf(str, "DELE %s", cp);
  1244. X            (void) command(str);
  1245. X            if (!activemcmd && fromatty) {
  1246. X                if (confirm("Continue with", "mdelete")) {
  1247. X                    activemcmd++;
  1248. X                }
  1249. X            }
  1250. X        }
  1251. X    }
  1252. X    (void) Signal(SIGINT, oldintr);
  1253. X    activemcmd = 0;
  1254. X    return NOERR;
  1255. X}    /* mdelete */
  1256. X
  1257. X
  1258. X
  1259. X
  1260. X/*
  1261. X * Rename a remote file.
  1262. X */
  1263. Xint renamefile(int argc, char **argv)
  1264. X{
  1265. X    string str;
  1266. X
  1267. X    if (argc < 2)
  1268. X        argv = re_makeargv("(from-name) ", &argc);
  1269. X    if (argc < 2) {
  1270. Xusage:
  1271. X        return USAGE;
  1272. X    }
  1273. X    if (argc < 3)
  1274. X        argv = re_makeargv("(to-name) ", &argc);
  1275. X    if (argc < 3)
  1276. X        goto usage;
  1277. X    if (rem_glob_one(argv[1]) < 0)
  1278. X        return CMDERR;
  1279. X    (void) sprintf(str, "RNFR %s", argv[1]);
  1280. X    if (command(str) == CONTINUE) {
  1281. X        (void) sprintf(str, "RNTO %s", argv[2]);
  1282. X        (void) command(str);
  1283. X    }
  1284. X    return NOERR;
  1285. X}    /* renamefile */
  1286. X
  1287. X
  1288. X
  1289. X/*
  1290. X * Get a directory listing
  1291. X * of remote files.
  1292. X */
  1293. Xint ls(int argc, char **argv)
  1294. X{
  1295. X    char        *whichcmd, *cp;
  1296. X    str32        lsflags;
  1297. X    string        remote, local, str;
  1298. X    int            listmode, pagemode, i;
  1299. X
  1300. X    PurgeLineBuffer();
  1301. X    pagemode = 0;
  1302. X    switch (**argv) {
  1303. X        case 'p':                            /* pls, pdir, pnlist */
  1304. X            pagemode = 1;
  1305. X            listmode = argv[0][1] == 'd';
  1306. X            break;
  1307. X        case 'd':                            /* dir */
  1308. X            listmode = 1;
  1309. X            break;
  1310. X        default:                            /* ls, nlist */
  1311. X            listmode = 0;
  1312. X    }
  1313. X    whichcmd = listmode ? "LIST" : "NLST";
  1314. X
  1315. X    (void) strncpy(local, (pagemode ? pager : "-"), sizeof(local));
  1316. X    remote[0] = lsflags[0] = 0;
  1317. X    
  1318. X    /* Possible scenarios:
  1319. X     *  1.    ls
  1320. X     *  2.    ls -flags
  1321. X     *  3.    ls directory
  1322. X     *  4.  ls -flags >outfile
  1323. X     *  5.  ls directory >outfile
  1324. X     *  6.  ls -flags directory
  1325. X     *  7.  ls -flags directory >outfile
  1326. X     *
  1327. X     * Note that using a wildcard will choke with flags.  I.e., don't do
  1328. X     * "ls -CF *.tar," but instead do "ls *.tar."
  1329. X     */
  1330. X
  1331. X    for (i=1; i<argc; i++) {
  1332. X        switch (argv[i][0]) {
  1333. X            case '-': 
  1334. X                /*
  1335. X                 * If you give more than one set of flags, concat the each
  1336. X                 * additional set to the first one (without the dash).
  1337. X                 */
  1338. X                (void) strncat(lsflags, (argv[i] + (lsflags[0] == '-')), sizeof(lsflags));
  1339. X                break;
  1340. X            case '|':
  1341. X                (void) Strncpy(local, argv[i]);
  1342. X                LocalDotPath(local + 1);
  1343. X                break;
  1344. X            case '>':
  1345. X                /* We don't want the '>'. */
  1346. X                (void) Strncpy(local, argv[i] + 1);
  1347. X                LocalDotPath(local);
  1348. X                break;
  1349. X            default:  
  1350. X                cp = argv[i];
  1351. X                /*
  1352. X                 * In case you want to get a remote file called '--README--'
  1353. X                 * or '>README,' you can use '\--README--' and '\>README.'
  1354. X                 */
  1355. X                if ((cp[1] != 0) && (*cp == '\\'))
  1356. X                    ++cp;
  1357. X                if (remote[0] != 0) {
  1358. X                    (void) Strncat(remote, " ");
  1359. X                    (void) Strncat(remote, cp);
  1360. X                } else {
  1361. X                    (void) Strncpy(remote, cp);
  1362. X                }
  1363. X        }    /* end switch */    
  1364. X    }        /* end loop */
  1365. X
  1366. X    /*
  1367. X     *    If we are given an ls with some flags, make sure we use 
  1368. X     *    columnized output (-C) unless one column output (-1) is
  1369. X     *    specified.
  1370. X     */
  1371. X    if (!listmode) {
  1372. X        if (lsflags[0] != 0) {
  1373. X            (void) Strncpy(str, lsflags);
  1374. X            for (cp = str + 1; *cp; cp++)
  1375. X                if (*cp == '1')
  1376. X                    goto aa;
  1377. X            (void) sprintf(lsflags, "-FC%s", str + 1);
  1378. X        } else {
  1379. X            if (remote_is_unix)
  1380. X                (void) strcpy(lsflags, "-FC");
  1381. X        }
  1382. X        /* As noted above, we can't use -flags if the user gave a
  1383. X         * wildcard expr.
  1384. X         */
  1385. X        if (remote_is_unix && (strpbrk(remote, globchars) != NULL)) {
  1386. X            lsflags[0] = 0;
  1387. X            /* Warn the user what's going on. */
  1388. X            if ((warnNoLSFlagsWithWildcards == 0) && NOT_VQUIET) {
  1389. X                (void) fprintf(stderr, "Warning: ls flags disabled with wildcard expressions.\n");
  1390. X                warnNoLSFlagsWithWildcards++;
  1391. X            }
  1392. X        }
  1393. X    }
  1394. X
  1395. Xaa:    if ((strcmp(local, "-") != 0) && (local[0] != '|')) {
  1396. X        if (!confirm("Output to local-file: ", local))
  1397. X            return CMDERR;
  1398. X    }
  1399. X    is_ls = 1; /* tells getreply() to start saving input to a buffer. */
  1400. X    (void) Strncpy(str, remote);
  1401. X    if (lsflags[0] && remote[0])
  1402. X        (void) sprintf(remote, "%s%c%s", lsflags, LS_FLAGS_AND_FILE, str);
  1403. X    else
  1404. X        (void) strncpy(remote, lsflags[0] ? lsflags : str, sizeof(remote));
  1405. X    (void) recvrequest(whichcmd, local, (remote[0] == 0 ? NULL : remote), "w");
  1406. X    is_ls=0;
  1407. X    return NOERR;
  1408. X}    /* ls */
  1409. X
  1410. X
  1411. X
  1412. X/*
  1413. X * Do a shell escape
  1414. X */
  1415. X/*ARGSUSED*/
  1416. Xint shell(int argc, char **argv)
  1417. X{
  1418. X    int                pid;
  1419. X    Sig_t            old1, old2;
  1420. X    char            *theShell, *namep;
  1421. X#ifndef U_WAIT
  1422. X    int                Status;
  1423. X#else
  1424. X    union wait        Status;
  1425. X#endif
  1426. X    string            str;
  1427. X
  1428. X    old1 = signal (SIGINT, SIG_IGN);
  1429. X    old2 = signal (SIGQUIT, SIG_IGN);
  1430. X    if ((pid = fork()) == 0) {
  1431. X        for (pid = 3; pid < 20; pid++)
  1432. X            (void) close(pid);
  1433. X        (void) Signal(SIGINT, SIG_DFL);
  1434. X        (void) Signal(SIGQUIT, SIG_DFL);
  1435. X        if ((theShell = getenv("SHELL")) == NULL)
  1436. X            theShell = uinfo.shell;
  1437. X        if (theShell == NULL)
  1438. X            theShell = "/bin/sh";
  1439. X        namep = rindex(theShell, '/');
  1440. X        if (namep == NULL)
  1441. X            namep = theShell;
  1442. X        (void) strcpy(str, "-");
  1443. X        (void) strcat(str, ++namep);
  1444. X        if (strcmp(namep, "sh") != 0)
  1445. X            str[0] = '+';
  1446. X        dbprintf ("%s\n", theShell);
  1447. X        if (argc > 1)
  1448. X            (void) execl(theShell, str, "-c", altarg, (char *)0);
  1449. X        else
  1450. X            (void) execl(theShell, str, (char *)0);
  1451. X        PERROR("shell", theShell);
  1452. X        exit(1);
  1453. X        }
  1454. X    if (pid > 0)
  1455. X        while (wait((void *) &Status) != pid)
  1456. X            ;
  1457. X    (void) Signal(SIGINT, old1);
  1458. X    (void) Signal(SIGQUIT, old2);
  1459. X    if (pid == -1) {
  1460. X        PERROR("shell", "Try again later");
  1461. X    }
  1462. X    return NOERR;
  1463. X}    /* shell */
  1464. X
  1465. X
  1466. X
  1467. X
  1468. X/*
  1469. X * Send new user information (re-login)
  1470. X */
  1471. Xint do_user(int argc, char **argv)
  1472. X{
  1473. X    char            acct[80];
  1474. X    int                n, aflag = 0;
  1475. X    string            str;
  1476. X
  1477. X    if (argc < 2)
  1478. X        argv = re_makeargv("(username) ", &argc);
  1479. X    if (argc > 4) {
  1480. X        return USAGE;
  1481. X    }
  1482. X    (void) sprintf(str, "USER %s", argv[1]);
  1483. X    n = command(str);
  1484. X    if (n == CONTINUE) {
  1485. X        if (argc < 3 )
  1486. X            argv[2] = Getpass("Password: "), argc++;
  1487. X        (void) sprintf(str, "PASS %s", argv[2]);
  1488. X        n = command(str);
  1489. X    }
  1490. X    if (n == CONTINUE) {
  1491. X        if (argc < 4) {
  1492. X            (void) printf("Account: "); (void) fflush(stdout);
  1493. X            (void) FGets(acct, stdin);
  1494. X            acct[strlen(acct) - 1] = '\0';
  1495. X            argv[3] = acct; argc++;
  1496. X        }
  1497. X        (void) sprintf(str, "ACCT %s", argv[3]);
  1498. X        n = command(str);
  1499. X        aflag++;
  1500. X    }
  1501. X    if (n != COMPLETE) {
  1502. X        (void) fprintf(stdout, "Login failed.\n");
  1503. X        logged_in = 0;
  1504. X        return (0);
  1505. X    }
  1506. X    if (!aflag && argc == 4) {
  1507. X        (void) sprintf(str, "ACCT %s", argv[3]);
  1508. X        (void) command(str);
  1509. X    }
  1510. X    logged_in = 1;
  1511. X    CheckRemoteSystemType(0);
  1512. X    return NOERR;
  1513. X}    /* do_user */
  1514. X
  1515. X
  1516. X
  1517. X
  1518. X/*
  1519. X * Print working directory.
  1520. X */
  1521. X/*ARGSUSED*/
  1522. Xint pwd(int argc, char **argv)
  1523. X{
  1524. X    (void) verbose_command("PWD");
  1525. X    return NOERR;
  1526. X}    /* pwd */
  1527. X
  1528. X
  1529. X
  1530. X
  1531. X/*
  1532. X * Make a directory.
  1533. X */
  1534. Xint makedir(int argc, char **argv)
  1535. X{
  1536. X    string str;
  1537. X
  1538. X    if (argc < 2)
  1539. X        argv = re_makeargv("(directory-name) ", &argc);
  1540. X    if (argc < 2) {
  1541. X        return USAGE;
  1542. X    }
  1543. X    (void) sprintf(str, "MKD %s", argv[1]);
  1544. X    (void) command(str);
  1545. X    return NOERR;
  1546. X}    /* makedir */
  1547. X
  1548. X
  1549. X
  1550. X
  1551. X/*
  1552. X * Remove a directory.
  1553. X */
  1554. Xint removedir(int argc, char **argv)
  1555. X{
  1556. X    string str;
  1557. X    if (argc < 2)
  1558. X        argv = re_makeargv("(directory-name) ", &argc);
  1559. X    if (argc < 2) {
  1560. X        return USAGE;
  1561. X    }
  1562. X    if (rem_glob_one(argv[1]) == 0) {
  1563. X        (void) sprintf(str, "RMD %s", argv[1]);
  1564. X        (void) command(str);
  1565. X    }
  1566. X    return NOERR;
  1567. X}    /* removedir */
  1568. X
  1569. X
  1570. X
  1571. X
  1572. X/*
  1573. X * Send a line, verbatim, to the remote machine.
  1574. X */
  1575. Xint quote(int argc, char **argv)
  1576. X{
  1577. X    int i, tmpverbose;
  1578. X    string str;
  1579. X
  1580. X    if (argc < 2)
  1581. X        argv = re_makeargv("(command line to send) ", &argc);
  1582. X    if (argc < 2) {
  1583. X        return USAGE;
  1584. X    }
  1585. X    str[0] = 0;
  1586. X    if (*argv[0] == 's')    /* Command was 'site' instead of 'quote.' */
  1587. X        (void) Strncpy(str, "site ");
  1588. X    (void) Strncat(str, argv[1]);
  1589. X    for (i = 2; i < argc; i++) {
  1590. X        (void) Strncat(str, " ");
  1591. X        (void) Strncat(str, argv[i]);
  1592. X    }
  1593. X    tmpverbose = verbose;
  1594. X    verbose = V_VERBOSE;
  1595. X    if (command(str) == PRELIM) {
  1596. X        while (getreply(0) == PRELIM);
  1597. X    }
  1598. X    verbose = tmpverbose;
  1599. X    return NOERR;
  1600. X}    /* quote */
  1601. X
  1602. X
  1603. X
  1604. X
  1605. X/*
  1606. X * Ask the other side for help.
  1607. X */
  1608. Xint rmthelp(int argc, char **argv)
  1609. X{
  1610. X    string str;
  1611. X
  1612. X    if (argc == 1) (void) verbose_command("HELP");
  1613. X    else {
  1614. X        (void) sprintf(str, "HELP %s", argv[1]);
  1615. X        (void) verbose_command(str);
  1616. X    }
  1617. X    return NOERR;
  1618. X}    /* rmthelp */
  1619. X
  1620. X
  1621. X
  1622. X
  1623. X/*
  1624. X * Terminate session and exit.
  1625. X */
  1626. X/*ARGSUSED*/
  1627. Xint quit(int argc, char **argv)
  1628. X{
  1629. X    close_up_shop();
  1630. X    trim_log();
  1631. X    exit(0);
  1632. X}    /* quit */
  1633. X
  1634. X
  1635. X
  1636. Xvoid close_streams(int wantShutDown)
  1637. X{
  1638. X    if (cout != NULL) {
  1639. X        if (wantShutDown)
  1640. X            (void) shutdown(fileno(cout), 1+1);
  1641. X        (void) fclose(cout);
  1642. X        cout = NULL;
  1643. X    }
  1644. X    if (cin != NULL) {
  1645. X        if (wantShutDown)
  1646. X            (void) shutdown(fileno(cin), 1+1);
  1647. X        (void) fclose(cin);
  1648. X        cin = NULL;
  1649. X    }
  1650. X}    /* close_streams */
  1651. X
  1652. X
  1653. X
  1654. X
  1655. X/*
  1656. X * Terminate session, but don't exit.
  1657. X */
  1658. X/*ARGSUSED*/
  1659. Xint disconnect(int argc, char **argv)
  1660. X{
  1661. X#ifdef SYSLOG
  1662. X    syslog (LOG_INFO, "%s disconnected from %s.", uinfo.username, hostname);
  1663. X#endif
  1664. X
  1665. X    (void) command("QUIT");
  1666. X    close_streams(0);
  1667. X    UpdateRecentSitesList(hostname, cwd);
  1668. X    hostname[0] = cwd[0] = 0;
  1669. X    logged_in = connected = 0;
  1670. X    data = -1;
  1671. X    macnum = 0;
  1672. X    return NOERR;
  1673. X}    /* disconnect */
  1674. X
  1675. X
  1676. X
  1677. Xvoid
  1678. Xclose_up_shop(void)
  1679. X{
  1680. X    static int only_once = 0;
  1681. X    if (only_once++ > 0)
  1682. X        return;
  1683. X    if (connected)
  1684. X        (void) disconnect(0, NULL);
  1685. X    WriteRecentSitesFile();
  1686. X    if (logf != NULL) {
  1687. X        (void) fclose(logf);
  1688. X        logf = NULL;
  1689. X    }
  1690. X}    /* close_up_shop */
  1691. X
  1692. X
  1693. X
  1694. X
  1695. X/*
  1696. X * Glob a local file name specification with
  1697. X * the expectation of a single return value.
  1698. X * Can't control multiple values being expanded
  1699. X * from the expression, we return only the first.
  1700. X */
  1701. Xint globulize(char **cpp)
  1702. X{
  1703. X    char **globbed;
  1704. X
  1705. X    (void) LocalPath(*cpp);
  1706. X    globbed = glob(*cpp);
  1707. X    if (globerr != NULL) {
  1708. X        (void) printf("%s: %s\n", *cpp, globerr);
  1709. X        if (globbed) {
  1710. X            blkfree(globbed);
  1711. X            Free(globbed);
  1712. X        }
  1713. X        return (0);
  1714. X    }
  1715. X    if (globbed) {
  1716. X        *cpp = *globbed++;
  1717. X        /* don't waste too much memory */
  1718. X        if (*globbed) {
  1719. X            blkfree(globbed);
  1720. X            Free(globbed);
  1721. X        }
  1722. X    }
  1723. X    return (1);
  1724. X}    /* globulize */
  1725. X
  1726. X
  1727. X
  1728. X/* change directory to perent directory */
  1729. X/*ARGSUSED*/
  1730. Xint cdup(int argc, char **argv)
  1731. X{
  1732. X    (void) _cd("CDUP");
  1733. X    return NOERR;
  1734. X}    /* cdup */
  1735. X
  1736. X
  1737. X/* show remote system type */
  1738. X/*ARGSUSED*/
  1739. Xint syst(int argc, char **argv)
  1740. X{
  1741. X    (void) verbose_command("SYST");
  1742. X    return NOERR;
  1743. X}    /* syst */
  1744. X
  1745. X
  1746. X
  1747. X
  1748. Xint make_macro(char *name, FILE *fp)
  1749. X{
  1750. X    char            *tmp;
  1751. X    char            *cp;
  1752. X    string            str;
  1753. X    size_t            len;
  1754. X    int                i;
  1755. X
  1756. X    if (macnum == MAXMACROS) {
  1757. X        (void) fprintf(stderr, "Limit of %d macros have already been defined.\n", MAXMACROS);
  1758. X        return -1;
  1759. X    }
  1760. X
  1761. X    /* Make sure macros have unique names.  If 'init' was attempted to be
  1762. X     * redefined, just return, since it was probably cmdOpen() in a redial
  1763. X     * mode which tried to define it again.
  1764. X     */
  1765. X    for (i = 0; i<macnum; i++) {
  1766. X        if (strncmp(name, macros[i].mac_name, (size_t)8) == 0) {
  1767. X            if (parsing_rc) {
  1768. X                /* Just shut up and read in the macro, but don't save it,
  1769. X                 * because we already have it.
  1770. X                 */
  1771. X                while ((cp = FGets(str, fp)) != NULL) {
  1772. X                    /* See if we have a 'blank' line: just whitespace. */
  1773. X                    while (*cp && isspace(*cp)) ++cp;
  1774. X                    if (!*cp)
  1775. X                        break;
  1776. X                }
  1777. X            } else
  1778. X                (void) fprintf(stderr,
  1779. X                    "There is already a macro named '%s.'\n", name);
  1780. X            return -1;
  1781. X        }
  1782. X    }
  1783. X    (void) strncpy(macros[macnum].mac_name, name, (size_t)8);
  1784. X    if (macnum == 0)
  1785. X        macros[macnum].mac_start = macbuf;
  1786. X    else
  1787. X        macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  1788. X    tmp = macros[macnum].mac_start;
  1789. X    while (1) {
  1790. X        cp = FGets(str, fp);
  1791. X        if (cp == NULL) {
  1792. X            /*
  1793. X             * If we had started a macro, we will say it is
  1794. X             * okay to skip the blank line delimiter if we
  1795. X             * are at the EOF.
  1796. X             */
  1797. X            if (tmp > macros[macnum].mac_start)
  1798. X                goto endmac;
  1799. X            (void) fprintf(stderr, "No text supplied for macro \"%s.\"\n", name);
  1800. X        }
  1801. X        /* see if we have a 'blank' line: just whitespace. */
  1802. X        while (*cp && isspace(*cp)) ++cp;
  1803. X        if (*cp == '\0') {
  1804. X            /* Blank line; end this macro. */
  1805. Xendmac:
  1806. X            macros[macnum++].mac_end = tmp;
  1807. X            return 0;
  1808. X        }
  1809. X        /* Add the text of this line to the macro. */
  1810. X        len = strlen(cp) + 1;    /* we need the \0 too. */
  1811. X        if (tmp + len >= macbuf + MACBUFLEN) {
  1812. X            (void) fprintf(stderr, "Macro \"%s\" not defined -- %d byte buffer exceeded.\n", name, MACBUFLEN);
  1813. X            return -1;
  1814. X        }
  1815. X        (void) strcpy(tmp, cp);
  1816. X        tmp += len;
  1817. X    }
  1818. X}    /* make_macro */
  1819. X
  1820. X
  1821. X
  1822. X
  1823. Xint macdef(int argc, char **argv)
  1824. X{
  1825. X    if (argc < 2)
  1826. X        argv = re_makeargv("(macro name) ", &argc);
  1827. X    if (argc != 2) {
  1828. X        (void) domacro(0, NULL);
  1829. X        return USAGE;
  1830. X    }
  1831. X    (void) printf("Enter macro line by line, terminating it with a blank line\n");
  1832. X    (void) make_macro(argv[1], stdin);
  1833. X    return NOERR;
  1834. X}    /* macdef */
  1835. X
  1836. X
  1837. X
  1838. X
  1839. Xint domacro(int argc, char **argv)
  1840. X{
  1841. X    register int            i, j;
  1842. X    register char            *cp1, *cp2;
  1843. X    int                        count = 2, loopflg = 0;
  1844. X    string                    str;
  1845. X    struct cmd                *c;
  1846. X
  1847. X    if (argc < 2) {
  1848. X        /* print macros. */
  1849. X        if (macnum == 0)
  1850. X            (void) printf("No macros defined.\n");
  1851. X        else {
  1852. X            (void) printf("Current macro definitions:\n");
  1853. X            for (i = 0; i < macnum; ++i) {
  1854. X                (void) printf("%s:\n", macros[i].mac_name);
  1855. X                cp1 = macros[i].mac_start;
  1856. X                cp2 = macros[i].mac_end;
  1857. X                while (cp1 < cp2) {
  1858. X                    (void) printf("   > ");
  1859. X                    while (cp1 < cp2 && *cp1)
  1860. X                        putchar(*cp1++);
  1861. X                    ++cp1;
  1862. X                }
  1863. X            }
  1864. X        }
  1865. X        if (argc == 0) return (NOERR);    /* called from macdef(), above. */
  1866. X        argv = re_makeargv("(macro to run) ", &argc);
  1867. X    }            
  1868. X    if (argc < 2) {
  1869. X        return USAGE;
  1870. X    }
  1871. X    for (i = 0; i < macnum; ++i) {
  1872. X        if (!strncmp(argv[1], macros[i].mac_name, (size_t) 9)) {
  1873. X            break;
  1874. X        }
  1875. X    }
  1876. X    if (i == macnum) {
  1877. X        (void) printf("'%s' macro not found.\n", argv[1]);
  1878. X        return USAGE;
  1879. X    }
  1880. X    (void) Strncpy(str, line);
  1881. XTOP:
  1882. X    cp1 = macros[i].mac_start;
  1883. X    while (cp1 != macros[i].mac_end) {
  1884. X        while (isspace(*cp1)) {
  1885. X            cp1++;
  1886. X        }
  1887. X        cp2 = line;
  1888. X        while (*cp1 != '\0') {
  1889. X              switch(*cp1) {
  1890. X                   case '\\':
  1891. X                 *cp2++ = *++cp1;
  1892. X                 break;
  1893. X                case '$':
  1894. X                 if (isdigit(*(cp1+1))) {
  1895. X                    j = 0;
  1896. X                    while (isdigit(*++cp1)) {
  1897. X                      j = 10*j +  *cp1 - '0';
  1898. X                    }
  1899. X                    cp1--;
  1900. X                    if (argc - 2 >= j) {
  1901. X                    (void) strcpy(cp2, argv[j+1]);
  1902. X                    cp2 += strlen(argv[j+1]);
  1903. X                    }
  1904. X                    break;
  1905. X                 }
  1906. X                 if (*(cp1+1) == 'i') {
  1907. X                    loopflg = 1;
  1908. X                    cp1++;
  1909. X                    if (count < argc) {
  1910. X                       (void) strcpy(cp2, argv[count]);
  1911. X                       cp2 += strlen(argv[count]);
  1912. X                    }
  1913. X                    break;
  1914. X                }
  1915. X                /* intentional drop through */
  1916. X                default:
  1917. X                *cp2++ = *cp1;
  1918. X                break;
  1919. X              }
  1920. X              if (*cp1 != '\0') {
  1921. X                    cp1++;
  1922. X              }
  1923. X        }
  1924. X        *cp2 = '\0';
  1925. X        makeargv();
  1926. X        c = getcmd(margv[0]);
  1927. X        if ((c == (struct cmd *) -1) && !parsing_rc) {
  1928. X            (void) printf("?Ambiguous command\n");
  1929. X        } else if (c == NULL && !parsing_rc) {
  1930. X            (void) printf("?Invalid command\n");
  1931. X        } else if (c->c_conn && !connected) {
  1932. X            (void) printf("Not connected.\n");
  1933. X        } else {
  1934. X            if (IS_VVERBOSE)
  1935. X                (void) printf("%s\n",line);
  1936. X            if ((*c->c_handler)(margc, margv) == USAGE)
  1937. X                cmd_usage(c);
  1938. X            (void) strcpy(line, str);
  1939. X            makeargv();
  1940. X            argc = margc;
  1941. X            argv = margv;
  1942. X        }
  1943. X        if (cp1 != macros[i].mac_end) {
  1944. X            cp1++;
  1945. X        }
  1946. X    }
  1947. X    if (loopflg && ++count < argc) {
  1948. X        goto TOP;
  1949. X    }
  1950. X    return NOERR;
  1951. X}    /* domacro */
  1952. X
  1953. X
  1954. X
  1955. X/*
  1956. X * get size of file on remote machine
  1957. X */
  1958. Xint sizecmd(int argc, char **argv)
  1959. X{
  1960. X    string str;
  1961. X
  1962. X    if (argc < 2)
  1963. X        argv = re_makeargv("(remote-file) ", &argc);
  1964. X    if (argc < 2) {
  1965. X        return USAGE;
  1966. X    }
  1967. X    if (rem_glob_one(argv[1]) == 0) {
  1968. X        (void) sprintf(str, "SIZE %s", argv[1]);
  1969. X        (void) verbose_command(str);
  1970. X    }
  1971. X    return NOERR;
  1972. X}    /* sizecmd */
  1973. X
  1974. X
  1975. X
  1976. X
  1977. X/*
  1978. X * get last modification time of file on remote machine
  1979. X */
  1980. Xint modtime(int argc, char **argv)
  1981. X{
  1982. X    int overbose;
  1983. X    string str;
  1984. X
  1985. X    if (argc < 2)
  1986. X        argv = re_makeargv("(remote-file) ", &argc);
  1987. X    if (argc < 2) {
  1988. X        return USAGE;
  1989. X    }
  1990. X    if (rem_glob_one(argv[1]) == 0) {
  1991. X        overbose = verbose;
  1992. X        if (debug == 0)
  1993. X            verbose = V_QUIET;
  1994. X        (void) sprintf(str, "MDTM %s", argv[1]);
  1995. X        if (command(str) == COMPLETE) {
  1996. X            int yy, mo, day, hour, min, sec;
  1997. X            (void) sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  1998. X                &day, &hour, &min, &sec);
  1999. X            /* might want to print this in local time */
  2000. X            (void) printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2001. X                mo, day, yy, hour, min, sec);
  2002. X        } else
  2003. X            (void) fputs(reply_string, stdout);
  2004. X        verbose = overbose;
  2005. X    }
  2006. X    return NOERR;
  2007. X}    /* modtime */
  2008. X
  2009. X
  2010. X
  2011. Xint lookup(int argc, char **argv)
  2012. X{
  2013. X    int i, j, by_name, result = NOERR;
  2014. X    struct hostent *host;        /* structure returned by gethostbyaddr() */
  2015. X    extern int h_errno;
  2016. X#ifdef BAD_INETADDR
  2017. X    struct in_addr addr;        /* address in host order */
  2018. X# define ADDR    addr.s_addr
  2019. X#else
  2020. X    unsigned long addr;            /* address in host order */
  2021. X# define ADDR    addr
  2022. X#endif
  2023. X
  2024. X    if (argc < 2)
  2025. X        argv = re_makeargv("(sitename) ", &argc);
  2026. X    if (argc < 2) {
  2027. X        return USAGE;
  2028. X    }
  2029. X
  2030. X     lasthostname[0] = 0;
  2031. X    for (i=1; i<argc; i++) {
  2032. X        /* does the argument look like an address? */
  2033. X        if (4 == sscanf (argv[i], "%d.%d.%d.%d", &j, &j, &j, &j)) {
  2034. X            /* ip */
  2035. X              addr = inet_addr (argv[i]);
  2036. X              if (ADDR == 0xffffffff) {
  2037. X                 (void) fprintf(stderr, "## could not convert \"%s\" into a valid IP address.\n", argv[i]);
  2038. X                 continue;
  2039. X             }
  2040. X            host = gethostbyaddr ((char *) &ADDR, 4, AF_INET);
  2041. X            by_name = 0;
  2042. X        } else {
  2043. X            /* name */
  2044. X            host = gethostbyname (argv[i]);
  2045. X            by_name = 1;
  2046. X        }
  2047. X        if (host == NULL) {
  2048. X            if (NOT_VQUIET) {
  2049. X                /* gethostxxx error */                
  2050. X                if (h_errno == HOST_NOT_FOUND) {
  2051. X                     (void) printf("%s: lookup error (%d).\n",
  2052. X                         argv[i], h_errno);
  2053. X                     result = h_errno;
  2054. X                 } else {
  2055. X                     (void) printf("%s \"%s\"\n",
  2056. X                         (by_name==0 ? "unknown address" : "unknown host"),
  2057. X                         argv[i]);
  2058. X                     result = 
  2059. X                         h_errno != 0 ? h_errno :
  2060. X                         -1;
  2061. X                }
  2062. X            }
  2063. X         } else {
  2064. X             if (*host->h_name)
  2065. X                 (void) Strncpy(lasthostname, host->h_name);
  2066. X            if (NOT_VQUIET) {
  2067. X                (void) printf("%-32s  ", *host->h_name ? host->h_name : "???");
  2068. X                if (*host->h_addr_list) {
  2069. X                    unsigned long horder;
  2070. X    
  2071. X                    horder = ntohl (*(unsigned long *) *(char **)host->h_addr_list);
  2072. X                    (void) printf ("%lu.%lu.%lu.%lu\n",
  2073. X                        (horder >> 24),
  2074. X                        (horder >> 16) & 0xff,
  2075. X                        (horder >> 8) & 0xff,
  2076. X                        horder & 0xff);
  2077. X                }
  2078. X                else (void) printf("???\n");
  2079. X            }
  2080. X        }
  2081. X    }    /* loop thru all sites */
  2082. X    return result;
  2083. X}    /* lookup */
  2084. X
  2085. X
  2086. X
  2087. X
  2088. Xint getlocalhostname(char *host, size_t size)
  2089. X{
  2090. X    int oldv, r;
  2091. X    char *argv[2];
  2092. X#ifdef HAS_DOMAINNAME
  2093. X    char domain[64];
  2094. X#endif
  2095. X
  2096. X#ifdef HOSTNAME
  2097. X    (void) strncpy(host, HOSTNAME, size);
  2098. X    return NOERR;
  2099. X#else
  2100. X    *host = 0;
  2101. X    if ((r = gethostname(host, size)) == 0) {
  2102. X        oldv = verbose;
  2103. X        verbose = V_QUIET;
  2104. X        argv[0] = "lookup";
  2105. X        (void) sprintf(line, "lookup %s", host);
  2106. X        (void) makeargv();
  2107. X        if (lookup(margc, margv) == 0 && lasthostname[0]) {
  2108. X            (void) _Strncpy(host, lasthostname, size);
  2109. X#ifdef HAS_DOMAINNAME
  2110. X            if (index(host, '.') == NULL) {
  2111. X                if (getdomainname(domain + 1, sizeof(domain) - 1) == 0) {
  2112. X                    domain[0] = '.';
  2113. X                    (void) _Strncat(host, domain, size);
  2114. X                }
  2115. X            }
  2116. X#endif
  2117. X        }
  2118. X        verbose = oldv;
  2119. X    }
  2120. X    return r;
  2121. X#endif
  2122. X}    /* getlocalhostname */
  2123. X
  2124. X
  2125. X
  2126. X
  2127. X/*
  2128. X * show status on remote machine
  2129. X */
  2130. Xint rmtstatus(int argc, char **argv)
  2131. X{
  2132. X    string str;
  2133. X
  2134. X    if (argc > 1) {
  2135. X        (void) sprintf(str, "STAT %s" , argv[1]);
  2136. X        (void) verbose_command(str);
  2137. X    } else (void) verbose_command("STAT");
  2138. X    return NOERR;
  2139. X}    /* rmtstatus */
  2140. X
  2141. X
  2142. X
  2143. X
  2144. X/*
  2145. X * create an empty file on remote machine.
  2146. X */
  2147. Xint create(int argc, char **argv)
  2148. X{
  2149. X    string            str;
  2150. X    FILE            *ftemp;
  2151. X
  2152. X    if (argc < 2)
  2153. X        argv = re_makeargv("(remote-file) ", &argc);
  2154. X    if (argc < 2) {
  2155. X        return USAGE;
  2156. X    }
  2157. X    (void) tmp_name(str);
  2158. X    ftemp = fopen(str, "w");
  2159. X    /* (void) fputc('x', ftemp); */
  2160. X    (void) fclose(ftemp);
  2161. X    creating = 1;
  2162. X    (void) sendrequest("STOR", str, argv[1]);
  2163. X    creating = 0;
  2164. X    (void) unlink(str);
  2165. X    return NOERR;
  2166. X}    /* create */
  2167. X
  2168. X
  2169. X
  2170. X
  2171. X/* show version info */
  2172. X/*ARGSUSED*/
  2173. Xint show_version(int argc, char **argv)
  2174. X{
  2175. X    char    *DStrs[80];
  2176. X    int        nDStrs = 0, i, j;
  2177. X
  2178. X    (void) printf("%-30s %s\n", "NcFTP Version:", version);
  2179. X    (void) printf("%-30s %s\n", "Author:",
  2180. X        "Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu).");
  2181. X
  2182. X/* Now entering CPP hell... */
  2183. X#ifdef __DATE__
  2184. X    (void) printf("%-30s %s\n", "Compile Date:", __DATE__);
  2185. X#endif
  2186. X    (void) printf("%-30s %s (%s)\n", "Operating System:",
  2187. X#ifdef System
  2188. X    System,
  2189. X#else
  2190. X#    ifdef unix
  2191. X    "UNIX",
  2192. X#    else
  2193. X    "??",
  2194. X#    endif
  2195. X#endif
  2196. X#ifdef SYSV
  2197. X        "SYSV");
  2198. X#else
  2199. X#    ifdef BSD
  2200. X            "BSD");
  2201. X#    else
  2202. X            "neither BSD nor SYSV?");
  2203. X#    endif
  2204. X#endif
  2205. X
  2206. X    /* Show which CPP symbols were used in compilation. */
  2207. X#ifdef __GNUC__
  2208. X    DStrs[nDStrs++] = "__GNUC__";
  2209. X#endif
  2210. X#ifdef RINDEX
  2211. X    DStrs[nDStrs++] = "RINDEX";
  2212. X#endif
  2213. X#ifdef CURSES
  2214. X    DStrs[nDStrs++] = "CURSES";
  2215. X#endif
  2216. X#ifdef NO_CURSES_H
  2217. X    DStrs[nDStrs++] = "NO_CURSES_H";
  2218. X#endif
  2219. X#ifdef HERROR
  2220. X    DStrs[nDStrs++] = "HERROR";
  2221. X#endif
  2222. X#ifdef U_WAIT
  2223. X    DStrs[nDStrs++] = "U_WAIT";
  2224. X#endif
  2225. X#if defined(NO_CONST) || defined(const)
  2226. X    DStrs[nDStrs++] = "NO_CONST";
  2227. X#endif
  2228. X#ifdef GETPASS
  2229. X    DStrs[nDStrs++] = "GETPASS";
  2230. X#endif
  2231. X#ifdef HAS_GETCWD
  2232. X    DStrs[nDStrs++] = "HAS_GETCWD";
  2233. X#endif
  2234. X#ifdef GETCWDSIZET
  2235. X    DStrs[nDStrs++] = "GETCWDSIZET";
  2236. X#endif
  2237. X#ifdef HAS_DOMAINNAME
  2238. X    DStrs[nDStrs++] = "HAS_DOMAINNAME";
  2239. X#endif
  2240. X#ifdef HOSTNAME
  2241. X    DStrs[nDStrs++] = "HOSTNAME";
  2242. X#endif
  2243. X#ifdef SYSDIRH
  2244. X    DStrs[nDStrs++] = "SYSDIRH";
  2245. X#endif
  2246. X#ifdef SYSSELECTH
  2247. X    DStrs[nDStrs++] = "SYSSELECTH";
  2248. X#endif
  2249. X#ifdef TERMH
  2250. X    DStrs[nDStrs++] = "TERMH";
  2251. X#endif
  2252. X#ifdef NO_UNISTDH 
  2253. X    DStrs[nDStrs++] = "NO_UNISTDH";
  2254. X#endif
  2255. X#ifdef NO_STDLIBH
  2256. X    DStrs[nDStrs++] = "NO_STDLIBH";
  2257. X#endif
  2258. X#ifdef SYSLOG 
  2259. X    DStrs[nDStrs++] = "SYSLOG";
  2260. X#endif
  2261. X#ifdef BAD_INETADDR
  2262. X    DStrs[nDStrs++] = "BAD_INETADDR";
  2263. X#endif
  2264. X#ifdef SGTTYB
  2265. X    DStrs[nDStrs++] = "SGTTYB";
  2266. X#endif
  2267. X#ifdef TERMIOS
  2268. X    DStrs[nDStrs++] = "TERMIOS";
  2269. X#endif
  2270. X#ifdef STRICT_PROTOS
  2271. X    DStrs[nDStrs++] = "STRICT_PROTOS";
  2272. X#endif
  2273. X#ifdef dFTP_PORT
  2274. X    DStrs[nDStrs++] = "dFTP_PORT";
  2275. X#endif
  2276. X#ifdef BROKEN_MEMCPY
  2277. X    DStrs[nDStrs++] = "BROKEN_MEMCPY";
  2278. X#endif
  2279. X#ifdef READLINE
  2280. X    DStrs[nDStrs++] = "READLINE";
  2281. X#endif
  2282. X#ifdef GETLINE 
  2283. X    DStrs[nDStrs++] = "GETLINE";
  2284. X#endif
  2285. X#ifdef _POSIX_SOURCE
  2286. X    DStrs[nDStrs++] = "_POSIX_SOURCE";
  2287. X#endif
  2288. X#ifdef NO_TIPS
  2289. X    DStrs[nDStrs++] = "NO_TIPS";
  2290. X#endif
  2291. X#ifdef GZCAT
  2292. X    DStrs[nDStrs++] = "GZCAT";
  2293. X#endif
  2294. X#ifdef LINGER
  2295. X    DStrs[nDStrs++] = "LINGER";
  2296. X#endif
  2297. X#ifdef TRY_NOREPLY
  2298. X    DStrs[nDStrs++] = "TRY_NOREPLY";
  2299. X#endif
  2300. X#ifdef NO_UTIMEH 
  2301. X    DStrs[nDStrs++] = "NO_UTIMEH";
  2302. X#endif
  2303. X#ifdef DB_ERRS
  2304. X    DStrs[nDStrs++] = "DB_ERRS";
  2305. X#endif
  2306. X#ifdef NO_VARARGS 
  2307. X    DStrs[nDStrs++] = "NO_VARARGS";
  2308. X#endif
  2309. X#ifdef NO_MKTIME
  2310. X    DStrs[nDStrs++] = "NO_MKTIME";
  2311. X#endif
  2312. X#ifdef NO_STRSTR
  2313. X    DStrs[nDStrs++] = "NO_STRSTR";
  2314. X#endif
  2315. X#ifdef NO_STRFTIME
  2316. X    DStrs[nDStrs++] = "NO_STRFTIME";
  2317. X#endif
  2318. X#ifdef NO_RENAME
  2319. X    DStrs[nDStrs++] = "NO_RENAME";
  2320. X#endif
  2321. X#ifdef TRY_ABOR
  2322. X    DStrs[nDStrs++] = "TRY_ABOR";
  2323. X#endif
  2324. X#ifdef GATEWAY
  2325. X    DStrs[nDStrs++] = "GATEWAY";
  2326. X#endif
  2327. X#ifdef SOCKS
  2328. X    DStrs[nDStrs++] = "SOCKS";
  2329. X#endif
  2330. X#ifdef TERM_FTP
  2331. X    DStrs[nDStrs++] = "TERM_FTP";
  2332. X#endif
  2333. X#ifdef NET_ERRNO_H
  2334. X    DStrs[nDStrs++] = "NET_ERRNO_H";
  2335. X#endif
  2336. X
  2337. X/* DONE with #ifdefs for now! */
  2338. X
  2339. X    (void) printf ("\nCompile Options:\n");
  2340. X    for (i=j=0; i<nDStrs; i++) {
  2341. X        if (j == 0)
  2342. X            (void) printf("    ");
  2343. X        (void) printf("%-15s", DStrs[i]);
  2344. X        if (++j == 4) {
  2345. X            j = 0;
  2346. X            (void) putchar('\n');
  2347. X        }
  2348. X    }
  2349. X    if (j != 0)
  2350. X        (void) putchar('\n');
  2351. X
  2352. X#ifdef MK
  2353. X    (void) printf("\nMK: %s\n", MK);
  2354. X#endif /* MK */
  2355. X
  2356. X    (void) printf("\nDefaults:\n");
  2357. X    (void) printf("\
  2358. X    Xfer Buf Size: %8d   Debug: %d   MPrompt: %d   Verbosity: %d\n\
  2359. X    Prompt: %s   Pager: %s  ZCat: %s\n\
  2360. X    Logname: %s   Logging: %d   Type: %s   Cmd Len: %d\n\
  2361. X    Recv Line Len: %d   #Macros: %d   Macbuf: %d  Auto-Binary: %d\n\
  2362. X    Recent File: %s   Recent On: %d   nRecents: %d\n\
  2363. X    Redial Delay: %d  Anon Open: %d  New Mail Message: \"%s\"\n",
  2364. X        MAX_XFER_BUFSIZE, dDEBUG, dMPROMPT, dVERBOSE,
  2365. X        dPROMPT, dPAGER, ZCAT,
  2366. X        dLOGNAME, dLOGGING, dTYPESTR, CMDLINELEN,
  2367. X        RECEIVEDLINELEN, MAXMACROS, MACBUFLEN, dAUTOBINARY,
  2368. X        dRECENTF, dRECENT_ON, dMAXRECENTS,
  2369. X        dREDIALDELAY, dANONOPEN, NEWMAILMESSAGE
  2370. X    );
  2371. X#ifdef GATEWAY
  2372. X    (void) printf("\
  2373. X    Gateway Login: %s\n", dGATEWAY_LOGIN);
  2374. X#endif
  2375. X    return NOERR;
  2376. X}    /* show_version */
  2377. X
  2378. X
  2379. X
  2380. Xvoid PurgeLineBuffer(void)
  2381. X{
  2382. X    register struct lslist *a, *b;
  2383. X         
  2384. X    for (a = lshead; a != NULL; ) {
  2385. X        b = a->next;
  2386. X        if (a->string)
  2387. X            free(a->string);    /* free string */
  2388. X        Free(a);         /* free node */
  2389. X        a = b;
  2390. X    }
  2391. X    lshead = lstail = NULL;
  2392. X}    /* PurgeLineBuffer */
  2393. X
  2394. X
  2395. X
  2396. X
  2397. X/*ARGSUSED*/
  2398. Xint ShowLineBuffer(int argc, char **argv)
  2399. X{
  2400. X    register struct lslist *a = lshead;
  2401. X    int pagemode;
  2402. X    FILE *fp;
  2403. X    Sig_t oldintp;
  2404. X
  2405. X    if (a == NULL)
  2406. X        return CMDERR;
  2407. X    pagemode= (**argv) == 'p' && pager[0] == '|';
  2408. X    if (pagemode) {
  2409. X        fp = popen(pager + 1, "w");
  2410. X        if (!fp) {
  2411. X            PERROR("ShowLineBuffer", pager + 1);
  2412. X            return CMDERR;
  2413. X        }
  2414. X    } else
  2415. X        fp = stdout;
  2416. X    oldintp = Signal(SIGPIPE, SIG_IGN);
  2417. X    while (a) {
  2418. X        if (a->string)
  2419. X            (void) fprintf(fp, "%s\n", a->string);
  2420. X        a = a->next;
  2421. X    }
  2422. X    if (pagemode)
  2423. X        (void) pclose(fp);
  2424. X    if (oldintp)
  2425. X        (void) Signal(SIGPIPE, oldintp);
  2426. X    return NOERR;
  2427. X}    /* ShowLineBuffer */
  2428. X
  2429. X
  2430. X
  2431. X
  2432. X/*ARGSUSED*/
  2433. Xint unimpl(int argc, char **argv)
  2434. X{
  2435. X    if (!parsing_rc)
  2436. X        (void) printf("%s: command not supported. (and probably won't ever be).\n", argv[0]);
  2437. X    return (NOERR);
  2438. X}    /* unimpl */
  2439. X
  2440. X/* eof cmds.c */
  2441. END_OF_FILE
  2442.   if test 40489 -ne `wc -c <'cmds.c'`; then
  2443.     echo shar: \"'cmds.c'\" unpacked with wrong size!
  2444.   fi
  2445.   # end of 'cmds.c'
  2446. fi
  2447. echo shar: End of archive 1 \(of 6\).
  2448. cp /dev/null ark1isdone
  2449. MISSING=""
  2450. for I in 1 2 3 4 5 6 ; do
  2451.     if test ! -f ark${I}isdone ; then
  2452.     MISSING="${MISSING} ${I}"
  2453.     fi
  2454. done
  2455. if test "${MISSING}" = "" ; then
  2456.     echo You have unpacked all 6 archives.
  2457.     rm -f ark[1-9]isdone
  2458. else
  2459.     echo You still must unpack the following archives:
  2460.     echo "        " ${MISSING}
  2461. fi
  2462. exit 0
  2463. exit 0 # Just in case...
  2464.