GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ftp/cmds.c Lines: 0 745 0.0 %
Date: 2017-11-07 Branches: 0 554 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cmds.c,v 1.79 2017/01/21 08:33:07 krw Exp $	*/
2
/*	$NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $	*/
3
4
/*
5
 * Copyright (C) 1997 and 1998 WIDE Project.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the project nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * Copyright (c) 1985, 1989, 1993, 1994
35
 *	The Regents of the University of California.  All rights reserved.
36
 *
37
 * Redistribution and use in source and binary forms, with or without
38
 * modification, are permitted provided that the following conditions
39
 * are met:
40
 * 1. Redistributions of source code must retain the above copyright
41
 *    notice, this list of conditions and the following disclaimer.
42
 * 2. Redistributions in binary form must reproduce the above copyright
43
 *    notice, this list of conditions and the following disclaimer in the
44
 *    documentation and/or other materials provided with the distribution.
45
 * 3. Neither the name of the University nor the names of its contributors
46
 *    may be used to endorse or promote products derived from this software
47
 *    without specific prior written permission.
48
 *
49
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59
 * SUCH DAMAGE.
60
 */
61
62
#ifndef SMALL
63
64
/*
65
 * FTP User Program -- Command Routines.
66
 */
67
#include <sys/types.h>
68
#include <sys/socket.h>
69
#include <sys/stat.h>
70
#include <sys/wait.h>
71
#include <arpa/ftp.h>
72
73
#include <ctype.h>
74
#include <err.h>
75
#include <fnmatch.h>
76
#include <glob.h>
77
#include <netdb.h>
78
#include <stdio.h>
79
#include <stdlib.h>
80
#include <string.h>
81
#include <unistd.h>
82
#include <errno.h>
83
84
#include "ftp_var.h"
85
#include "pathnames.h"
86
#include "cmds.h"
87
88
/*
89
 * Set ascii transfer type.
90
 */
91
/*ARGSUSED*/
92
void
93
setascii(int argc, char *argv[])
94
{
95
96
	stype[1] = "ascii";
97
	settype(2, stype);
98
}
99
100
/*
101
 * Set file transfer mode.
102
 */
103
/*ARGSUSED*/
104
void
105
setftmode(int argc, char *argv[])
106
{
107
108
	fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
109
	code = -1;
110
}
111
112
/*
113
 * Set file transfer format.
114
 */
115
/*ARGSUSED*/
116
void
117
setform(int argc, char *argv[])
118
{
119
120
	fprintf(ttyout, "We only support %s format, sorry.\n", formname);
121
	code = -1;
122
}
123
124
/*
125
 * Set file transfer structure.
126
 */
127
/*ARGSUSED*/
128
void
129
setstruct(int argc, char *argv[])
130
{
131
132
	fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
133
	code = -1;
134
}
135
136
void
137
reput(int argc, char *argv[])
138
{
139
140
	(void)putit(argc, argv, 1);
141
}
142
143
void
144
put(int argc, char *argv[])
145
{
146
147
	(void)putit(argc, argv, 0);
148
}
149
150
/*
151
 * Send a single file.
152
 */
153
void
154
putit(int argc, char *argv[], int restartit)
155
{
156
	char *cmd;
157
	int loc = 0;
158
	char *oldargv1, *oldargv2;
159
160
	if (argc == 2) {
161
		argc++;
162
		argv[2] = argv[1];
163
		loc++;
164
	}
165
	if (argc < 2 && !another(&argc, &argv, "local-file"))
166
		goto usage;
167
	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
168
usage:
169
		fprintf(ttyout, "usage: %s local-file [remote-file]\n",
170
		    argv[0]);
171
		code = -1;
172
		return;
173
	}
174
	oldargv1 = argv[1];
175
	oldargv2 = argv[2];
176
	if (!globulize(&argv[1])) {
177
		code = -1;
178
		return;
179
	}
180
	/*
181
	 * If "globulize" modifies argv[1], and argv[2] is a copy of
182
	 * the old argv[1], make it a copy of the new argv[1].
183
	 */
184
	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
185
		argv[2] = argv[1];
186
	}
187
	if (restartit == 1) {
188
		if (curtype != type)
189
			changetype(type, 0);
190
		restart_point = remotesize(argv[2], 1);
191
		if (restart_point < 0) {
192
			restart_point = 0;
193
			code = -1;
194
			return;
195
		}
196
	}
197
	if (strcmp(argv[0], "append") == 0) {
198
		restartit = 1;
199
	}
200
	cmd = restartit ? "APPE" : ((sunique) ? "STOU" : "STOR");
201
	if (loc && ntflag) {
202
		argv[2] = dotrans(argv[2]);
203
	}
204
	if (loc && mapflag) {
205
		argv[2] = domap(argv[2]);
206
	}
207
	sendrequest(cmd, argv[1], argv[2],
208
	    argv[1] != oldargv1 || argv[2] != oldargv2);
209
	restart_point = 0;
210
	if (oldargv1 != argv[1])	/* free up after globulize() */
211
		free(argv[1]);
212
}
213
214
/*
215
 * Send multiple files.
216
 */
217
void
218
mput(int argc, char *argv[])
219
{
220
	extern int optind, optreset;
221
	int ch, i, restartit = 0;
222
	sig_t oldintr;
223
	char *cmd, *tp, *xargv[] = { argv[0], NULL, NULL };
224
	const char *errstr;
225
	static int depth = 0, max_depth = 0;
226
227
	optind = optreset = 1;
228
229
	if (depth)
230
		depth++;
231
232
	while ((ch = getopt(argc, argv, "cd:r")) != -1) {
233
		switch(ch) {
234
		case 'c':
235
			restartit = 1;
236
			break;
237
		case 'd':
238
			max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
239
			if (errstr != NULL) {
240
				fprintf(ttyout, "bad depth value, %s: %s\n",
241
				    errstr, optarg);
242
				code = -1;
243
				return;
244
			}
245
			break;
246
		case 'r':
247
			depth = 1;
248
			break;
249
		default:
250
			goto usage;
251
		}
252
	}
253
254
	if (argc - optind < 1 && !another(&argc, &argv, "local-files")) {
255
usage:
256
		fprintf(ttyout, "usage: %s [-cr] [-d depth] local-files\n",
257
		    argv[0]);
258
		code = -1;
259
		return;
260
	}
261
262
	argv[optind - 1] = argv[0];
263
	argc -= optind - 1;
264
	argv += optind - 1;
265
266
	mname = argv[0];
267
	mflag = 1;
268
269
	oldintr = signal(SIGINT, mabort);
270
	(void)setjmp(jabort);
271
	if (proxy) {
272
		char *cp, *tp2, tmpbuf[PATH_MAX];
273
274
		while ((cp = remglob(argv, 0, NULL)) != NULL) {
275
			if (*cp == '\0') {
276
				mflag = 0;
277
				continue;
278
			}
279
			if (mflag && confirm(argv[0], cp)) {
280
				tp = cp;
281
				if (mcase) {
282
					while (*tp && !islower((unsigned char)*tp)) {
283
						tp++;
284
					}
285
					if (!*tp) {
286
						tp = cp;
287
						tp2 = tmpbuf;
288
						while ((*tp2 = *tp) != '\0') {
289
						     if (isupper((unsigned char)*tp2)) {
290
							    *tp2 =
291
								tolower((unsigned char)*tp2);
292
						     }
293
						     tp++;
294
						     tp2++;
295
						}
296
					}
297
					tp = tmpbuf;
298
				}
299
				if (ntflag) {
300
					tp = dotrans(tp);
301
				}
302
				if (mapflag) {
303
					tp = domap(tp);
304
				}
305
				if (restartit == 1) {
306
					off_t ret;
307
308
					if (curtype != type)
309
						changetype(type, 0);
310
					ret = remotesize(tp, 0);
311
					restart_point = (ret < 0) ? 0 : ret;
312
				}
313
				cmd = restartit ? "APPE" : ((sunique) ?
314
				    "STOU" : "STOR");
315
				sendrequest(cmd, cp, tp,
316
				    cp != tp || !interactive);
317
				restart_point = 0;
318
				if (!mflag && fromatty) {
319
					if (confirm(argv[0], NULL))
320
						mflag = 1;
321
				}
322
			}
323
		}
324
		(void)signal(SIGINT, oldintr);
325
		mflag = 0;
326
		return;
327
	}
328
329
	for (i = 1; i < argc; i++) {
330
		char **cpp;
331
		glob_t gl;
332
		int flags;
333
334
		/* Copy files without word expansion */
335
		if (!doglob) {
336
			if (mflag && confirm(argv[0], argv[i])) {
337
				tp = (ntflag) ? dotrans(argv[i]) : argv[i];
338
				tp = (mapflag) ? domap(tp) : tp;
339
				if (restartit == 1) {
340
					off_t ret;
341
342
					if (curtype != type)
343
						changetype(type, 0);
344
					ret = remotesize(tp, 0);
345
					restart_point = (ret < 0) ? 0 : ret;
346
				}
347
				cmd = restartit ? "APPE" : ((sunique) ?
348
				    "STOU" : "STOR");
349
				sendrequest(cmd, argv[i], tp,
350
				    tp != argv[i] || !interactive);
351
				restart_point = 0;
352
				if (!mflag && fromatty) {
353
					if (confirm(argv[0], NULL))
354
						mflag = 1;
355
				}
356
			}
357
			continue;
358
		}
359
360
		/* expanding file names */
361
		memset(&gl, 0, sizeof(gl));
362
		flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
363
		if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
364
			warnx("%s: not found", argv[i]);
365
			globfree(&gl);
366
			continue;
367
		}
368
369
		/* traverse all expanded file names */
370
		for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
371
			struct stat filestat;
372
373
			if (!mflag)
374
				continue;
375
			if (stat(*cpp, &filestat) != 0) {
376
				warn("local: %s", *cpp);
377
				continue;
378
			}
379
			if (S_ISDIR(filestat.st_mode) && depth == max_depth)
380
				continue;
381
			if (!confirm(argv[0], *cpp))
382
				continue;
383
384
			/*
385
			 * If file is a directory then create a new one
386
			 * at the remote machine.
387
			 */
388
			if (S_ISDIR(filestat.st_mode)) {
389
				xargv[1] = *cpp;
390
				makedir(2, xargv);
391
				cd(2, xargv);
392
				if (dirchange != 1) {
393
					warnx("remote: %s", *cpp);
394
					continue;
395
				}
396
397
				if (chdir(*cpp) != 0) {
398
					warn("local: %s", *cpp);
399
					goto out;
400
				}
401
402
				/* Copy the whole directory recursively. */
403
				xargv[1] = "*";
404
				mput(2, xargv);
405
406
				if (chdir("..") != 0) {
407
					mflag = 0;
408
					warn("local: %s", *cpp);
409
					goto out;
410
				}
411
412
 out:
413
				xargv[1] = "..";
414
				cd(2, xargv);
415
				if (dirchange != 1) {
416
					warnx("remote: %s", *cpp);
417
					mflag = 0;
418
				}
419
				continue;
420
			}
421
422
			tp = (ntflag) ? dotrans(*cpp) : *cpp;
423
			tp = (mapflag) ? domap(tp) : tp;
424
			if (restartit == 1) {
425
				off_t ret;
426
427
				if (curtype != type)
428
					changetype(type, 0);
429
				ret = remotesize(tp, 0);
430
				restart_point = (ret < 0) ? 0 : ret;
431
			}
432
			cmd = restartit ? "APPE" : ((sunique) ?
433
			    "STOU" : "STOR");
434
			sendrequest(cmd, *cpp, tp,
435
			    *cpp != tp || !interactive);
436
			restart_point = 0;
437
			if (!mflag && fromatty) {
438
				if (confirm(argv[0], NULL))
439
					mflag = 1;
440
			}
441
		}
442
		globfree(&gl);
443
	}
444
445
	(void)signal(SIGINT, oldintr);
446
447
	if (depth)
448
		depth--;
449
	if (depth == 0 || mflag == 0)
450
		depth = max_depth = mflag = 0;
451
}
452
453
void
454
reget(int argc, char *argv[])
455
{
456
457
	(void)getit(argc, argv, 1, "a+w");
458
}
459
460
char *
461
onoff(int bool)
462
{
463
464
	return (bool ? "on" : "off");
465
}
466
467
/*
468
 * Show status.
469
 */
470
/*ARGSUSED*/
471
void
472
status(int argc, char *argv[])
473
{
474
	int i;
475
476
	if (connected)
477
		fprintf(ttyout, "Connected %sto %s.\n",
478
		    connected == -1 ? "and logged in" : "", hostname);
479
	else
480
		fputs("Not connected.\n", ttyout);
481
	if (!proxy) {
482
		pswitch(1);
483
		if (connected) {
484
			fprintf(ttyout, "Connected for proxy commands to %s.\n",
485
			    hostname);
486
		}
487
		else {
488
			fputs("No proxy connection.\n", ttyout);
489
		}
490
		pswitch(0);
491
	}
492
	fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
493
	    *gateserver ? gateserver : "(none)", gateport);
494
	fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode));
495
	fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
496
		modename, typename, formname, structname);
497
	fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
498
		onoff(verbose), onoff(bell), onoff(interactive),
499
		onoff(doglob));
500
	fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique),
501
		onoff(runique));
502
	fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
503
	fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
504
	if (ntflag) {
505
		fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
506
	}
507
	else {
508
		fputs("Ntrans: off.\n", ttyout);
509
	}
510
	if (mapflag) {
511
		fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
512
	}
513
	else {
514
		fputs("Nmap: off.\n", ttyout);
515
	}
516
	fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
517
	    onoff(hash), mark, onoff(progress));
518
	fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport));
519
	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
520
	    epsv4bad ? " (disabled for this connection)" : "");
521
	fprintf(ttyout, "Command line editing: %s.\n", onoff(editing));
522
	if (macnum > 0) {
523
		fputs("Macros:\n", ttyout);
524
		for (i=0; i<macnum; i++) {
525
			fprintf(ttyout, "\t%s\n", macros[i].mac_name);
526
		}
527
	}
528
	code = 0;
529
}
530
531
/*
532
 * Toggle a variable
533
 */
534
int
535
togglevar(int argc, char *argv[], int *var, const char *mesg)
536
{
537
	if (argc < 2) {
538
		*var = !*var;
539
	} else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
540
		*var = 1;
541
	} else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
542
		*var = 0;
543
	} else {
544
		fprintf(ttyout, "usage: %s [on | off]\n", argv[0]);
545
		return (-1);
546
	}
547
	if (mesg)
548
		fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
549
	return (*var);
550
}
551
552
/*
553
 * Set beep on cmd completed mode.
554
 */
555
/*ARGSUSED*/
556
void
557
setbell(int argc, char *argv[])
558
{
559
560
	code = togglevar(argc, argv, &bell, "Bell mode");
561
}
562
563
/*
564
 * Set command line editing
565
 */
566
/*ARGSUSED*/
567
void
568
setedit(int argc, char *argv[])
569
{
570
571
	code = togglevar(argc, argv, &editing, "Editing mode");
572
	controlediting();
573
}
574
575
/*
576
 * Toggle use of IPv4 EPSV/EPRT
577
 */
578
/*ARGSUSED*/
579
void
580
setepsv4(int argc, char *argv[])
581
{
582
583
	code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4");
584
	epsv4bad = 0;
585
}
586
587
/*
588
 * Turn on packet tracing.
589
 */
590
/*ARGSUSED*/
591
void
592
settrace(int argc, char *argv[])
593
{
594
595
	code = togglevar(argc, argv, &trace, "Packet tracing");
596
}
597
598
/*
599
 * Toggle hash mark printing during transfers, or set hash mark bytecount.
600
 */
601
/*ARGSUSED*/
602
void
603
sethash(int argc, char *argv[])
604
{
605
	if (argc == 1)
606
		hash = !hash;
607
	else if (argc != 2) {
608
		fprintf(ttyout, "usage: %s [on | off | size]\n", argv[0]);
609
		code = -1;
610
		return;
611
	} else if (strcasecmp(argv[1], "on") == 0)
612
		hash = 1;
613
	else if (strcasecmp(argv[1], "off") == 0)
614
		hash = 0;
615
	else {
616
		int nmark;
617
		const char *errstr;
618
619
		nmark = strtonum(argv[1], 1, INT_MAX, &errstr);
620
		if (errstr) {
621
			fprintf(ttyout, "bytecount value is %s: %s\n",
622
			    errstr, argv[1]);
623
			code = -1;
624
			return;
625
		}
626
		mark = nmark;
627
		hash = 1;
628
	}
629
	fprintf(ttyout, "Hash mark printing %s", onoff(hash));
630
	if (hash)
631
		fprintf(ttyout, " (%d bytes/hash mark)", mark);
632
	fputs(".\n", ttyout);
633
	code = hash;
634
}
635
636
/*
637
 * Turn on printing of server echo's.
638
 */
639
/*ARGSUSED*/
640
void
641
setverbose(int argc, char *argv[])
642
{
643
644
	code = togglevar(argc, argv, &verbose, "Verbose mode");
645
}
646
647
/*
648
 * Toggle PORT/LPRT cmd use before each data connection.
649
 */
650
/*ARGSUSED*/
651
void
652
setport(int argc, char *argv[])
653
{
654
655
	code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
656
}
657
658
/*
659
 * Toggle transfer progress bar.
660
 */
661
/*ARGSUSED*/
662
void
663
setprogress(int argc, char *argv[])
664
{
665
666
	code = togglevar(argc, argv, &progress, "Progress bar");
667
}
668
669
/*
670
 * Turn on interactive prompting during mget, mput, and mdelete.
671
 */
672
/*ARGSUSED*/
673
void
674
setprompt(int argc, char *argv[])
675
{
676
677
	code = togglevar(argc, argv, &interactive, "Interactive mode");
678
}
679
680
/*
681
 * Toggle gate-ftp mode, or set gate-ftp server
682
 */
683
/*ARGSUSED*/
684
void
685
setgate(int argc, char *argv[])
686
{
687
	static char gsbuf[HOST_NAME_MAX+1];
688
689
	if (argc > 3) {
690
		fprintf(ttyout, "usage: %s [on | off | host [port]]\n",
691
		    argv[0]);
692
		code = -1;
693
		return;
694
	} else if (argc < 2) {
695
		gatemode = !gatemode;
696
	} else {
697
		if (argc == 2 && strcasecmp(argv[1], "on") == 0)
698
			gatemode = 1;
699
		else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
700
			gatemode = 0;
701
		else {
702
			if (argc == 3) {
703
				gateport = strdup(argv[2]);
704
				if (gateport == NULL)
705
					err(1, NULL);
706
			}
707
			strlcpy(gsbuf, argv[1], sizeof(gsbuf));
708
			gateserver = gsbuf;
709
			gatemode = 1;
710
		}
711
	}
712
	if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
713
		fprintf(ttyout,
714
		    "Disabling gate-ftp mode - no gate-ftp server defined.\n");
715
		gatemode = 0;
716
	} else {
717
		fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
718
		    onoff(gatemode),
719
		    *gateserver ? gateserver : "(none)", gateport);
720
	}
721
	code = gatemode;
722
}
723
724
/*
725
 * Toggle metacharacter interpretation on local file names.
726
 */
727
/*ARGSUSED*/
728
void
729
setglob(int argc, char *argv[])
730
{
731
732
	code = togglevar(argc, argv, &doglob, "Globbing");
733
}
734
735
/*
736
 * Toggle preserving modification times on retrieved files.
737
 */
738
/*ARGSUSED*/
739
void
740
setpreserve(int argc, char *argv[])
741
{
742
743
	code = togglevar(argc, argv, &preserve, "Preserve modification times");
744
}
745
746
/*
747
 * Set debugging mode on/off and/or set level of debugging.
748
 */
749
/*ARGSUSED*/
750
void
751
setdebug(int argc, char *argv[])
752
{
753
	if (argc > 2) {
754
		fprintf(ttyout, "usage: %s [on | off | debuglevel]\n", argv[0]);
755
		code = -1;
756
		return;
757
	} else if (argc == 2) {
758
		if (strcasecmp(argv[1], "on") == 0)
759
			debug = 1;
760
		else if (strcasecmp(argv[1], "off") == 0)
761
			debug = 0;
762
		else {
763
			const char *errstr;
764
			int val;
765
766
			val = strtonum(argv[1], 0, INT_MAX, &errstr);
767
			if (errstr) {
768
				fprintf(ttyout, "debugging value is %s: %s\n",
769
				    errstr, argv[1]);
770
				code = -1;
771
				return;
772
			}
773
			debug = val;
774
		}
775
	} else
776
		debug = !debug;
777
	if (debug)
778
		options |= SO_DEBUG;
779
	else
780
		options &= ~SO_DEBUG;
781
	fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
782
	code = debug > 0;
783
}
784
785
/*
786
 * Set current working directory on local machine.
787
 */
788
void
789
lcd(int argc, char *argv[])
790
{
791
	char buf[PATH_MAX];
792
	char *oldargv1;
793
794
	if (argc < 2)
795
		argc++, argv[1] = home;
796
	if (argc != 2) {
797
		fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
798
		code = -1;
799
		return;
800
	}
801
	oldargv1 = argv[1];
802
	if (!globulize(&argv[1])) {
803
		code = -1;
804
		return;
805
	}
806
	if (chdir(argv[1]) < 0) {
807
		warn("local: %s", argv[1]);
808
		code = -1;
809
	} else {
810
		if (getcwd(buf, sizeof(buf)) != NULL)
811
			fprintf(ttyout, "Local directory now %s\n", buf);
812
		else
813
			warn("getcwd: %s", argv[1]);
814
		code = 0;
815
	}
816
	if (oldargv1 != argv[1])	/* free up after globulize() */
817
		free(argv[1]);
818
}
819
820
/*
821
 * Delete a single file.
822
 */
823
void
824
deletecmd(int argc, char *argv[])
825
{
826
827
	if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
828
		fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
829
		code = -1;
830
		return;
831
	}
832
	(void)command("DELE %s", argv[1]);
833
}
834
835
/*
836
 * Delete multiple files.
837
 */
838
void
839
mdelete(int argc, char *argv[])
840
{
841
	sig_t oldintr;
842
	char *cp;
843
844
	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
845
		fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
846
		code = -1;
847
		return;
848
	}
849
	mname = argv[0];
850
	mflag = 1;
851
	oldintr = signal(SIGINT, mabort);
852
	(void)setjmp(jabort);
853
	while ((cp = remglob(argv, 0, NULL)) != NULL) {
854
		if (*cp == '\0') {
855
			mflag = 0;
856
			continue;
857
		}
858
		if (mflag && confirm(argv[0], cp)) {
859
			(void)command("DELE %s", cp);
860
			if (!mflag && fromatty) {
861
				if (confirm(argv[0], NULL))
862
					mflag = 1;
863
			}
864
		}
865
	}
866
	(void)signal(SIGINT, oldintr);
867
	mflag = 0;
868
}
869
870
/*
871
 * Rename a remote file.
872
 */
873
void
874
renamefile(int argc, char *argv[])
875
{
876
877
	if (argc < 2 && !another(&argc, &argv, "from-name"))
878
		goto usage;
879
	if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
880
usage:
881
		fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
882
		code = -1;
883
		return;
884
	}
885
	if (command("RNFR %s", argv[1]) == CONTINUE)
886
		(void)command("RNTO %s", argv[2]);
887
}
888
889
/*
890
 * Get a directory listing of remote files.
891
 */
892
void
893
ls(int argc, char *argv[])
894
{
895
	const char *cmd;
896
	char *oldargv2, *globargv2;
897
898
	if (argc < 2)
899
		argc++, argv[1] = NULL;
900
	if (argc < 3)
901
		argc++, argv[2] = "-";
902
	if (argc > 3) {
903
		fprintf(ttyout, "usage: %s [remote-directory [local-file]]\n",
904
		    argv[0]);
905
		code = -1;
906
		return;
907
	}
908
	cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
909
	oldargv2 = argv[2];
910
	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
911
		code = -1;
912
		return;
913
	}
914
	globargv2 = argv[2];
915
	if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) ||
916
	    !confirm("output to local-file:", argv[2]))) {
917
		code = -1;
918
		goto freels;
919
	}
920
	recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
921
922
	/* flush results in case commands are coming from a pipe */
923
	fflush(ttyout);
924
freels:
925
	if (argv[2] != globargv2)		/* free up after globulize() */
926
		free(argv[2]);
927
	if (globargv2 != oldargv2)
928
		free(globargv2);
929
}
930
931
/*
932
 * Get a directory listing of multiple remote files.
933
 */
934
void
935
mls(int argc, char *argv[])
936
{
937
	sig_t oldintr;
938
	int i;
939
	char lmode[1], *dest, *odest;
940
941
	if (argc < 2 && !another(&argc, &argv, "remote-files"))
942
		goto usage;
943
	if (argc < 3 && !another(&argc, &argv, "local-file")) {
944
usage:
945
		fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
946
		code = -1;
947
		return;
948
	}
949
	odest = dest = argv[argc - 1];
950
	argv[argc - 1] = NULL;
951
	if (strcmp(dest, "-") && *dest != '|')
952
		if (!globulize(&dest) ||
953
		    !confirm("output to local-file:", dest)) {
954
			code = -1;
955
			return;
956
	}
957
	mname = argv[0];
958
	mflag = 1;
959
	oldintr = signal(SIGINT, mabort);
960
	(void)setjmp(jabort);
961
	for (i = 1; mflag && i < argc-1; ++i) {
962
		*lmode = (i == 1) ? 'w' : 'a';
963
		recvrequest("LIST", dest, argv[i], lmode, 0, 0);
964
		if (!mflag && fromatty) {
965
			if (confirm(argv[0], NULL))
966
				mflag ++;
967
		}
968
	}
969
	(void)signal(SIGINT, oldintr);
970
	mflag = 0;
971
	if (dest != odest)			/* free up after globulize() */
972
		free(dest);
973
}
974
975
/*
976
 * Do a shell escape
977
 */
978
/*ARGSUSED*/
979
void
980
shell(int argc, char *argv[])
981
{
982
	pid_t pid;
983
	sig_t old1, old2;
984
	char shellnam[PATH_MAX], *shellp, *namep;
985
	int wait_status;
986
987
	old1 = signal (SIGINT, SIG_IGN);
988
	old2 = signal (SIGQUIT, SIG_IGN);
989
	if ((pid = fork()) == 0) {
990
		for (pid = 3; pid < 20; pid++)
991
			(void)close(pid);
992
		(void)signal(SIGINT, SIG_DFL);
993
		(void)signal(SIGQUIT, SIG_DFL);
994
		shellp = getenv("SHELL");
995
		if (shellp == NULL || *shellp == '\0')
996
			shellp = _PATH_BSHELL;
997
		namep = strrchr(shellp, '/');
998
		if (namep == NULL)
999
			namep = shellp;
1000
		shellnam[0] = '-';
1001
		(void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1);
1002
		if (strcmp(namep, "sh") != 0)
1003
			shellnam[0] = '+';
1004
		if (debug) {
1005
			fputs(shellp, ttyout);
1006
			fputc('\n', ttyout);
1007
			(void)fflush(ttyout);
1008
		}
1009
		if (argc > 1) {
1010
			execl(shellp, shellnam, "-c", altarg, (char *)NULL);
1011
		}
1012
		else {
1013
			execl(shellp, shellnam, (char *)NULL);
1014
		}
1015
		warn("%s", shellp);
1016
		code = -1;
1017
		exit(1);
1018
	}
1019
	if (pid > 0)
1020
		while (wait(&wait_status) != pid)
1021
			;
1022
	(void)signal(SIGINT, old1);
1023
	(void)signal(SIGQUIT, old2);
1024
	if (pid == -1) {
1025
		warn("Try again later");
1026
		code = -1;
1027
	}
1028
	else {
1029
		code = 0;
1030
	}
1031
}
1032
1033
/*
1034
 * Send new user information (re-login)
1035
 */
1036
void
1037
user(int argc, char *argv[])
1038
{
1039
	char acctname[80];
1040
	int n, aflag = 0;
1041
1042
	if (argc < 2)
1043
		(void)another(&argc, &argv, "username");
1044
	if (argc < 2 || argc > 4) {
1045
		fprintf(ttyout, "usage: %s username [password [account]]\n",
1046
		    argv[0]);
1047
		code = -1;
1048
		return;
1049
	}
1050
	n = command("USER %s", argv[1]);
1051
	if (n == CONTINUE) {
1052
		if (argc < 3 )
1053
			argv[2] = getpass("Password:"), argc++;
1054
		n = command("PASS %s", argv[2]);
1055
	}
1056
	if (n == CONTINUE) {
1057
		if (argc < 4) {
1058
			(void)fputs("Account: ", ttyout);
1059
			(void)fflush(ttyout);
1060
			if (fgets(acctname, sizeof(acctname), stdin) == NULL) {
1061
				clearerr(stdin);
1062
				goto fail;
1063
			}
1064
1065
			acctname[strcspn(acctname, "\n")] = '\0';
1066
1067
			argv[3] = acctname;
1068
			argc++;
1069
		}
1070
		n = command("ACCT %s", argv[3]);
1071
		aflag++;
1072
	}
1073
	if (n != COMPLETE) {
1074
 fail:
1075
		fputs("Login failed.\n", ttyout);
1076
		return;
1077
	}
1078
	if (!aflag && argc == 4) {
1079
		(void)command("ACCT %s", argv[3]);
1080
	}
1081
	connected = -1;
1082
}
1083
1084
/*
1085
 * Print working directory on remote machine.
1086
 */
1087
/*ARGSUSED*/
1088
void
1089
pwd(int argc, char *argv[])
1090
{
1091
	int oldverbose = verbose;
1092
1093
	/*
1094
	 * If we aren't verbose, this doesn't do anything!
1095
	 */
1096
	verbose = 1;
1097
	if (command("PWD") == ERROR && code == 500) {
1098
		fputs("PWD command not recognized, trying XPWD.\n", ttyout);
1099
		(void)command("XPWD");
1100
	}
1101
	verbose = oldverbose;
1102
}
1103
1104
/*
1105
 * Print working directory on local machine.
1106
 */
1107
/* ARGSUSED */
1108
void
1109
lpwd(int argc, char *argv[])
1110
{
1111
	char buf[PATH_MAX];
1112
1113
	if (getcwd(buf, sizeof(buf)) != NULL)
1114
		fprintf(ttyout, "Local directory %s\n", buf);
1115
	else
1116
		warn("getcwd");
1117
	code = 0;
1118
}
1119
1120
/*
1121
 * Make a directory.
1122
 */
1123
void
1124
makedir(int argc, char *argv[])
1125
{
1126
1127
	if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1128
	    argc > 2) {
1129
		fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1130
		code = -1;
1131
		return;
1132
	}
1133
	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1134
		if (verbose)
1135
			fputs("MKD command not recognized, trying XMKD.\n", ttyout);
1136
		(void)command("XMKD %s", argv[1]);
1137
	}
1138
}
1139
1140
/*
1141
 * Remove a directory.
1142
 */
1143
void
1144
removedir(int argc, char *argv[])
1145
{
1146
1147
	if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1148
	    argc > 2) {
1149
		fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1150
		code = -1;
1151
		return;
1152
	}
1153
	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1154
		if (verbose)
1155
			fputs("RMD command not recognized, trying XRMD.\n", ttyout);
1156
		(void)command("XRMD %s", argv[1]);
1157
	}
1158
}
1159
1160
/*
1161
 * Send a line, verbatim, to the remote machine.
1162
 */
1163
void
1164
quote(int argc, char *argv[])
1165
{
1166
1167
	if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1168
		fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1169
		code = -1;
1170
		return;
1171
	}
1172
	quote1("", argc, argv);
1173
}
1174
1175
/*
1176
 * Send a SITE command to the remote machine.  The line
1177
 * is sent verbatim to the remote machine, except that the
1178
 * word "SITE" is added at the front.
1179
 */
1180
void
1181
site(int argc, char *argv[])
1182
{
1183
1184
	if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1185
		fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1186
		code = -1;
1187
		return;
1188
	}
1189
	quote1("SITE", argc, argv);
1190
}
1191
1192
/*
1193
 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1194
 * Send the result as a one-line command and get response.
1195
 */
1196
void
1197
quote1(const char *initial, int argc, char *argv[])
1198
{
1199
	int i, len;
1200
	char buf[BUFSIZ];		/* must be >= sizeof(line) */
1201
1202
	(void)strlcpy(buf, initial, sizeof(buf));
1203
	if (argc > 1) {
1204
		for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) {
1205
			/* Space for next arg */
1206
			if (len > 1)
1207
				buf[len++] = ' ';
1208
1209
			/* Sanity check */
1210
			if (len >= sizeof(buf) - 1)
1211
				break;
1212
1213
			/* Copy next argument, NUL terminate always */
1214
			strlcpy(&buf[len], argv[i], sizeof(buf) - len);
1215
1216
			/* Update string length */
1217
			len = strlen(buf);
1218
		}
1219
	}
1220
1221
	/* Make double (triple?) sure the sucker is NUL terminated */
1222
	buf[sizeof(buf) - 1] = '\0';
1223
1224
	if (command("%s", buf) == PRELIM) {
1225
		while (getreply(0) == PRELIM)
1226
			continue;
1227
	}
1228
}
1229
1230
void
1231
do_chmod(int argc, char *argv[])
1232
{
1233
1234
	if (argc < 2 && !another(&argc, &argv, "mode"))
1235
		goto usage;
1236
	if ((argc < 3 && !another(&argc, &argv, "file")) || argc > 3) {
1237
usage:
1238
		fprintf(ttyout, "usage: %s mode file\n", argv[0]);
1239
		code = -1;
1240
		return;
1241
	}
1242
	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1243
}
1244
1245
void
1246
do_umask(int argc, char *argv[])
1247
{
1248
	int oldverbose = verbose;
1249
1250
	verbose = 1;
1251
	(void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1252
	verbose = oldverbose;
1253
}
1254
1255
void
1256
idle(int argc, char *argv[])
1257
{
1258
	int oldverbose = verbose;
1259
1260
	verbose = 1;
1261
	(void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1262
	verbose = oldverbose;
1263
}
1264
1265
/*
1266
 * Ask the other side for help.
1267
 */
1268
void
1269
rmthelp(int argc, char *argv[])
1270
{
1271
	int oldverbose = verbose;
1272
1273
	verbose = 1;
1274
	(void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1275
	verbose = oldverbose;
1276
}
1277
1278
/*
1279
 * Terminate session and exit.
1280
 */
1281
/*ARGSUSED*/
1282
void
1283
quit(int argc, char *argv[])
1284
{
1285
1286
	if (connected)
1287
		disconnect(0, 0);
1288
	pswitch(1);
1289
	if (connected) {
1290
		disconnect(0, 0);
1291
	}
1292
	exit(0);
1293
}
1294
1295
void
1296
account(int argc, char *argv[])
1297
{
1298
	char *ap;
1299
1300
	if (argc > 2) {
1301
		fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1302
		code = -1;
1303
		return;
1304
	}
1305
	else if (argc == 2)
1306
		ap = argv[1];
1307
	else
1308
		ap = getpass("Account:");
1309
	(void)command("ACCT %s", ap);
1310
}
1311
1312
jmp_buf abortprox;
1313
1314
/* ARGSUSED */
1315
void
1316
proxabort(int signo)
1317
{
1318
	int save_errno = errno;
1319
1320
	alarmtimer(0);
1321
	if (!proxy) {
1322
		pswitch(1);
1323
	}
1324
	if (connected) {
1325
		proxflag = 1;
1326
	}
1327
	else {
1328
		proxflag = 0;
1329
	}
1330
	pswitch(0);
1331
	errno = save_errno;
1332
	longjmp(abortprox, 1);
1333
}
1334
1335
void
1336
doproxy(int argc, char *argv[])
1337
{
1338
	struct cmd *c;
1339
	int cmdpos;
1340
	sig_t oldintr;
1341
1342
	if (argc < 2 && !another(&argc, &argv, "command")) {
1343
		fprintf(ttyout, "usage: %s command\n", argv[0]);
1344
		code = -1;
1345
		return;
1346
	}
1347
	c = getcmd(argv[1]);
1348
	if (c == (struct cmd *) -1) {
1349
		fputs("?Ambiguous command.\n", ttyout);
1350
		(void)fflush(ttyout);
1351
		code = -1;
1352
		return;
1353
	}
1354
	if (c == 0) {
1355
		fputs("?Invalid command.\n", ttyout);
1356
		(void)fflush(ttyout);
1357
		code = -1;
1358
		return;
1359
	}
1360
	if (!c->c_proxy) {
1361
		fputs("?Invalid proxy command.\n", ttyout);
1362
		(void)fflush(ttyout);
1363
		code = -1;
1364
		return;
1365
	}
1366
	if (setjmp(abortprox)) {
1367
		code = -1;
1368
		return;
1369
	}
1370
	oldintr = signal(SIGINT, proxabort);
1371
	pswitch(1);
1372
	if (c->c_conn && !connected) {
1373
		fputs("Not connected.\n", ttyout);
1374
		(void)fflush(ttyout);
1375
		pswitch(0);
1376
		(void)signal(SIGINT, oldintr);
1377
		code = -1;
1378
		return;
1379
	}
1380
	cmdpos = strcspn(line, " \t");
1381
	if (cmdpos > 0)		/* remove leading "proxy " from input buffer */
1382
		memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1383
	(*c->c_handler)(argc-1, argv+1);
1384
	if (connected) {
1385
		proxflag = 1;
1386
	}
1387
	else {
1388
		proxflag = 0;
1389
	}
1390
	pswitch(0);
1391
	(void)signal(SIGINT, oldintr);
1392
}
1393
1394
void
1395
setcase(int argc, char *argv[])
1396
{
1397
1398
	code = togglevar(argc, argv, &mcase, "Case mapping");
1399
}
1400
1401
void
1402
setcr(int argc, char *argv[])
1403
{
1404
1405
	code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1406
}
1407
1408
void
1409
setntrans(int argc, char *argv[])
1410
{
1411
	if (argc == 1) {
1412
		ntflag = 0;
1413
		fputs("Ntrans off.\n", ttyout);
1414
		code = ntflag;
1415
		return;
1416
	}
1417
	ntflag++;
1418
	code = ntflag;
1419
	(void)strlcpy(ntin, argv[1], sizeof(ntin));
1420
	if (argc == 2) {
1421
		ntout[0] = '\0';
1422
		return;
1423
	}
1424
	(void)strlcpy(ntout, argv[2], sizeof(ntout));
1425
}
1426
1427
void
1428
setnmap(int argc, char *argv[])
1429
{
1430
	char *cp;
1431
1432
	if (argc == 1) {
1433
		mapflag = 0;
1434
		fputs("Nmap off.\n", ttyout);
1435
		code = mapflag;
1436
		return;
1437
	}
1438
	if ((argc < 3 && !another(&argc, &argv, "outpattern")) || argc > 3) {
1439
		fprintf(ttyout, "usage: %s [inpattern outpattern]\n", argv[0]);
1440
		code = -1;
1441
		return;
1442
	}
1443
	mapflag = 1;
1444
	code = 1;
1445
	cp = strchr(altarg, ' ');
1446
	if (proxy) {
1447
		while(*++cp == ' ')
1448
			continue;
1449
		altarg = cp;
1450
		cp = strchr(altarg, ' ');
1451
	}
1452
	*cp = '\0';
1453
	(void)strncpy(mapin, altarg, PATH_MAX - 1);
1454
	while (*++cp == ' ')
1455
		continue;
1456
	(void)strncpy(mapout, cp, PATH_MAX - 1);
1457
}
1458
1459
void
1460
setpassive(int argc, char *argv[])
1461
{
1462
1463
	code = togglevar(argc, argv, &passivemode,
1464
	    verbose ? "Passive mode" : NULL);
1465
}
1466
1467
void
1468
setsunique(int argc, char *argv[])
1469
{
1470
1471
	code = togglevar(argc, argv, &sunique, "Store unique");
1472
}
1473
1474
void
1475
setrunique(int argc, char *argv[])
1476
{
1477
1478
	code = togglevar(argc, argv, &runique, "Receive unique");
1479
}
1480
1481
/* change directory to parent directory */
1482
/* ARGSUSED */
1483
void
1484
cdup(int argc, char *argv[])
1485
{
1486
	int r;
1487
1488
	r = command("CDUP");
1489
	if (r == ERROR && code == 500) {
1490
		if (verbose)
1491
			fputs("CDUP command not recognized, trying XCUP.\n", ttyout);
1492
		r = command("XCUP");
1493
	}
1494
	if (r == COMPLETE)
1495
		dirchange = 1;
1496
}
1497
1498
/*
1499
 * Restart transfer at specific point
1500
 */
1501
void
1502
restart(int argc, char *argv[])
1503
{
1504
	off_t nrestart_point;
1505
	char *ep;
1506
1507
	if (argc != 2)
1508
		fputs("restart: offset not specified.\n", ttyout);
1509
	else {
1510
		nrestart_point = strtoll(argv[1], &ep, 10);
1511
		if (nrestart_point == LLONG_MAX || *ep != '\0')
1512
			fputs("restart: invalid offset.\n", ttyout);
1513
		else {
1514
			fprintf(ttyout, "Restarting at %lld. Execute get, put "
1515
				"or append to initiate transfer\n",
1516
				(long long)nrestart_point);
1517
			restart_point = nrestart_point;
1518
		}
1519
	}
1520
}
1521
1522
/*
1523
 * Show remote system type
1524
 */
1525
/* ARGSUSED */
1526
void
1527
syst(int argc, char *argv[])
1528
{
1529
1530
	(void)command("SYST");
1531
}
1532
1533
void
1534
macdef(int argc, char *argv[])
1535
{
1536
	char *tmp;
1537
	int c;
1538
1539
	if (macnum == 16) {
1540
		fputs("Limit of 16 macros have already been defined.\n", ttyout);
1541
		code = -1;
1542
		return;
1543
	}
1544
	if ((argc < 2 && !another(&argc, &argv, "macro-name")) || argc > 2) {
1545
		fprintf(ttyout, "usage: %s macro-name\n", argv[0]);
1546
		code = -1;
1547
		return;
1548
	}
1549
	if (interactive)
1550
		fputs(
1551
"Enter macro line by line, terminating it with a null line.\n", ttyout);
1552
	(void)strlcpy(macros[macnum].mac_name, argv[1],
1553
	    sizeof(macros[macnum].mac_name));
1554
	if (macnum == 0)
1555
		macros[macnum].mac_start = macbuf;
1556
	else
1557
		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1558
	tmp = macros[macnum].mac_start;
1559
	while (tmp != macbuf+4096) {
1560
		if ((c = getchar()) == EOF) {
1561
			fputs("macdef: end of file encountered.\n", ttyout);
1562
			code = -1;
1563
			return;
1564
		}
1565
		if ((*tmp = c) == '\n') {
1566
			if (tmp == macros[macnum].mac_start) {
1567
				macros[macnum++].mac_end = tmp;
1568
				code = 0;
1569
				return;
1570
			}
1571
			if (*(tmp-1) == '\0') {
1572
				macros[macnum++].mac_end = tmp - 1;
1573
				code = 0;
1574
				return;
1575
			}
1576
			*tmp = '\0';
1577
		}
1578
		tmp++;
1579
	}
1580
	while (1) {
1581
		while ((c = getchar()) != '\n' && c != EOF)
1582
			/* LOOP */;
1583
		if (c == EOF || getchar() == '\n') {
1584
			fputs("Macro not defined - 4K buffer exceeded.\n", ttyout);
1585
			code = -1;
1586
			return;
1587
		}
1588
	}
1589
}
1590
1591
/*
1592
 * Get size of file on remote machine
1593
 */
1594
void
1595
sizecmd(int argc, char *argv[])
1596
{
1597
	off_t size;
1598
1599
	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1600
		fprintf(ttyout, "usage: %s file\n", argv[0]);
1601
		code = -1;
1602
		return;
1603
	}
1604
	size = remotesize(argv[1], 1);
1605
	if (size != -1)
1606
		fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size);
1607
	code = size;
1608
}
1609
1610
/*
1611
 * Get last modification time of file on remote machine
1612
 */
1613
void
1614
modtime(int argc, char *argv[])
1615
{
1616
	time_t mtime;
1617
1618
	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1619
		fprintf(ttyout, "usage: %s file\n", argv[0]);
1620
		code = -1;
1621
		return;
1622
	}
1623
	mtime = remotemodtime(argv[1], 1);
1624
	if (mtime != -1)
1625
		fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
1626
	code = mtime;
1627
}
1628
1629
/*
1630
 * Show status on remote machine
1631
 */
1632
void
1633
rmtstatus(int argc, char *argv[])
1634
{
1635
1636
	(void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
1637
}
1638
1639
/*
1640
 * Get file if modtime is more recent than current file
1641
 */
1642
void
1643
newer(int argc, char *argv[])
1644
{
1645
1646
	(void)getit(argc, argv, -1, "w");
1647
}
1648
1649
/*
1650
 * Display one file through $PAGER (defaults to "more").
1651
 */
1652
void
1653
page(int argc, char *argv[])
1654
{
1655
	off_t orestart_point;
1656
	int ohash, overbose;
1657
	char *p, *pager, *oldargv1;
1658
1659
	if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
1660
		fprintf(ttyout, "usage: %s file\n", argv[0]);
1661
		code = -1;
1662
		return;
1663
	}
1664
	oldargv1 = argv[1];
1665
	if (!globulize(&argv[1])) {
1666
		code = -1;
1667
		return;
1668
	}
1669
	p = getenv("PAGER");
1670
	if (p == NULL || (*p == '\0'))
1671
		p = PAGER;
1672
	if (asprintf(&pager, "|%s", p) == -1)
1673
		errx(1, "Can't allocate memory for $PAGER");
1674
1675
	orestart_point = restart_point;
1676
	ohash = hash;
1677
	overbose = verbose;
1678
	restart_point = hash = verbose = 0;
1679
	recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
1680
	(void)free(pager);
1681
	restart_point = orestart_point;
1682
	hash = ohash;
1683
	verbose = overbose;
1684
	if (oldargv1 != argv[1])	/* free up after globulize() */
1685
		free(argv[1]);
1686
}
1687
1688
#endif /* !SMALL */
1689