1 /*
2 * cmd.c -- read and execute commands, this is the main loop
3 *
4 * Yet Another FTP Client
5 * Copyright (C) 1998-2001, Martin Hedenfalk <mhe@stacken.kth.se>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. See COPYING for more details.
11 */
12
13 #include "syshdr.h"
14 #include "gvars.h"
15 #include "ftp.h"
16 #include "cmd.h"
17 #include "input.h"
18 #include "strq.h"
19 #include "args.h"
20 #include "redir.h"
21 #include "transfer.h"
22 #include "commands.h"
23 #include "alias.h"
24 #include "utils.h"
25 #include "bookmark.h"
26 #include "redir.h"
27 #include "prompt.h"
28 #include "ltag.h"
29 #include "lscolors.h"
30
31 //static void exe_cmdline(char *str, bool aliases_are_expanded);
32
exit_yafc(void)33 void exit_yafc(void)
34 {
35 ftp_quit_all();
36 list_free(gvFtpList);
37 gvFtpList = NULL;
38 input_save_history();
39 save_ltaglist(0);
40 gvars_destroy();
41 reset_xterm_title();
42 free_colors();
43
44 exit(0);
45 }
46
cmd_exit(int argc,char ** argv)47 void cmd_exit(int argc, char **argv)
48 {
49 cmd_quit(argc,argv);
50 }
51
cmd_quit(int argc,char ** argv)52 void cmd_quit(int argc, char **argv)
53 {
54 if(argv != 0) {
55 OPT_HELP_NEW(_("Close all connections and quit."), "quit [options]", NULL);
56 maxargs(optind - 1);
57 }
58 exit_yafc();
59 }
60
61 /* main loop, prompts for commands and executes them.
62 */
command_loop(void)63 void command_loop(void)
64 {
65 char *p;
66 #ifdef HAVE_GETTIMEOFDAY
67 struct timeval beg, end;
68 #endif
69
70 #ifdef HAVE_POSIX_SIGSETJMP
71 if(sigsetjmp(gvRestartJmp, 1))
72 #else
73 if(setjmp(gvRestartJmp))
74 #endif
75 {
76 if(!ftp_connected())
77 printf(_("restarted command loop, connection closed\n"));
78 else
79 printf(_("restarted command loop, command aborted\n"));
80 }
81 gvJmpBufSet = true;
82 force_completion_type = cpUnset;
83 close_redirection();
84 gvInTransfer = false;
85 gvInterrupted = false;
86
87 while(!gvSighupReceived) {
88 char *cmdstr, *s;
89
90 ftp_initsigs();
91
92 #if 0 && (defined(HAVE_SETPROCTITLE) || defined(linux))
93 if(gvUseEnvString) {
94 if(ftp_connected())
95 setproctitle("%s", ftp->url->hostname);
96 else
97 setproctitle(_("not connected"));
98 }
99 #endif
100
101 fputc('\r', stderr);
102 p = expand_prompt(ftp_connected()
103 ? (ftp_loggedin() ? gvPrompt3 : gvPrompt2)
104 : gvPrompt1);
105 if(!p)
106 p = xstrdup("yafc> ");
107
108 print_xterm_title();
109
110 cmdstr = input_read_string("%s", p);
111 free(p);
112
113 if(!cmdstr) { /* bare EOF received */
114 fputc('\n', stderr);
115 if(gvQuitOnEOF)
116 break;
117 else
118 continue;
119 }
120 s = strip_blanks(cmdstr);
121 if(!*s) {
122 /* blank line */
123 free(cmdstr);
124 continue;
125 }
126 #ifdef HAVE_LIBREADLINE
127 add_history(s);
128 #endif
129
130 #ifdef HAVE_GETTIMEOFDAY
131 gettimeofday(&beg, 0);
132 #endif
133 ftp_trace("yafc: '%s'\n", s);
134 exe_cmdline(s, false);
135 free(cmdstr);
136
137 #ifdef HAVE_GETTIMEOFDAY
138 gettimeofday(&end, 0);
139 end.tv_sec -= beg.tv_sec;
140 if(gvBeepLongCommand && end.tv_sec >= gvLongCommandTime)
141 fputc('\007', stderr);
142 #endif
143 }
144 /* end of main loop, exiting program... */
145 if(gvSighupReceived)
146 transfer_end_nohup();
147 else
148 cmd_quit(0, 0);
149 }
150
exe_cmd(cmd_t * c,args_t * args)151 static void exe_cmd(cmd_t *c, args_t *args)
152 {
153 int i;
154 char *e;
155
156 if(!ftp_connected() && c->needconnect)
157 fprintf(stderr,
158 _("Not connected. Try 'open --help' for more information.\n"));
159 else if(!ftp_loggedin() && c->needlogdin)
160 fprintf(stderr,
161 _("Not logged in. Try 'user --help' for more information.\n"));
162 else {
163 for(i=1; i<args->argc; i++) {
164 int ret;
165 switch(args->argv[i][0]) {
166 case '|':
167 case '>':
168 e = args_cat2(args, i);
169 /* remove pipe/redir from command parameters */
170 args_del(args, i, args->argc);
171 ret = open_redirection(e); /* modifies stdout and/or stderr */
172 free(e);
173 if(ret != 0)
174 return;
175 break;
176 case '<':
177 fprintf(stderr, _("input redirection not supported\n"));
178 return;
179 }
180 }
181
182 if(c->auto_unquote)
183 args_unquote(args);
184 args_remove_empty(args);
185
186 if(strcmp(args->argv[0], "shell") == 0
187 || strcmp(args->argv[0], "!") == 0)
188 {
189 char *e = args_cat(args->argc, args->argv, 1);
190 bool b = reject_ampersand(e);
191 free(e);
192 if(b)
193 return;
194 }
195
196 gvInterrupted = false;
197 c->func(args->argc, args->argv);
198 gvInterrupted = false;
199 gvInTransfer = false;
200 close_redirection();
201 ftp_cache_flush();
202 }
203 }
204
expand_alias(const char * cmd)205 static args_t *expand_alias(const char *cmd)
206 {
207 args_t *args;
208 alias *a;
209
210 a = alias_search(cmd);
211 if(a == 0 || a == ALIAS_AMBIGUOUS)
212 return (args_t *)a;
213
214 args = args_create();
215 args_add_args(args, a->value);
216
217 return args;
218 }
219
220 /* executes the commandline in STR
221 * handles expansion of aliases and splits the command line
222 * into ;-separated strings which are fed to exe_cmd()
223 *
224 * modifies STR
225 *
226 * first call should pass aliases_are_expanded == false
227 */
exe_cmdline(char * str,bool aliases_are_expanded)228 void exe_cmdline(char *str, bool aliases_are_expanded)
229 {
230 char *e;
231
232 /* fprintf(stderr, "exe_cmdline: %s\n", str);*/
233
234 /* split command into ;-separated commands */
235 while((e = strqsep(&str, ';')) != 0) {
236 args_t *args;
237
238 /* make an args_t of the command string */
239 args = args_create();
240 args_push_back(args, e);
241
242 /* remove empty arguments */
243 args_remove_empty(args);
244 if(args->argc == 0) {
245 args_destroy(args);
246 continue;
247 }
248
249 rearrange_redirections(args);
250
251 if(aliases_are_expanded) {
252 cmd_t *c;
253
254 /* special handling of '!' (synonym for shell command) */
255 if(args->argv[0][0] == '!' && strlen(args->argv[0]) > 1) {
256 strpull(args->argv[0], 1);
257 args_push_front(args, "!");
258 }
259
260 /* now we have the expanded command line in args
261 * this string might include multiple real commands (;-separated)
262 */
263
264 rearrange_redirections(args);
265
266 c = find_func(args->argv[0], true);
267
268 if(c != 0)
269 exe_cmd(c, args);
270 args_destroy(args);
271 } else {
272 args_t *expanded_cmd;
273 char *cmd;
274 char *xstr;
275
276 /* get the command, the first word in the string */
277 cmd = xstrdup(args->argv[0]);
278 unquote(cmd);
279
280 /* expand command if it's an alias */
281 expanded_cmd = expand_alias(cmd);
282
283 if(expanded_cmd == 0) /* it wasn't an alias */
284 expanded_cmd = args;
285 else if(expanded_cmd == (args_t *)ALIAS_AMBIGUOUS) {
286 fprintf(stderr, _("ambiguous alias '%s'\n"), cmd);
287 args_destroy(args);
288 free(cmd);
289 continue;
290 } else {
291 args_t *alias_args;
292
293 /* get the arguments for the alias
294 * these are used with expand_alias_parameters()
295 */
296 alias_args = args_create();
297 args_add_args2(alias_args, args, 1);
298
299 expand_alias_parameters(&expanded_cmd, alias_args);
300 args_destroy(alias_args);
301 args_destroy(args);
302
303 /* remove empty arguments */
304 args_remove_empty(expanded_cmd);
305 if(expanded_cmd->argc == 0) {
306 free(cmd);
307 args_destroy(expanded_cmd);
308 continue;
309 }
310 }
311
312 free(cmd);
313
314 xstr = args_cat2(expanded_cmd, 0);
315 exe_cmdline(xstr, true);
316 free(xstr);
317 args_destroy(expanded_cmd);
318 }
319 }
320 }
321