1 /******************************************************************************
2 * This file is Copyright 1992 by Philip G. Richards.  All Rights Reserved.
3 * See the file README that came with this distribution for permissions on
4 * code usage, copying, and distribution.  It comes with absolutely no warranty.
5 ******************************************************************************/
6 
7 #include "client.h"
8 #include "main.h"
9 #include "macro.h"
10 #include "parse.h"
11 #include "redirect.h"
12 #include <ctype.h>
13 #include <stdlib.h>
14 #include "local/util.h"
15 
16 /*****************************************************************************/
17 
18 #include "remote/table.h"
19 #include "local/table.h"
20 
21 static int fsp_help(int argc, char **argv, char **envp);
22 
23 /*****************************************************************************/
24 
25 #undef  CMDPROTO
26 #define CMDPROTO(com,fun,glob,help) { #com, NEEDCONN, glob, fun, help },
27 
28 static DT dispatch_table[] = {
29 #define NEEDCONN 1
30 #include "remote/table.h"
31 #undef NEEDCONN
32 
33 #define NEEDCONN 0
34 #include "local/table.h"
35 CMDPROTO(help,fsp_help,NOGLOB,"give help on commands or macros")
36 CMDPROTO(?,fsp_help,NOGLOB,"identical to `help'")
37 { (char *)0, 0, NOGLOB, 0, (char *)0 }
38 };
39 #undef NEEDCONN
40 
41 /*****************************************************************************/
42 
43 #include "patchlevel.h"
44 static char packageid[] = PACKAGEID;
45 static char copyright[] = COPYRIGHT;
46 
47 extern char **environ;
48 #define COMMSIZE 512
49 
50 int notconnected, notquit, last_retcode, dbug_flag;
51 char *myprompt = "fsp> ";
52 char *pager_command = (char*)0;
53 
54 static int myport;
55 
56 static int
execute_builtin(int argc,char ** argv,char ** envp)57 execute_builtin(int argc, char **argv, char **envp)
58 {
59     int  i;
60 
61     i = 0;
62     while (dispatch_table[i].com && strcmp(dispatch_table[i].com, argv[0]))
63 	i++;
64 
65     if (dispatch_table[i].com == (char*)0)
66 	return 1;
67 
68     if (dispatch_table[i].needconn && notconnected)
69     {
70 	if (env_host == (char*)0 || env_port == (char*)0)
71 	{
72 	    ffprintf(STDERR, "?not connected\n");
73 	    return 0;
74 	}
75 
76 	notconnected = (init_client(env_host, atoi(env_port), myport) < 0);
77 
78 	if (notconnected)
79 	{
80 	    ffprintf(STDERR, "?failed to connect -- aborting `%s' command\n",
81 		     argv[0]);
82 	    return 0;
83 	}
84     }
85 
86     switch (dispatch_table[i].glob)
87     {
88       case NOGLOB:
89 	break;
90       case LOCALGLOB:
91 	local_glob_routines();
92 	break;
93       case REMOTEGLOB:
94 	remote_glob_routines();
95 	break;
96     }
97 
98     last_retcode = (dispatch_table[i].fun)(argc, argv, envp);
99 
100     if (last_retcode && client_intr_state < 2 && notquit && onerrorargv)
101     	execute_command(onerrorargc, onerrorargv);
102 
103     return 0;
104 }
105 
106 static void
execute_macro(int argc,char ** argv)107 execute_macro(int argc, char **argv)
108 {
109     char *macro_comm, **myargv;
110     unsigned int mymaxargc = 10;
111 
112     myargv = (char**)calloc(mymaxargc, sizeof(char*));
113 
114     while ((macro_comm = get_macroline()) != (char*)0)
115     {
116 	char *comm;
117 	int myargc;
118 
119 	comm = strdup(macro_comm);
120 
121 	if ((myargc = parsemyargs(comm, &myargv, &mymaxargc, argc, argv)) > 0)
122 	{
123 	    execute_command(myargc, myargv);
124 	    freemyargs(myargc,myargv);
125 	}
126 
127 	(void)free(comm);
128     }
129 
130     (void)free((char*)myargv);
131 }
132 
133 static int broken_pipe;
134 static int save_client_intr_state;
135 
136 static RETSIGTYPE
pipe_handler(int sig)137 pipe_handler(int sig)
138 {
139     broken_pipe = 1;
140     client_intr_state = 2;
141     save_client_intr_state = client_intr_state;
142 }
143 
144 void
execute_command(int argc,char ** argv)145 execute_command(int argc, char **argv)
146 {
147     int builtin;
148     FILE *pipefs = 0;
149     iobuffers storedfs;
150     RETSIGTYPE (*old_pipe_handler)(int);
151 
152     builtin = (strcmp(argv[0], BUILTIN) == 0);
153     broken_pipe = 0;
154 
155     if (argc > 1 && argv[argc-1][0] == '|')
156     {
157         old_pipe_handler = signal(SIGPIPE, pipe_handler);
158 
159 	pipefs = popen(&argv[argc-1][1], "w");
160 	if (pipefs == 0)
161 	{
162 	    ffprintf(STDERR, "?cannot open pipe to command `%s'\n",
163 		     &argv[argc-1][1]);
164 	    return;
165 	}
166 
167 	storedfs = global_iobuffers;
168 	STDOUT   = pipefs;
169 
170 	argv[--argc] = 0;
171     }
172 
173     if (builtin || initialise_macro(argc, argv))
174     {	/* either specific builtin or no such macro */
175 	if (builtin)
176 	{
177 	    argc--;
178 	    argv++;
179 	}
180 
181 	if (execute_builtin(argc, argv, environ))
182 	    /* no such builtin */
183 	    ffprintf(STDERR, "?invalid command\n");
184     }
185     else
186 	execute_macro(argc, argv);
187 
188     if (pipefs)
189     {
190 	global_iobuffers = storedfs;
191 	pclose(pipefs);
192 
193         (void)signal(SIGPIPE, old_pipe_handler);
194     }
195 
196     if (broken_pipe)
197 	client_intr_state = save_client_intr_state;
198 }
199 
200 int
execute_stdin(int argc,char ** argv)201 execute_stdin(int argc, char **argv)
202 {
203     int myargc;
204     unsigned int mymaxargc = 10;
205     char **myargv;
206 
207     myargv = (char**)malloc(mymaxargc * sizeof(char*));
208 
209     while (notquit && !feof(STDIN))
210     {
211 	char comm[COMMSIZE];	/* pick a number, any number ... correct! */
212 	char *thislabel = 0;
213         unsigned int myargv0len;
214 	int islabel;
215 
216 	/* get command; currently we don't allow continuation lines */
217 	ffprintf(STDPROMPT, "%s", myprompt);
218 	if (my_fgets(comm, COMMSIZE, STDIN) == NULL)
219 	    break;
220 
221 	client_intr_state = 1;	/* interrupts cause abort of operations */
222 	client_intr_cnt   = 0;	/* reset the number of interrupts received */
223 
224         memset(myargv,0,mymaxargc*sizeof(char*));
225 	if ((myargc = parsemyargs(comm, &myargv, &mymaxargc, argc, argv)) < 1)
226 	    continue;
227 
228 	myargv0len = strlen(myargv[0]);
229 
230 	if (myargv0len > 0 && myargv[0][myargv0len - 1] == ':')
231 	    thislabel = myargv[0];
232 
233 	islabel = (thislabel != 0);
234 
235 	if (skiptolabel && thislabel
236 	   && strncmp(skiptolabel, thislabel, myargv0len - 1) == 0)
237 	{
238 	    (void)free(skiptolabel);
239 	    skiptolabel = 0;
240 	}
241 
242 	if (skiptolabel)
243 	    continue;
244 
245 	if (myargc > islabel)
246 	    execute_command(myargc - islabel, myargv + islabel);
247 
248 	freemyargs(myargc, myargv);
249     }
250 
251     (void)free((char*)myargv);
252 
253     return 0;
254 }
255 
256 static struct
257 {
258     char *prog;
259     char *name;
260 }
261 commandline_names[] =
262 {
263     { "fcatcmd",	"cat"	},
264     { "fcdcmd",		"cd"	},
265     { "fducmd",		"du"	},
266     { "fgetcmd",	"get"	},
267     { "fgrabcmd",	"grab"	},
268     { "flscmd",		"ls"	},
269     { "fmkdir",		"mkdir"	},
270     { "fprocmd",	"pro"	},
271     { "fput",		"put"	},
272     { "frmcmd",		"rm"	},
273     { "frmdircmd",	"rmdir"	},
274     { "ftarcmd",	"tar"	},
275     { "ftouch",		"touch"	},
276     { "fver",		"ver"	},
277     { 0,		0	}	/* both these should be 0 */
278 };
279 
280 static char *
command_name(char * progname)281 command_name(char *progname)
282 {
283     int i;
284 
285     for (i = 0; commandline_names[i].prog; i++)
286 	if (strcmp(commandline_names[i].prog, progname) == 0)
287 	    break;
288 
289     return commandline_names[i].name;
290 }
291 
292 static RETSIGTYPE
interrupt_handler(int sig)293 interrupt_handler(int sig)
294 {
295     char *txt = (char*)0;
296 
297     switch (client_intr_cnt)
298     {
299       case 0:
300 	txt = "Interrupt!";
301 	break;
302       case 1:
303 	txt = "Ouch!";
304 	break;
305       case 2:
306 	txt = "Urgh!";
307 	break;
308       case 3:
309 	txt = "Argh!";
310 	break;
311       case 4:
312 	txt = "Ok, ok, I've got the idea.  I'll stop when I can!";
313 	break;
314       case 5:
315 	txt = "Stop it!  Hit something like ^\\ if you want a fatal death.";
316 	break;
317       case 6:
318 	txt = "Not talking to you anymore [sulk]...";
319 	break;
320       default:
321 	break;
322     }
323 
324     if (txt)
325 	ffprintf(STDPROMPT, "%s\n", txt);
326 
327     client_intr_cnt++;
328 
329     if (client_intr_state)
330 	client_intr_state++;
331 
332     (void)signal(SIGINT, interrupt_handler);
333 }
334 
335 static void
init_env(void)336 init_env(void)
337 {
338     util_get_env();
339 
340     if (!env_myport)
341 	myport = 0;
342     else
343 	myport = atoi(env_myport);
344 }
345 
346 int
main(int argc,char ** argv)347 main(int argc, char **argv)
348 {
349     int thisflag;
350     int show_banner, dont_run;
351     int flag_errs = 0;
352     char *comname;
353 
354     comname = strrchr(argv[0], '/');
355     if (comname == 0)
356 	comname = argv[0];
357     else
358 	comname++;
359     comname = command_name(comname);
360 
361     standalone = (comname != 0);
362 
363     opterr = 0;
364 
365     last_retcode = 0;
366     dbug_flag	 = 0;
367     show_banner	 = 0;
368     dont_run	 = 0;
369 
370     if (!standalone)
371     {
372 	while ((thisflag = getopt(argc, argv, "dvV")) != -1)
373 	    switch (thisflag)
374 	    {
375 	      case 'd':
376 		dbug_flag++;
377 		break;
378 
379 	      case 'v':
380 		show_banner = 1;
381 		break;
382 
383 	      case 'V':
384 		show_banner = 1;
385 		dont_run = 1;
386 		break;
387 
388 	      case '?':
389 		flag_errs++;
390 		ffprintf(STDERR,"unrecognised flag (-%c) ignored\n",thisflag);
391 		break;
392 
393 	      default:
394 		break;
395 	    }
396 
397 	optind--;
398 	argv[optind] = argv[0];
399 	argc -= optind;
400 	argv += optind;
401     }
402 
403     initialise_stdio();
404 
405     if (flag_errs)
406 	ffprintf(STDDBG, "total of %d command line errors\n", flag_errs);
407 
408     if (show_banner)
409 	ffprintf(STDINFO, "FSP client version %s (id: %s)\n%s\n",
410 		 PATCHLEVEL, packageid , copyright + 4);
411 
412     if (dont_run)
413 	return 0;
414 
415     notconnected = 1;
416     notquit = 1;
417 
418     {
419 	char *startup[3];
420 
421 	startup[0] = "source";
422 
423 	if ((startup[1] = (char *)getenv("FSPRC")) == (char*)0)
424 	    startup[1] = "~/.fsprc";
425 
426 	startup[2] = (char*)0;
427 
428 	execute_command(2, startup);
429     }
430 
431     if (comname != 0)
432     {
433 	init_env();
434 	argv[0] = comname;
435 	return execute_builtin(argc, argv, environ);
436     }
437 
438     if (argc > 1)
439     {
440 	if (initialise_macro(argc - 1, argv + 1) == 0)
441 	    execute_macro(argc - 1, argv + 1);
442 	else
443 	{
444 	    /* strdup() is used so that the variables can be free()d later */
445 	    env_host = strdup(argv[1]);
446 
447 	    if (argc > 2)
448 		env_port = strdup(argv[2]);
449 	    else
450 		env_port = strdup("21");
451 
452 	    if (argc > 3)
453 		env_dir  = strdup(argv[3]);
454 	    else
455 		env_dir  = strdup("/");
456 	}
457     }
458 
459     init_env();
460 
461     /* only set up an interrupt handler if fsp is running interactively */
462     if (STDPROMPT)
463 	(void)signal(SIGINT,interrupt_handler);
464 
465     /* if a pager wasn't set in the .fsprc, then check for one now */
466     if (!pager_command)
467     {
468 	pager_command = (char *)getenv("PAGER");
469 	/* allow pager_command to be free'd */
470 	    if (pager_command)
471 		pager_command = strdup(pager_command);
472     }
473 
474     (void)execute_stdin(argc, argv);
475 
476     disconnect();
477 
478     return last_retcode;
479 }
480 
481 #define NCO 6
482 static void
fsp_builtin_long_help_all(void)483 fsp_builtin_long_help_all(void)
484 {
485     int i;
486     int notext = 0;
487 
488     ffprintf(STDOUT, "Builtin commands are:\n");
489 
490     for (i = 0; dispatch_table[i].com; i++)
491         if (dispatch_table[i].help)
492 	    ffprintf(STDOUT, "      %-10s    %s\n",
493 		     dispatch_table[i].com, dispatch_table[i].help);
494 	else
495 	    notext++;
496 
497     if (notext)
498     {
499 	int j;
500 
501 	ffprintf(STDOUT, "\nUndocumented commands are:\n");
502 
503 	for (i = 0, j = 0; dispatch_table[i].com; i++)
504 	    if (!dispatch_table[i].help)
505 	    {
506 		ffprintf(STDOUT, "  %-10s%s",
507 			 dispatch_table[i].com, j == NCO-1? "\n" : "");
508 		j = (j+1) % NCO;
509 	    }
510 
511 	if (j)
512 	    ffprintf(STDOUT, "\n");
513     }
514 }
515 
516 static int
fsp_builtin_long_help(char * name)517 fsp_builtin_long_help(char *name)
518 {
519     int i;
520 
521     for (i = 0; dispatch_table[i].com; i++)
522 	if (strcmp(dispatch_table[i].com, name) == 0)
523 	    break;
524 
525     if (dispatch_table[i].com)
526     {
527 	if (dispatch_table[i].help)
528 	    ffprintf(STDOUT, "%-10s    %s\n",
529 		 dispatch_table[i].com, dispatch_table[i].help);
530 	else
531 	    ffprintf(STDOUT, "no help available for command `%s'\n", name);
532     }
533     else
534 	return 1;
535 
536     return 0;
537 }
538 
539 static void
fsp_builtin_short_help(void)540 fsp_builtin_short_help(void)
541 {
542     int i, j;
543 
544     ffprintf(STDOUT, "Builtin commands are:\n");
545 
546     for (i = 0, j = 0; dispatch_table[i].com; i++)
547     {
548 	ffprintf(STDOUT, "  %-10s%s",
549 		 dispatch_table[i].com, j == NCO-1? "\n" : "");
550 	j = (j+1) % NCO;
551     }
552 
553     if (j)
554 	ffprintf(STDOUT,"\n");
555 }
556 
557 static int
fsp_help(int argc,char ** argv,char ** envp)558 fsp_help(int argc, char **argv, char **envp)
559 {
560     if (argc > 1)
561     {
562 	if (strcmp(argv[1], "all") == 0)
563 	{
564 	    fsp_builtin_long_help_all();
565 	    ffprintf(STDOUT, "\n");
566 	    fsp_macro_long_help_all();
567 	}
568 	else
569 	{
570 	    int i;
571 	    for (i = 1; i < argc; i++)
572 		if (fsp_macro_long_help(argv[i])
573 		    && fsp_builtin_long_help(argv[i]))
574 		    ffprintf(STDERR, "no such command or macro: `%s'\n",
575 			     argv[i]);
576 	}
577     }
578     else
579     {
580 	fsp_builtin_short_help();
581 	ffprintf(STDOUT, "\n");
582 	fsp_macro_short_help();
583     }
584 
585     return 0;
586 }
587