1 /*
2  * main.c -- parses command line options and starts Yafc
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 "ftp.h"
15 #include "gvars.h"
16 #include "help.h"
17 #include "alias.h"
18 #include "input.h"
19 #include "cmd.h"
20 #include "completion.h"
21 #include "login.h"
22 #include "strq.h"
23 #include "utils.h"
24 #include "rc.h"
25 #include "ltag.h"
26 #include "lscolors.h"
27 
28 #ifdef HAVE_LOCALE_H
29 # include <locale.h>
30 #endif
31 
32 #include "yafcrc.h"
33 
print_syntax_and_exit(const char * argv0)34 void print_syntax_and_exit(const char* argv0)
35 {
36 	printf(COPYLINE "\n");
37 	printf(_("This is yet another FTP client.\n"));
38   printf(_("Usage: %s [options] [[proto://][user[:password]@]hostname[:port][/directory] ...]\n"), argv0);
39   printf(_("Options:\n"));
40   printf(_("  -a, --anon        (*) anonymous login\n"));
41 	printf(_("  -d, --debug           print all commands sent to/from server\n"));
42 	printf(_("  -D, --dump-rc         prints the default config file to stdout\n"));
43 	printf(_("  -m, --mechanism=MECH\n"
44 	         "                    (*) try MECH as security mechanism(s)\n"));
45 	printf(_("  -n, --norc            don't parse config file\n"));
46 	printf(_("  -p, --noproxy     (*) don't connect via proxy\n"));
47 	printf(_("  -q, --quiet           don't print the yafc welcome message\n"));
48 	printf(_("  -r, --rcfile=FILE     use other config file instead of ~/.yafc/yafcrc\n"));
49 	printf(_("  -t, --trace[=FILE]    use a trace file (mainly for debugging)\n"
50 	         "               if FILE specified, use it instead of ~/.yafc/trace/trace.<pid>\n"));
51 	printf(_("  -u, --noauto      (*) disable autologin\n"));
52 	printf(_("  -U, --noalias     (*) disable bookmark alias lookup and abbreviation\n"));
53 	printf(_("  -v, --verbose         print all replies from server\n"));
54 	printf(_("  -w, --wait=TIME       use a different wait time for reconnecting\n"));
55 	printf(_("  -W, --workdir=DIR     use a different working directory (instead of ~/.yafc)\n"));
56 	printf(_("  -V, --version         print version information and quit\n"));
57 	printf(_("  -h, --help            print this help and quit\n"));
58 	printf("\n");
59 	printf(_("(*) only applies for login to host specified on the command line\n"));
60 	printf("\n");
61 	printf(_("Report bugs to %s\n\n"), PACKAGE_BUGREPORT);
62 	exit(0);
63 }
64 
tstp_sighandler(int signum)65 void tstp_sighandler(int signum)
66 {
67 	if(signum == SIGTSTP) {
68 		reset_xterm_title();
69 		raise(SIGSTOP);
70 	} else if(signum == SIGCONT) {
71 		if(readline_running)
72 			input_redisplay_prompt();
73 		print_xterm_title();
74 	}
75 	ftp_set_signal(signum, tstp_sighandler);
76 }
77 
init_ftp(void)78 void init_ftp(void)
79 {
80 	ftp->getuser_hook = getuser_hook;
81 	ftp->getpass_hook = getpass_hook;
82 
83 	ftp->open_timeout = gvConnectionTimeout;
84 	ftp->reply_timeout = gvCommandTimeout;
85 
86 	ftp_set_verbosity(vbError); /* default */
87 	if(gvVerbose)
88 		ftp_set_verbosity(vbCommand);
89 	if(gvDebug)
90 		ftp_set_verbosity(vbDebug);
91 }
92 
init_yafc(void)93 void init_yafc(void)
94 {
95 	gvFtpList = list_new((listfunc)ftp_destroy);
96 	list_additem(gvFtpList, ftp_create());
97 	gvCurrentFtp = gvFtpList->first;
98 	ftp_use((Ftp *)gvCurrentFtp->data);
99 	ftp_initsigs();
100 
101 	gvEditor = getenv("EDITOR");
102 	if(!gvEditor)
103 		gvEditor = getenv("VISUAL");
104 	if(gvEditor)
105 		gvEditor = xstrdup(gvEditor);
106 	else
107 		gvEditor = xstrdup("vi");
108 
109 #ifdef HAVE_UNAME
110   struct utsname unbuf;
111 	if(uname(&unbuf) == 0)
112 		gvLocalHost = xstrdup(unbuf.nodename);
113 #endif
114 	if(!gvLocalHost)
115 		gvLocalHost = xstrdup(getenv("HOST"));
116 	if(!gvLocalHost)
117 		gvLocalHost = xstrdup("localhost");
118 
119 	{
120 		struct passwd *pwd;
121 		pwd = getpwuid(geteuid());
122 		gvUsername = xstrdup(pwd->pw_name);
123 		gvLocalHomeDir = xstrdup(pwd->pw_dir);
124 	}
125 
126 	if(!gvLocalHomeDir)
127 		gvLocalHomeDir = xstrdup(getenv("HOME"));
128 
129   char* curdir = getcwd(NULL, 0);
130 	gvWorkingDirectory = path_absolute(
131 		gvWorkingDirectory ? gvWorkingDirectory : "~/.yafc",
132     curdir,
133 		gvLocalHomeDir);
134   free(curdir);
135 
136 	gvAnonPasswd = xstrdup("anonymous@");
137 
138 	/* init colors from LS_COLORS for ls */
139 	init_colors();
140 
141 	/* choose default security mechanism */
142 	gvDefaultMechanism = list_new((listfunc)free);
143 #ifdef HAVE_KRB5
144 # ifdef USE_SSL
145 	listify_string("krb5:ssl:none", gvDefaultMechanism);
146 # else
147 	listify_string("krb5:none", gvDefaultMechanism);
148 # endif
149 #elif defined(USE_SSL)
150 	listify_string("ssl", gvDefaultMechanism);
151 #else
152 	listify_string("none", gvDefaultMechanism);
153 #endif
154 
155 	gvPrompt1 = xstrdup("yafc> ");
156 	gvPrompt2 = xstrdup("yafc %h> ");
157 	gvPrompt3 = xstrdup("yafc %h:%42~> ");
158 
159 	gvTerm = xstrdup(getenv("TERM"));
160 	if(!gvTerm)
161 		gvTerm = xstrdup("dummy");
162 	gvXtermTitleTerms = xstrdup("xterm xterm-debian rxvt");
163 
164 	gvBookmarks = list_new((listfunc)url_destroy);
165 	gvAliases = list_new((listfunc)alias_destroy);
166 	gvAsciiMasks = list_new((listfunc)free);
167 	gvTransferFirstMasks = list_new((listfunc)free);
168 	gvIgnoreMasks = list_new((listfunc)free);
169 	gvLocalTagList = list_new((listfunc)free);
170 	gvProxyExclude = list_new((listfunc)free);
171 
172 	if (asprintf(&gvHistoryFile, "%s/history", gvWorkingDirectory) == -1)
173   {
174     fprintf(stderr, _("Failed to allocate memory.\n"));
175     exit_yafc();
176   }
177 
178 	gvSendmailPath = xstrdup("/usr/sbin/sendmail");
179 
180 	ftp_set_signal(SIGTSTP, tstp_sighandler);
181 	ftp_set_signal(SIGCONT, tstp_sighandler);
182 
183 	gvTransferBeginString = xstrdup("%-70R\n");
184 	gvTransferString = xstrdup("%5p%% [%25v] %s/%S ETA %e %B");
185 /*	gvTransferEndString = xstrdup("%-40R      %s in %t @ %b\n");*/
186 
187 	gvTransferXtermString = xstrdup("\x1B]0;yafc - (%p%%) %r\x07");
188 
189 	gvStatsTransfer = stats_create();
190 
191 	input_init();
192 }
193 
check_if_first_time(void)194 void check_if_first_time(void)
195 {
196 	if (access(gvWorkingDirectory, X_OK) == 0)
197 		return;
198 
199 	if(errno == ENOENT) {
200 		char *dir;
201 
202 /*		printf(_("This seems to be the first time you run Yafc...\n"));*/
203 
204 		printf(_("creating working directory %s: "), gvWorkingDirectory);
205 		fflush(stdout);
206 		if(mkdir(gvWorkingDirectory, S_IRUSR|S_IWUSR|S_IXUSR) != 0) {
207 			perror("");
208 			return;
209 		}
210 		chmod(gvWorkingDirectory, S_IRUSR|S_IWUSR|S_IXUSR);
211 		printf(_("done\n"));
212 
213 		if (asprintf(&dir, "%s/trace", gvWorkingDirectory) == -1)
214     {
215       fprintf(stderr, _("Failed to allocate memory.\n"));
216       exit_yafc();
217     }
218 		printf(_("creating directory %s: "), dir);
219 		fflush(stdout);
220 		if(mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR) != 0) {
221 			perror("");
222 			free(dir);
223 			return;
224 		}
225 		chmod(dir, S_IRUSR|S_IWUSR|S_IXUSR);
226 		printf(_("done\n"));
227 		free(dir);
228     dir = NULL;
229 
230 		if (asprintf(&dir, "%s/nohup", gvWorkingDirectory) == -1)
231     {
232       fprintf(stderr, _("Failed to allocate memory.\n"));
233       exit_yafc();
234     }
235 		printf(_("creating directory %s: "), dir);
236 		fflush(stdout);
237 		if(mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR) != 0) {
238 			perror("");
239 			free(dir);
240 			return;
241 		}
242 		chmod(dir, S_IRUSR|S_IWUSR|S_IXUSR);
243 		printf(_("done\n"));
244 		free(dir);
245 	} else
246 		perror(gvWorkingDirectory);
247 }
248 
main(int argc,char ** argv,char ** envp)249 int main(int argc, char **argv, char **envp)
250 {
251 	int c;
252 	char *configfile = 0;
253 	bool dotrace = false;
254 	char *tracefile = 0;
255 	unsigned int open_opt = 0;
256 	int wait_time = -1;
257 
258 	bool override_yafcrc = false;
259 	bool override_debug = false;
260 	bool override_verbose = false;
261 	bool override_welcome = false;
262 
263 	char *mech = 0;
264 
265 	struct option longopts[] = {
266 		{"anon", no_argument, 0, 'a'},
267 		{"debug", no_argument, 0, 'd'},
268 		{"dump-rc", no_argument, 0, 'D'},
269 		{"norc", no_argument, 0, 'n'},
270 		{"quiet", no_argument, 0, 'q'},
271 		{"rcfile", required_argument, 0, 'r'},
272 		{"mechanism", required_argument, 0, 'm'},
273 		{"noproxy", no_argument, 0, 'p'},
274 		{"trace", optional_argument, 0, 't'},
275 		{"noauto", no_argument, 0, 'u'},
276 		{"verbose", no_argument, 0, 'v'},
277 		{"version", no_argument, 0, 'V'},
278 		{"wait", required_argument, 0, 'w'},
279 		{"workdir", required_argument, 0, 'W'},
280 		{"help", no_argument, 0, 'h'},
281 		{0, 0, 0, 0},
282 	};
283 
284 #ifdef SOCKS
285 	SOCKSinit(argv[0]);
286 #endif
287 
288 #ifdef ENABLE_NLS
289 	setlocale(LC_ALL, "");
290 	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
291   bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
292 	textdomain(GETTEXT_PACKAGE);
293 #endif
294 #if 0 && (!defined(HAVE_SETPROCTITLE) && defined(linux))
295 	initsetproctitle(argc, argv, envp);
296 #endif
297 
298 	while((c = getopt_long(argc, argv,
299 						   "qhdDgant::r:uUm:pvVw:W:", longopts, 0)) != EOF)
300 	{
301 		switch(c) {
302 		case 'a':
303 			open_opt |= OP_ANON;
304 			break;
305 		case 'n':
306 			override_yafcrc = true;
307 			break;
308 		case 'r':
309 			configfile = xstrdup(optarg);
310 			break;
311 		case 't':
312 			dotrace = true;
313 			if(optarg)
314 				tracefile = xstrdup(optarg);
315 			break;
316 		case 'u':
317 			open_opt |= OP_NOAUTO;
318 			break;
319 		case 'U':
320 			open_opt |= OP_NOALIAS;
321 			break;
322 		case 'm':
323 			mech = xstrdup(optarg);
324 			break;
325 		case 'p':
326 			open_opt |= OP_NOPROXY;
327 			break;
328 		case 'd':
329 			override_debug = true;
330 			break;
331 		case 'D':
332 			printf("%s", default_yafcrc);
333 			return 0;
334 		case 'q':
335 			override_welcome = true;
336 			break;
337 		case 'v':
338 			override_verbose = true;
339 			break;
340 		case 'V':
341 			printf(PACKAGE " " VERSION "\n");
342 			return 0;
343 		case 'w':
344 			wait_time = atoi(optarg);
345 			break;
346 		case 'W':
347 			stripslash(optarg);
348 			gvWorkingDirectory = xstrdup(optarg);
349 			break;
350 		case 'h':
351 			print_syntax_and_exit(argv[0]);
352 			break;
353 		case '?':
354 			return 1;
355 		}
356 	}
357 
358 	if(!override_welcome)
359 		puts(_(FULLVER));
360 
361 	init_yafc();
362 
363 	if(!configfile)
364 		if (asprintf(&configfile, "%s/yafcrc", gvWorkingDirectory) == -1)
365     {
366       fprintf(stderr, _("Failed to allocate memory.\n"));
367       exit_yafc();
368     }
369 
370 	check_if_first_time();
371 
372 	if(!override_yafcrc) {
373 		char *tmp;
374 		parse_rc(SYSCONFDIR "/yafcrc", false);
375 		parse_rc(configfile, false);
376 		if (asprintf(&tmp, "%s/bookmarks", gvWorkingDirectory) == -1)
377     {
378       fprintf(stderr, _("Failed to allocate memory.\n"));
379       exit_yafc();
380     }
381 		parse_rc(tmp, false);
382 		free(tmp);
383 	}
384   free(configfile);
385   configfile = NULL;
386 
387 	if(gvReadNetrc)
388 		parse_rc("~/.netrc", false);
389 
390 	if(gvProxyType != 0 && gvProxyUrl == 0) {
391 		fprintf(stderr, _("No proxy host defined!\n\n"));
392 		gvProxyType = 0;
393 	}
394 
395 	if(override_debug)
396 		gvDebug = true;
397 	if(override_verbose)
398 		gvVerbose = true;
399 	if(wait_time != -1) {
400 		if(wait_time < 0)
401 			fprintf(stderr, _("Invalid value for --wait: %d\n"), wait_time);
402 		else
403 			gvConnectWaitTime = wait_time;
404 	}
405 
406 	init_ftp();
407 
408 	if(dotrace || gvTrace) {
409 		if(!tracefile)
410 			if (asprintf(&tracefile, "%s/trace/trace.%u",
411 					 gvWorkingDirectory, getpid()) == -1)
412       {
413         fprintf(stderr, _("Failed to allocate memory.\n"));
414         exit_yafc();
415       }
416 		if(ftp_set_trace(tracefile) != 0)
417 			fprintf(stderr, _("Couldn't open tracefile '%s': %s\n"),
418 					tracefile, strerror(errno));
419 		free(tracefile);
420 	}
421 
422 	if(optind < argc) {
423 #ifdef HAVE_LIBREADLINE
424 		char *s;
425 #endif
426 		int i;
427 
428 		if(!gvAutologin)
429 			open_opt |= OP_NOAUTO;
430 
431 		for(i=optind; i<argc; i++) {
432 #ifdef HAVE_GETTIMEOFDAY
433 			struct timeval beg, end;
434 			gettimeofday(&beg, 0);
435 #endif
436 			yafc_open(argv[i], open_opt, mech, 0);
437 #ifdef HAVE_GETTIMEOFDAY
438 			gettimeofday(&end, 0);
439 			end.tv_sec -= beg.tv_sec;
440 			if(gvBeepLongCommand && end.tv_sec > gvLongCommandTime)
441 				fputc('\007', stderr);
442 #endif
443 #ifdef HAVE_LIBREADLINE /* add appropriate 'open' command to history */
444 			if (asprintf(&s, "open %s%s",
445 					 argv[i], test(open_opt, OP_ANON) ? " --anon" : "") == -1)
446       {
447         fprintf(stderr, _("Failed to allocate memory.\n"));
448         exit_yafc();
449       }
450 			add_history(s);
451 			free(s);
452 #endif
453 		}
454 	}
455 
456 	load_ltaglist(false, false, 0);
457 
458 	command_loop();
459 	/* should not return */
460 	list_free(gvFtpList);
461   gvFtpList = NULL;
462 	return 0;
463 }
464