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