1 /* Author: Hagen Fritsch <fritsch+wput-src@in.tum.de>
2    (C) 2002-2006 by Hagen Fritsch
3 
4    This file is part of wput.
5 
6    This programm is free software; you can redistribute it and/or
7    modify it under the terms of the GNU General Public License
8    as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
11    The wput is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15    You should have received a copy of the GNU General Public
16    License along with the wput; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19 
20 /* command-line-parsing routines and core control functions */
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #ifndef WIN32
26 #  include <netinet/in.h>
27 #endif
28 
29 #include "wput.h"
30 #include "netrc.h"
31 
32 #ifdef WIN32
33 #  include "getopt/getopt.h"
34 #else
35 #  define _GNU_SOURCE
36 #  ifdef HAVE_GETOPT_H
37 #    include <getopt.h>
38 #  else
39 #    ifdef HAVE_GNUGETOPT_GETOPT_H
40 #      include <gnugetopt/getopt.h>
41 #    else
42 #      include "getopt/getopt.h"
43 #    endif
44 #  endif
45 #endif
46 
47 #ifdef ENABLE_NLS
48 #  ifdef HAVE_LOCALE_H
49 #    include <locale.h>
50 #  endif
51 #endif
52 
53 #include "progress.h"
54 #include "_queue.h"
55 #include "utils.h"
56 
57 extern char *optarg;
58 
59 #ifdef WIN32
60 const static char * version = "0.6.2-w32";
61 #else
62 const static char * version = "0.6.2";
63 #endif
64 
65 _fsession * fsession_queue_entry_point = NULL;
66 
67 void commandlineoptions(int argc, char * argv[]);
68 int  start_fsession();
69 int  start_ftp();
70 int  start_recur_ftp();
71 void read_netrc_file(void);
72 opt_t opt;
73 
main(int argc,char * argv[])74 int main(int argc, char *argv[]){
75 #ifdef WIN32
76 	/* i don't know why, but if i call WSAStartup just once, there is an
77 	 * error when initialising sockets later (10093). quite strange and
78 	 * took me quite a while to figure out *dang* */
79 	WSADATA sa;
80 	if(WSAStartup(MAKEWORD(2,2),&sa) != 0) {
81 		fprintf(stderr, "1st: Error Initializing Windows Socket DLL (WSAStartup Failed).\nError-Code: 0x%x", GetLastError());
82 		exit(4);
83 	}
84 	if(WSAStartup(MAKEWORD(2,2),&sa) != 0) {
85 		fprintf(stderr, "2nd: Error Initializing Windows Socket DLL (WSAStartup Failed).\nError-Code: 0x%x", GetLastError());
86 		exit(4);
87 	}
88 #endif
89 	signal(SIGPIPE, SIG_IGN);
90 	/* i18n */
91 #ifdef ENABLE_NLS
92 	/* LC_MESSAGES is enough as the only thing that is done is
93 	 * the translation of text-messages */
94 #  ifdef LC_MESSAGES
95 	setlocale (LC_MESSAGES, "");
96 	setlocale (LC_CTYPE, "");
97 #  else
98 	setlocale (LC_ALL, "");
99 #  endif
100 	/* Set the text message domain.  */
101 	bindtextdomain ("wput", LOCALEDIR);
102 	textdomain ("wput");
103 #endif
104 
105 
106 	/* initialise global options and set default values */
107 	memset(&opt, 0, sizeof(opt));
108 
109 	/* create the ssl framework */
110 #ifdef HAVE_SSL
111 	SSL_library_init();
112 #endif
113 
114 	opt.sbuf      = malloc(82);
115 	opt.retry     = -1;
116 	opt.retry_interval = 10;
117 	opt.time_deviation = 10;
118 	opt.binary    = TYPE_UNDEFINED;
119 	opt.output    = stdout;
120 
121 	opt.verbose   = vNORMAL;
122 	opt.bindaddr  = INADDR_ANY;
123 	opt.barstyle  = 1;
124 	opt.ps.bind   = 1;
125 	opt.session_start = wtimer_alloc();
126 
127 	opt.resume_table.small_large = RESUME_TABLE_UPLOAD;
128 	opt.resume_table.large_large = RESUME_TABLE_SKIP;
129 	opt.resume_table.large_small = RESUME_TABLE_RESUME;
130 
131 	opt.email_address = cpy("wput@localhost.com");
132 
133         if(!strncmp(&argv[0][strlen(argv[0])-4], "wdel", 5))
134           opt.wdel = 1;
135 
136 	/* env overrides home overrides system wputrc */
137 #ifdef SYSTEM_WPUTRC
138 	readwputrc(SYSTEM_WPUTRC);
139 #endif
140 	readwputrc(NULL); /*homedir*/
141 	readwputrc(getenv("WPUTRC"));
142 
143 	parse_proxy(getenv("ftp_proxy"));
144 
145 	read_netrc_file();
146 	read_password_file(getenv("PASSWORDFILE"));
147 
148 	wtimer_reset(opt.session_start);
149 
150 	commandlineoptions(argc, argv);
151 
152 #ifndef WIN32
153 	/* If we are still at stdout, then redirect output to 'wput-log'. */
154 	if(opt.background) {
155 		if(opt.output == stdout) {
156 				printout(vLESS, _("Resuming in background. Logging output to 'wput-log'.\n"));
157 				opt.output   = fopen("wput-log", "a");
158 				if(opt.output == NULL) { perror(_("Unable to open logfile")); exit(4); }
159 				opt.barstyle = 0;
160 		} else
161 				puts("Resuming in background.\n");
162 
163 		if(fork() > 0) exit(0);
164 
165 		if(opt.input_pipe) {
166 			printout(vNORMAL, _("Warning: "));
167 			printout(vNORMAL, _("background-mode might not work correctly, if the input-pipe needs to read from stdin (like cat -).\n"));
168 		}
169 		if(opt.input != stdin) {
170 			/* create a new session and release the console-descriptors... */
171 			setsid ();
172 			freopen ("/dev/null", "r", stdin);
173 			freopen ("/dev/null", "w", stdout);
174 			freopen ("/dev/null", "w", stderr);
175 		} else {
176 			printout(vNORMAL, _("Warning: "));
177 			printout(vNORMAL, _("reading urls from stdin, while running in background-mode is not reliable.\n"));
178 		}
179 	}
180 #endif
181 	/* this sets the barstyle to the old one unless wput runs on a tty */
182 	if(opt.barstyle && !isatty( fileno(stdout) ))
183 		opt.barstyle = 0;
184 
185 	if((opt.ps.ip == 0 || opt.ps.port == 0) && opt.ps.type != PROXY_OFF) {
186 		printout(vNORMAL, _("Warning: "));
187 		printout(vNORMAL, _("Ignoring request to turn proxy-usage on, since no proxy is configured.\n"));
188 		opt.ps.type = PROXY_OFF;
189 	}
190 
191         /* WDEL separate the urls from a potential file and ensure that the urls end in a '/' */
192         if(opt.wdel) separate_urls();
193 
194         /* WPUT process all url/file combinations that were supplied by commandline */
195         if(!opt.wdel) queue_process(0);
196 
197         /* read URLs from input-file */
198         if(opt.input != 0) read_urls();
199 
200         /* WPUT if there are lonely files remaining, give them the last (user-supplied) url */
201         if(!opt.wdel) process_missing();
202         else queue_process(0); /* later process in WDEL */
203 
204 	/* now we've everything we need or are already done */
205 	if(opt.sorturls) {
206 		printout(vDEBUG, "Transmitting sorted fsessions\n");
207 		while(fsession_queue_entry_point != NULL) {
208 				int res = fsession_process_file(fsession_queue_entry_point, opt.curftp);
209 				if(res == -1)      opt.failed++;
210 				else if(res == -2) opt.skipped++;
211 				opt.curftp = fsession_queue_entry_point->ftp;
212 				free_fsession(fsession_queue_entry_point);
213 		}
214 	}
215 
216 	/* finally close any existing connections */
217 	if(opt.curftp) ftp_quit(opt.curftp);
218 
219 	if(opt.transfered == 0 && opt.skipped == 0 && opt.failed == 0)
220 		printout(vNORMAL, _("Nothing done. Try `%s --help'.\n"), argv[0]);
221 	else
222 		printout(vNORMAL, _("FINISHED --%s--\n"), time_str());
223 
224 	if(opt.transfered > 0) {
225 		if(!opt.wdel) {
226 			printout(vNORMAL, opt.transfered == 1 ?
227 			_("Transfered %s bytes in %d file at %s\n") :
228 			_("Transfered %s bytes in %d files at %s\n"),
229 				legible(opt.transfered_bytes),
230 				opt.transfered,
231 				calculate_transfer_rate(
232 					wtimer_elapsed(opt.session_start),
233 					opt.transfered_bytes,
234 					0)
235 				);
236 		} else
237 			printout(vNORMAL, opt.transfered == 1 ?
238 				_("Deleted %d file\n") :
239 				_("Deleted %d files\n"),
240 				opt.transfered);
241 
242 	}
243 
244 	if(opt.skipped > 0)
245 		printout(vNORMAL, opt.skipped == 1 ? _("Skipped %d file.\n") : _("Skipped %d files.\n"), opt.skipped);
246 	if(opt.failed > 0)
247 		printout(vNORMAL, !opt.wdel ?
248 			(opt.failed == 1 ? _("Transmission of %d file failed.\n") : _("Transmission of %d files failed.\n")) :
249 			(opt.failed == 1 ? _("Deletion of %d file failed.\n") : _("Deletion of %d files failed.\n")), opt.failed);
250 
251 	/* clean up */
252 	free(opt.session_start);
253 	free(opt.email_address);
254 	free(opt.sbuf);
255 
256 	if(opt.ps.pass)    free(opt.ps.pass);
257 	if(opt.ps.user)    free(opt.ps.user);
258 	if(opt.last_url)   free(opt.last_url);
259 
260 	if(opt.pl)         password_list_free(opt.pl);
261 	skiplist_free(opt.skipdlist);
262 
263 #ifdef MEMDBG
264 	print_unfree();
265 #endif
266 
267 	return ((opt.failed != 0) * 2) | (opt.skipped != 0);
268 }
269 /* read urls/files from input-file as though they were supplied as command-line-arguments */
read_urls(void)270 int read_urls(void) {
271 	char * url;
272 	char * p;
273 	while ((url = p = read_line(opt.input))) {
274 		/* skip spaces and skip lines beginning with a # */
275 		printout(vDEBUG, "read `%s'\n", p);
276 
277 		while( isspace(*p) ) p++;
278 		if(*p == '#') {
279 			free(url);
280 			continue;
281 		}
282 
283 		/* just foolproof check for \r\n */
284 		if(url[strlen(url)-2] == '\r')
285 			url[strlen(url)-2] = 0;
286 		url[strlen(url)-1] = 0;
287 
288 		if(!strncmp(p, "ftp://", 6))
289 			opt.wdel ? wdel_queue_add_entry(NULL, cpy(p)) : queue_add_url(cpy(p));
290 		else
291 			opt.wdel ? wdel_queue_add_file(cpy(p)) : queue_add_file(cpy(p));
292 
293 		free(url);
294 		/* process anything that's already complete */
295 		queue_process(0);
296 	}
297 	return 0;
298 }
299 /* ugly code to parse through the wputrc-options */
set_option(char * com,char * val)300 int set_option(char * com, char * val) {
301   printout(vDEBUG, "Setting option '%s' to '%s'\n", com, val);
302 
303   switch(*com) {
304   case '1':
305   case '2':
306       if(!strncmp(com, "2_1", 4)) {
307           if(!strncasecmp(val, "SKIP", 5))
308             opt.resume_table.large_small = RESUME_TABLE_SKIP;
309           else
310             opt.resume_table.large_small = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_RESUME;
311       } else if(!strncmp(com, "2_2", 4))
312             opt.resume_table.large_large = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_SKIP;
313       else if(!strncmp(com, "1_2", 4))
314             opt.resume_table.small_large = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_SKIP;
315       else
316             return -1;
317       return 0;
318   case 'b':
319       if(!strncasecmp(com, "bind-address", 13)) {
320             if(get_ip_addr(optarg, &opt.bindaddr) == -1) {
321 				printout(vMORE, _("Error: "));
322 				printout(vMORE, _("`%s' could not be resolved. "), optarg);
323 				printout(vLESS, _("Exiting.\n"));
324                 exit(4);
325             }
326             return 0;
327         } else return -1;
328   case 'c':
329       if(!strncasecmp(com, "connection_mode", 16)) {
330         if(!strncasecmp(val, "pasv", 5)) {
331           opt.portmode = 0;
332         } else if(!strncasecmp(val, "port", 4)) {
333           opt.portmode = 1;
334         } else return -1;
335       }
336       else if(!strncasecmp(com, "chmod", 6)) {
337           int invalid = 0;
338 	  if(opt.wdel) return 0; /* disabled for wdel */
339           if(strlen(val) == 3) {
340               int modecounter;
341               for (modecounter = 0; modecounter < 3; modecounter++) {
342                   if (val[modecounter] < '0' || val[modecounter] > '7') {
343                       invalid = 1;
344                       break;
345                   }
346               }
347           } else {
348               invalid = 1;
349           }
350           if (!invalid)
351               opt.chmod = val;
352           else return -2;
353       } else return -1;
354       return 0;
355 #ifdef HAVE_SSL
356   case 'f':
357       if(!strncmp(com, "force_tls", 9))
358           opt.tls = !strncasecmp(val, "on", 3);
359       else
360           return -1;
361       return 0;
362 #endif
363   case 'm':
364       if(!strncmp(com, "email_address", 13))
365           opt.email_address = cpy(val);
366       else return -1;
367       return 0;
368   case 'p':
369       if(!strncasecmp(com, "proxy", 6)) {
370         if(!strncmp(val, "http", 5))
371           opt.ps.type = PROXY_HTTP;
372         else if(!strncasecmp(val, "socks", 6))
373           opt.ps.type = PROXY_SOCKS;
374         else
375           opt.ps.type = PROXY_OFF;
376       }
377       else if(!strncasecmp(com, "proxy_host", 11)) {
378         if(get_ip_addr(val, &opt.ps.ip) == -1) {
379             printout(vLESS, _("Warning: "));
380 			printout(vLESS, _("`%s' could not be resolved. "), val);
381 			printout(vLESS, _("Disabling proxy support.\n"));
382             opt.ps.type = 0;
383         }
384       }
385       else if(!strncasecmp(com, "proxy_port", 11))
386           opt.ps.port = atoi(val);
387       else if(!strncasecmp(com, "proxy_user", 11))
388           opt.ps.user = cpy(val);
389       else if(!strncasecmp(com, "proxy_pass", 11))
390           opt.ps.pass = cpy(val);
391       else if(!strncasecmp(com, "proxy_bind", 11))
392           opt.ps.bind = !strncasecmp(val, "on", 3);
393       else if(!strncasecmp(com, "passwordfile", 13) || !strncasecmp(com, "password_file", 14))
394           read_password_file(val);
395       else return -1;
396       return 0;
397     case 'r':
398         if(!strncasecmp(com, "rate", 5)) {
399 	  if(opt.wdel) return 0; /* disabled for wdel */
400           opt.speed_limit = atoi(val);
401           while(*val) {
402             if(*val == 'K') opt.speed_limit *= 1024;
403             if(*val == 'M') opt.speed_limit *= 1024 * 1024;
404             val++;
405           }
406           printout(vDEBUG, "Rate-Limit is set to %d Bytes per second\n", opt.speed_limit);
407         } else if(!strncasecmp(com, "retry_count", 12))
408             opt.retry = atoi(val);
409         else return -1;
410         return 0;
411   case 's':
412       //if(!strncmp(com, "script_file", 12))
413         //load_script(val);
414       //else
415       if(!strncasecmp(com, "sort_urls", 10))
416         opt.sorturls = !strncasecmp(val, "on", 3);
417       else return -1;
418       return 0;
419   case 't':
420       if(!strncasecmp(com, "timeout", 8))
421         socket_set_default_timeout(atoi(val));
422       else if(!strncasecmp(com, "timestamping", 13)) {
423 	if(opt.wdel) return 0; /* disabled for wdel */
424         opt.timestamping    = !strncasecmp(val, "on", 3); }
425       else if(!strncasecmp(com, "timeoffset", 11))
426         opt.time_offset     = atoi(val);
427       else if(!strncasecmp(com, "timeoffset", 11))
428         opt.time_deviation  = atoi(val);
429       else if(!strncasecmp(com, "transfer_type", 14)) {
430 	if(opt.wdel) return 0; /* disabled for wdel */
431         if(!strncasecmp(val, "auto", 5)) opt.binary = TYPE_UNDEFINED;
432         else if(!strncasecmp(val, "ascii", 6))  opt.binary = TYPE_A;
433         else if(!strncasecmp(val, "binary", 7)) opt.binary = TYPE_I;
434         else return -2;
435       } else return -1;
436       return 0;
437   case 'v':
438       if(!strncasecmp(com, "verbosity", 10)) {
439         char * levels[] = {"quite", "less", "normal", "more", "debug"};
440         int i;
441         for(i=0;i<5;i++)
442           if(!strcasecmp(val, levels[i])) {
443             opt.verbose = i;
444             return 0;
445           }
446         return -2;
447       } else return -1;
448   case 'w':
449       if(!strncasecmp(com, "wait_retry", 11))
450         opt.retry_interval = atoi(val);
451       else return -1;
452       return 0;
453   }
454   return -1;
455 }
456 
457 #define NETRC_FILE_NAME ".netrc"
458 
459 /* read the netrc file and store its contents in a linked list */
read_netrc_file(void)460 void read_netrc_file(void) {
461     /* Find ~/.netrc.  */
462     char *path, *home;
463     acc_t *netrc_list, *l;
464 
465     home = home_dir ();
466     if (!home)
467 	return;
468 
469     path = (char *) malloc(strlen (home) + 1 +
470 			   strlen (NETRC_FILE_NAME) + 1);
471     if (!path)
472 	return;
473 
474     sprintf (path, "%s/%s", home, NETRC_FILE_NAME);
475     free (home);
476 
477     if (!file_exists(path)) {
478 	printout(vMORE, _("netrc file '%s' cannot be read. skipping\n"), path);
479 	return;
480     }
481 
482     printout(vDEBUG, "Reading netrc file '%s'", path);
483     netrc_list = parse_netrc (path);
484     free(path);
485 
486     /* If nothing to do...  */
487     if (!netrc_list)
488 	return;
489 
490     for (l = netrc_list; l; l = l->next) {
491 	if (!l->host)
492 	    continue;
493 	opt.pl = password_list_add(opt.pl, cpy(l->host), l->acc ? cpy(l->acc) : NULL, l->passwd ? cpy(l->passwd) : NULL);
494 	printout(vDEBUG, "added %s:%s@%s to the password-list (%x)\n", l->acc, l->passwd, l->host, opt.pl);
495     }
496 
497     free_netrc(netrc_list);
498 }
499 
500 /* read the password file and store its contents in a linked list */
read_password_file(char * f)501 void read_password_file(char * f) {
502 	FILE * fp;
503 	char * line;
504 	char * tmp;
505 	char * user;
506 	char * pass;
507 	if(!file_exists(f)) {
508 		printout(vMORE, _("password_file '%s' cannot be read. skipping\n"), f);
509 		return;
510 	}
511 	printout(vNORMAL, _("Warning: You are using a wput password file. This is deprecated!\n"
512 			    "         Please consider switch to the widely used netrc-files.\n"));
513 	printout(vDEBUG, "Reading password-file '%s'", f);
514 	fp = fopen(f, "r");
515 	while( (tmp = line = read_line(fp)) ) {
516 		while(isspace(*tmp) && *tmp) tmp++;
517 		strtok(tmp, "\t");
518 		user = strtok(NULL, "\t");
519 		pass = strtok(NULL, "\t");
520 		if(*tmp == 0 || *tmp == '#' || user == NULL || pass == NULL) {
521 			free(line);
522 			continue;
523 		}
524 		if(pass[strlen(pass)-2] == '\r') pass[strlen(pass)-2] = 0;
525 		else if(pass[strlen(pass)-1] == '\n') pass[strlen(pass)-1] = 0;
526 		opt.pl = password_list_add(opt.pl, cpy(tmp), cpy(user), cpy(pass));
527 		printout(vDEBUG, "added %s:%s@%s to the password-list (%x)\n", user, pass, tmp, opt.pl);
528 		free(line);
529 	}
530 }
531 /* reads a wputrc file. parses its options and gives error-reports if necessary */
readwputrc(char * f)532 void readwputrc(char * f) {
533     FILE * fp;
534     char * file;
535     char * line;
536     int    ln   = 1;
537 
538     if(f == NULL) {
539         char * home = home_dir();
540         file = malloc(strlen(home) + 10); /* home + slash + (.wputrc | wput.ini) + 0-char */
541         sprintf(file, "%s/%s", home, WPUTRC_FILENAME);
542         free(home);
543     } else file = cpy(f);
544 
545     printout(vDEBUG, "Reading wputrc-file: %s\n", file);
546 
547     if(!file_exists(file)) {
548         printout(vDEBUG, "wputrc-file '%s' is not readable. skipping.\n", file);
549         free(file);
550         return;
551     }
552 
553     fp = fopen (file, "r");
554     if(!fp) {
555       printout(vLESS, _("Fatal error while opening '%s': %s\n"), file, strerror (errno));
556       free(file);
557       return;
558     }
559 
560   while ((line = read_line (fp))) {
561     char * tmp = line;
562     char * com;
563     char * val;
564     /* skip leading spaces */
565     while(isspace(*tmp) && *tmp) tmp++;
566 
567     /* discard comment lines */
568     if(*tmp == '#' || *tmp == ';' || *tmp == 0) {
569         free(line);
570         continue;
571     }
572     com = tmp;
573 
574     /* search for space, end or '=' */
575     while(!isspace(*tmp) && *tmp && *tmp != '=') tmp++;
576     *tmp++= 0;
577 
578     while((isspace(*tmp) || *tmp == '=') && *tmp) tmp++;
579     val = tmp;
580 
581     /* suppress the new-line-char */
582     while(*tmp != 0 && *tmp != '\n') tmp++;
583     if(*(tmp-1) == '\r') *(tmp-1) = 0;
584     else                 * tmp    = 0;
585 
586     /* we mis-use tmp to store the ret_val, and print a message if something was not parse-able */
587     tmp = (char *) set_option(com, val);
588     if(tmp == (char *) -1) printout(vLESS, _("%s#%d: Option '%s' not recognized\n"), file, ln, com);
589     if(tmp == (char *) -2) printout(vLESS, _("%s#%d: Unknow value '%s' for '%s'\n"), file, ln, val, com);
590     free(line);
591     ln++;
592   }
593   free(file);
594 }
595 
596 /* parses all the commandline-options available. */
commandlineoptions(int argc,char * argv[])597 void commandlineoptions(int argc, char * argv[]){
598     int c;
599 
600     /* TODO IMP windows doesn't automatically fill *.txt with the
601      * TODO IMP corresponding filenames. So this must be done by us (*urgs*) */
602 
603     int option_index = 0;
604     static struct option long_options[] =
605       {
606 		{"append-output", 1, 0, 'a'},    //0
607 		{"ascii", 0, 0, 'A'},
608 		{"background", 0, 0, 'b'},
609 		{"basename", 1, 0, 0},
610 		{"binary", 0, 0, 'B'},
611 		{"bind-address", 1, 0, 0},       //5
612 		{"compile-options", 0, 0, 0},
613 		{"debug", 0, 0, 'd'},
614 		{"dont-continue", 0, 0, 0},
615 		{"force-tls", 0, 0, 0},
616 		{"help", 0, 0, 'h'},             //10
617 		{"input-file", 1, 0, 'i'},
618 		{"input-pipe", 1, 0, 'I'},
619 		{"less-verbose", 0, 0, 0},
620 		{"limit-rate", 1, 0, 'l'},
621 		{"no-directories", 0, 0, 0},     //15
622 		{"output-file", 1, 0, 'o'},
623 		{"port-mode", 0, 0, 'p'},
624 		{"proxy", 1, 0, 'Y'},
625 		{"proxy-user", 1, 0, 0},
626 		{"proxy-pass", 1, 0, 0},         //20
627 		{"quiet", 0, 0, 'q'},
628 		{"random-wait", 0, 0, 0},
629 		{"remove-source-files", 0, 0, 'R'},
630 		{"reupload", 0, 0, 'u'},
631 		{"script", 1, 0, 'S'},           //25
632 		{"skip-existing", 0, 0, 0},
633 		{"skip-larger", 0, 0, 0},
634 		{"sort", 0, 0, 's'},
635 		{"timeoffset", 1, 0, 0},
636 		{"timeout", 1, 0, 'T'},          //30
637 		{"timestamping", 0, 0, 'N'},
638 		{"tries", 1, 0, 't'},
639 		{"use-proxy", 1, 0, 'Y'},
640 		{"verbose", 0, 0, 'v'},
641 		{"version", 0, 0, 'V'},          //35
642 		{"wait", 1, 0, 'w'},
643 		{"waitretry", 1, 0, 0},
644 		{"chmod", 1, 0, 'm'},
645 		{"disable-tls", 0, 0, 0},
646 		{0, 0, 0, 0}                    //40
647       };
648     while (1)
649     {
650         c = getopt_long (argc, argv, "Y:Vhbo:a:dqvn:i:I:t:NT:w:Rl:pABsS:um:",
651                            long_options, &option_index);
652 
653         if (c == -1)
654                 break;
655 
656         switch (c)
657         {
658         case 0:
659             switch(option_index) {
660             case 13:  //less-verbose
661                 opt.verbose--;                            break;
662             case  5: set_option("bind-address", optarg);  break;
663             case  8: //dont-continue
664 			if(opt.resume_table.large_small == RESUME_TABLE_RESUME)
665 				opt.resume_table.large_small = RESUME_TABLE_UPLOAD;
666 			break;
667             case 22: //random-wait
668 				opt.random_wait = 1;                      break;
669             case 17: //port-mode
670                 opt.portmode = 1;                         break;
671             case 19: set_option("proxy_user", optarg);    break;
672             case 20: set_option("proxy_pass", optarg);    break;
673             case  6: //compile-options
674                 fprintf(opt.output, "wput version: %s\n\n#defined options:\n", version);
675 #ifdef TIMER_GETTIMEOFDAY
676                 fprintf(opt.output, "TIMER_GETTIMEOFDAY\n");
677 #endif
678 #ifdef HAVE_SSL
679                 fprintf(opt.output, "HAVE_SSL\n");
680 #endif
681                 fprintf(opt.output, "\nUsing %d-Bytes for off_t\n", sizeof(off_t));
682                 exit(0);
683             case 27: //skip-larger
684                 opt.resume_table.small_large = RESUME_TABLE_SKIP;   break;
685             case 26: //skip-existing
686                 opt.resume_table.large_small = RESUME_TABLE_SKIP;
687                 opt.resume_table.large_large = RESUME_TABLE_SKIP;
688                 opt.resume_table.small_large = RESUME_TABLE_SKIP;   break;
689             case 29: //timeoffset
690                 set_option("timeoffset", optarg);                   break;
691 #ifdef HAVE_SSL
692             case 9: //force-tls
693                 set_option("force_tls", "on");                      break;
694 #endif
695             case 15: //no-directories
696                 opt.no_directories = 1;                             break;
697             case  3: //basename
698                 opt.basename = optarg;                              break;
699             case 37: //waitretry
700                 opt.retry_interval = atoi(optarg);                  break;
701 	    case 39: //disable-tls
702 		    opt.tls = 2;                                    break;
703             default:
704                 fprintf(stderr, _("Option %s should not appear here :|\n"), long_options[option_index].name);
705             }
706             break;
707         case 'o':
708         case 'a': opt.output = fopen(optarg, (c == 'o') ? "w" : "a");
709                   if(opt.output == NULL) { perror(_("Unable to open logfile")); exit(4); }
710                   opt.barstyle = 0;
711                   break;
712 #ifndef WIN32
713         case 'b': opt.background = 1;           break;
714 #endif
715         case 't':
716                   opt.retry = atoi(optarg) + 1;
717                   if(opt.retry <= 0) opt.retry = -1;
718                   break;
719         case 'T': socket_set_default_timeout(atoi(optarg));
720                                                 break;
721         case 'p': opt.portmode = 1;             break;
722         case 'n':
723                   if(optarg[0] == 'v')      opt.verbose--;
724                   if(optarg[0] == 'd')      opt.no_directories = 1;
725                   if(optarg[0] == 'c')
726                     if(opt.resume_table.large_small == RESUME_TABLE_RESUME)
727                        opt.resume_table.large_small =  RESUME_TABLE_UPLOAD;
728                   break;
729         case 'u': opt.resume_table.large_large = RESUME_TABLE_UPLOAD; break;
730         case 'N': opt.timestamping = 1;         break;
731         case 'v': opt.verbose++;                break;
732         case 'q': opt.verbose=0;                break;
733         case 'd': opt.verbose=vDEBUG;           break;
734         case 'w': opt.wait   =atoi(optarg);     break;
735         case 'A': opt.binary = TYPE_A;          break;
736         case 'B': opt.binary = TYPE_I;          break;
737         case 's': opt.sorturls = 1;             break;
738         case 'S': Abort("TODO SCRIPTING\n");    break;
739         case 'l': set_option("rate", optarg);   break;
740         case 'i':
741                   if(!strncmp(optarg, "-", 2)) {
742                     printout(vDEBUG, "Reading URLs from stdin\n");
743                     opt.input = stdin;
744                   } else {
745                     printout(vDEBUG, "Reading URLs from `%s'\n", optarg);
746                     opt.input = fopen(optarg, "r");
747                     if(opt.input == NULL) {
748                         perror(optarg);
749                         exit(4);
750                     }
751                   }
752                   break;
753         case 'I': printout(vNORMAL, _("Warning: "));
754                   printout(vNORMAL, _("You supplied an input-pipe. "
755                       "This is only to be used as fallback, if no filename "
756                       "can be found from the URL. This might not be the desired "
757                       "behavour. TODO\n"));
758                   opt.input_pipe = optarg;      break;
759         case 'R': opt.unlink = 1;               break;
760         case 'Y': set_option("proxy", optarg);  break;
761         case 'm': set_option("chmod", optarg);  break;
762         case 'V':
763             fprintf(opt.output, _("wput version: %s\n"), version);
764             exit(0);
765         case 'h':
766         default:
767             fprintf(stderr, _("Usage: wput [options] [file]... [url]...\n"
768 "  url        ftp://[username[:password]@]hostname[:port][/[path/][file]]\n\n"
769 "Startup:\n"
770 "  -V, --version         Display the version of wput and exit.\n"
771 "  -h, --help            Print this help-screen\n"));
772 #ifndef WIN32
773 			fprintf(stderr, _(
774 "  -b, --background      go to background after startup\n"));
775 #endif
776 			fprintf(stderr, "\n");
777 
778 			fprintf(stderr, _(
779 "Logging and input file:\n"
780 "  -o,  --output-file=FILE      log messages to FILE\n"
781 "  -a,  --append-output=FILE    append log messages to FILE\n"
782 "  -q,  --quiet                 quiet (no output)\n"
783 "  -v,  --verbose               be verbose\n"
784 "  -d,  --debug                 debug output\n"
785 "  -nv, --less-verbose          be less verbose\n"
786 "  -i,  --input-file=FILE       read the URLs from FILE\n"
787 "  -s,  --sort                  sorts all input URLs by server-ip and path\n"
788 "       --basename=PATH         snip PATH off each file when appendig to an URL\n"
789 "  -I,  --input-pipe=COMMAND    take the output of COMMAND as data-source\n"
790 /* will execute the command with the url and file as param and use its output as input
791    for the uploading file */
792 "  -R,  --remove-source-files   unlink files upon successful upload\n"
793 "\n"));
794 			fprintf(stderr, _(
795 "Connection:\n"
796 "       --bind-address=ADDR     bind to ADDR (hostname or IP) on local host\n"
797 "  -t,  --tries=NUMBER          set retry count to NUMBER (-1 means infinite)\n"
798 "  -nc, --dont-continue         do not resume partially-uploaded files\n"
799 "  -u,  --reupload              do not skip already completed files\n"
800 "       --skip-larger           do not upload files if remote size is larger\n"
801 "       --skip-existing         do not upload files that exist remotely\n"
802 "  -N,  --timestamping          don't re-upload files unless newer than remote\n"
803 "  -T,  --timeout=10th-SECONDS  set various timeouts to 10th-SECONDS\n"
804 "  -w,  --wait=10th-SECONDS     wait 10th-SECONDS between uploads. (default: 0)\n"
805 "       --random-wait           wait from 0...2*WAIT secs between uploads.\n"
806 "       --waitretry=SECONDS     wait SECONDS between retries of an upload\n"
807 "  -l,  --limit-rate=RATE       limit upload rate to RATE\n"
808 "  -nd, --no-directories        do not create any directories\n"
809 "  -Y,  --proxy=http/socks/off  set proxy type or turn off\n"
810 "       --proxy-user=NAME       set the proxy-username to NAME\n"
811 "       --proxy-pass=PASS       set the proxy-password to PASS\n"
812 "\n"));
813 			fprintf(stderr, _(
814 "FTP-Options:\n"
815 "  -p,  --port-mode             no-passive, turn on port mode ftp (def. pasv)\n"
816 "  -A,  --ascii                 force ASCII  mode-transfer\n"
817 "  -B,  --binary                force BINARY mode-transfer\n"
818 "  -m,  --chmod                 change mode of transferred files ([0-7]{3})\n"));
819 
820 #ifdef HAVE_SSL
821 			fprintf(stderr, _(
822 "       --force-tls             force the useage of TLS\n"
823 "       --disable-tls           disable the usage of TLS\n"));
824 #endif
825 /*"  -f,  --peace                 force wput not to be aggressive\n"*/
826 /*"  -S,  --script=FILE      TODO USS load a wput-script\n\n"*/
827 			fprintf(stderr, _(
828 "\n"
829 "See wput(1) for more detailed descriptions of the options.\n"
830 "Report bugs and suggestions via SourceForge at\n"
831 "http://sourceforge.net/tracker/?group_id=141519\n"));
832             exit(0);
833         }
834     }
835 
836     /* TODO NRV check if we got any input urls. otherwise print usage information */
837     while(optind < argc) {
838 	if(!strncmp(argv[optind], "ftp://", 6))
839 		opt.wdel ? wdel_queue_add_entry(NULL, cpy(argv[optind])) : queue_add_url(cpy(argv[optind]));
840 	else
841 		opt.wdel ? wdel_queue_add_file(cpy(argv[optind])) : queue_add_file(cpy(argv[optind]));
842 	/* delete argv content, so passwords are not displayed by ps */
843 	memset(argv[optind], ' ', strlen(argv[optind]));
844 
845         optind++;
846     }
847 }
848