/* Author: Hagen Fritsch <hagen _at_ itooktheredpill.dyndns.org>
   (C) 2002-2004 by Hagen Fritsch
    
   This file is part of wput.

   This programm is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License 
   as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The wput is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

   You should have received a copy of the GNU General Public
   License along with the wput; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

/* command-line-parsing routines and core control functions */
   
#include <sys/types.h>
#include <sys/stat.h>

#include "wput.h"

#ifdef WIN32
  #include "getopt/getopt.h"
#else
  #define _GNU_SOURCE
  #ifdef HAVE_GETOPT_H
      #include <getopt.h>
  #else
      #ifdef HAVE_GNUGETOPT_GETOPT_H
	#include <gnugetopt/getopt.h>
      #else
      	#include "getopt/getopt.h"
      #endif
  #endif
#endif

#include "utils.h"
#include "ftp.h"
#include "wpsocket.h"
#include "progress.h"
#include "_queue.h"

extern char *optarg;

#ifdef WIN32
const static char * version = "0.5-w32";
#else
const static char * version = "0.5";
#endif

char * main_menu = 
"wput [options] [file]... [url]...\n"
"  url        ftp://[username[:password]@]hostname[:port][/[path/][file]]\n\n"
"Startup:\n"
"  -V, --version         Display the version of wput and exit.\n"
"  -h, --help            Print this help-screen\n"
#if (! defined( WIN32)) && (! defined( __VMS))
"  -b, --background      go to background after startup\n"
#endif /* (! defined( WIN32)) && (! defined( __VMS)) */
"\n"
"Logging and input file:\n"
"  -o,  --output-file=FILE      log messages to FILE\n"
"  -a,  --append-output=FILE    append log messages to FILE\n"
"  -q,  --quiet                 quiet (no output)\n"
"  -v,  --verbose               be verbose\n"
"  -d,  --debug                 debug output\n"
"  -nv, --less-verbose          be less verbose\n"
"  -i,  --input-file=FILE       read the URLs from FILE\n"
"  -s,  --sort                  sorts all input URLs by server-ip and path\n"
"  -I,  --input-pipe=COMMAND    take the output of COMMAND as data-source\n"
/* will execute the command with the url and file as param and use its output as input
   for the uploading file */
"  -R,  --remove-source-files   unlink files upon successful upload\n"
"\n"
"Upload:\n"
"       --bind-address=ADDR     bind to ADDR (hostname or IP) on local host\n"
"  -t,  --tries=NUMBER          set retry count to NUMBER (-1 means infinite)\n"
"  -nc, --dont-continue         do not resume partially-uploaded files\n"
"  -u,  --reupload              do not skip already completed files\n"
"       --skip-larger           do not upload files if remote size is larger\n"
"       --skip-existing         do not upload files that exist remotely\n"
"  -N,  --timestamping          don't re-upload files unless newer than remote\n"
"  -T,  --timeout=10th-SECONDS  set various timeouts to 10th-SECONDS\n"
"  -w,  --wait=10th-SECONDS     wait 10th-SECONDS between uploads. (default: 0)\n"
"       --random-wait           wait from 0...2*WAIT secs between uploads.\n"
"       --waitretry=SECONDS     wait SECONDS between retries of an upload\n"
"  -l,  --limit-rate=RATE       limit upload rate to RATE\n"
"  -Y,  --proxy=http/socks/off  set proxy type or turn off\n"
"       --proxy-user=NAME       set the proxy-username to NAME\n"
"       --proxy-pass=PASS       set the proxy-password to PASS\n"
"\n"
"FTP-Options:\n"
"  -p,  --port-mode             no-passive, turn on port mode ftp (def. pasv)\n"
"  -A,  --ascii                 force ASCII  mode-transfer\n"
"  -B,  --binary                force BINARY mode-transfer\n"
"       --relative              only use relative CWDs\n"
"  -f,  --peace                 force wput not to be aggressive\n"
/*"  -S,  --script=FILE      TODO USS load a wput-script\n\n"*/
"\n"
"See the wput(1) for more detailed descriptions of the options.\n"
"Mail bug reports and suggestions to <itooktheredpill@gmx.de>";

_fsession * fsession_queue_entry_point = NULL;

void commandlineoptions(int argc, char * argv[]);
int  start_fsession();
int  start_ftp();
int  start_recur_ftp();

int main(int argc, char *argv[]){
#ifdef WIN32
	/* i don't know why, but if i call WSAStartup just once, there is an
	 * error when initialising sockets later (10093). quite strange and
	 * took me quite a while to figure out *dang* */
	WSADATA sa;
	if(WSAStartup(MAKEWORD(2,2),&sa) != 0) {
		fprintf(stderr, "1st: Error Initializing Windows Socket DLL (WSAStartup Failed).\nError-Code: 0x%x", GetLastError());
		exit(1);
	}
	if(WSAStartup(MAKEWORD(2,2),&sa) != 0) {
		fprintf(stderr, "2nd: Error Initializing Windows Socket DLL (WSAStartup Failed).\nError-Code: 0x%x", GetLastError());
		exit(1);
	}
#endif
  
	/* initialise global options and set default values */
	memset(&opt, 0, sizeof(opt));
	memset(&cc , 0, sizeof(cc ));
	opt.sbuf      = malloc(82);
	opt.retry     = -1;
	opt.retry_interval = 10;
	opt.time_deviation = 10;
	opt.binary    = TYPE_UNDEFINED;
	opt.timeout   = 300; /* 30 seconds is assumed to be a reasonable value. 10 was not! */
	opt.output    = stdout;
	opt.force     = 1;
	
	opt.verbose   = vNORMAL;
	opt.bindaddr  = INADDR_ANY;
	opt.barstyle  = 1;
	opt.proxy_bind= 1;
	opt.session_start = wtimer_alloc();
	
	/* set all fds to -1 */
	cc.csock         = -1;
	cc.data_socket   = -1;
	cc.s_socket      = -1;
	
	opt.resume_table.small_large = RESUME_TABLE_UPLOAD;
	opt.resume_table.large_large = RESUME_TABLE_SKIP;
	opt.resume_table.large_small = RESUME_TABLE_RESUME;
	
	opt.email_address = cpy("wput@localhost.com");
	
	/* env overrides home overrides system wputrc */
#ifdef SYSTEM_WPUTRC
	readwputrc(SYSTEM_WPUTRC);
#endif
	readwputrc(NULL); /*homedir*/
	readwputrc(getenv("WPUTRC"));
	
	parse_proxy(getenv("ftp_proxy"));
	
	read_password_file(getenv("PASSWORDFILE"));
	
	wtimer_reset(opt.session_start);
	
	commandlineoptions(argc, argv);

#if (! defined( WIN32)) && (! defined( __VMS))
	/* If we are still at stdout, then redirect output to 'wput-log'. */

	if(opt.background) {
		if(opt.output == stdout) {
				printout(vLESS, "Resuming in background. Logging output to 'wput-log'.\n");
				opt.output   = fopen("wput-log", "a");
				if(opt.output == NULL) { perror("Unable to open logfile"); exit(1); }
				opt.barstyle = 0;
		} else
				puts("Resuming in background.\n");
		
		if(fork() > 0) exit(2); 
		
		if(opt.input_pipe)
			printout(vNORMAL, "Warning: background-mode might not work correctly, if the input-pipe needs to read from stdin (like cat -).\n");
		if(opt.input != stdin) {
			/* create a new session and release the console-descriptors... */
			setsid ();
			freopen ("/dev/null", "r", stdin);
			freopen ("/dev/null", "w", stdout);
			freopen ("/dev/null", "w", stderr);
		} else
			printout(vNORMAL, "Warning: reading urls from stdin, while running in background-mode is not reliable.\n");
	}
#endif /* (! defined( WIN32)) && (! defined( __VMS)) */

	/* this sets the barstyle to the old one unless wput runs on a tty */
	if(opt.barstyle && !isatty( fileno(stdout) ))
		opt.barstyle = 0;
	
	if((opt.proxy_ip == 0 || opt.proxy_port == 0) && opt.proxy != PROXY_OFF) {
		printout(vLESS, "Warning: Ignoring request to turn proxy-usage on, since no proxy is configured.\n");
		opt.proxy = PROXY_OFF;
	}
	
	/* process all url/file combinations that were supplied by commandline */
	queue_process(0);
	
	/* read URLs from input-file */
	if(opt.input != 0) read_urls();
	
	/* if there are lonely files remaining, give them the last (user-supplied) url */
	process_missing();
	
	/* now we've everything we need or are already done */
	if(opt.sorturls) {
		printout(vDEBUG, "Sorting fsessions\n");
		fsession_sort();
		printout(vDEBUG, "Transmitting fsessions\n");
		while(fsession_queue_entry_point != NULL)
			fsession_transmit_file(fsession_queue_entry_point);
	}

	/* finally close any existing connections */
	if(cc.csock != -1) do_quit();
	
	if(opt.files_transfered > 1)
		printout(vNORMAL, "FINISHED --%s--\nTransfered %s bytes in %d files `%s'\n", 
			time_str(),
			legible(opt.transfered_bytes),
			opt.files_transfered,
			calculate_transfer_rate(
				wtimer_elapsed(opt.session_start), 
				opt.transfered_bytes,
				0)
			);
	
	/* clean up */
	free(opt.session_start);
	free(opt.email_address);
	free(opt.sbuf);
	
	if(opt.proxy_pass)        free(opt.proxy_pass);
	if(opt.proxy_user)        free(opt.proxy_user);
	if(opt.last_url)          free(opt.last_url);
	
	if(opt.pl)                password_list_free(opt.pl);
	skiplist_free(opt.skipdlist);
	
	
#ifdef MEMDBG
	print_unfree();
#endif
	
	return 0;
}
/* read urls/files from input-file as though they were supplied as command-line-arguments */
int read_urls(void) {
	char * url;
	char * p;
	while ((url = p = read_line(opt.input))) {
		/* skip spaces and skip lines beginning with a # */
		printout(vDEBUG, "read `%s'\n", p);

		while( isspace(*p) ) p++;
		if(*p == '#') {
			free(url);
			continue;
		}
		
		/* just foolproof check for \r\n */
		if(url[strlen(url)-2] == '\r') 
			url[strlen(url)-2] = 0;
		url[strlen(url)-1] = 0;

		if(!strncmp(p, "ftp://", 6))
			queue_add_url(cpy(p));
		else
			queue_add_file(cpy(p));

		free(url);
		/* process anything that's already complete */
		queue_process(0);
	}
	return 0;
}
/* ugly code to parse through the wputrc-options */
int set_option(char * com, char * val) {
  printout(vDEBUG, "Setting option '%s' to '%s'\n", com, val);
  
  switch(*com) {
  case '1':
  case '2':
      if(!strncmp(com, "2_1", 4)) {
          if(!strncasecmp(val, "SKIP", 5))
            opt.resume_table.small_large = RESUME_TABLE_SKIP;
          else 
            opt.resume_table.small_large = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_RESUME;
      } else if(!strncmp(com, "2_2", 4))
            opt.resume_table.large_large = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_SKIP;
      else if(!strncmp(com, "1_2", 4))
            opt.resume_table.large_small = !strncasecmp(val, "UPLOAD", 7) ? RESUME_TABLE_UPLOAD : RESUME_TABLE_SKIP;
      else
            return -1;
      return 0;
  case 'b':
      if(!strncasecmp(com, "bind-address", 13)) {
            if(get_ip_addr(optarg, &opt.bindaddr) == -1) {
                printout(vLESS, "Unable to determine IP-Address of %s. Exiting.\n", optarg);
                exit(1);
            }
            return 0;
        } else return -1;
  case 'c':
      if(!strncasecmp(com, "connection_mode", 16)) {
        if(!strncasecmp(val, "pasv", 5)) {
          opt.portmode = 0;
        } else if(!strncasecmp(val, "port", 4)) {
          opt.portmode = 1;
        } else return -1;
      } else return -1;
      return 0;
  case 'm':
      if(!strncmp(com, "email_address", 13))
          opt.email_address = cpy(val);
      else return -1;
      return 0;
  case 'p':
      if(!strncasecmp(com, "peace", 6))
        opt.force  = 0;
      else if(!strncasecmp(com, "proxy", 6)) {
        if(!strncmp(val, "http", 5))
          opt.proxy = PROXY_HTTP;
        else if(!strncasecmp(val, "socks", 6)) 
          opt.proxy = PROXY_SOCKS;
        else
          opt.proxy = PROXY_OFF;
      }
      else if(!strncasecmp(com, "proxy_host", 11)) {
        if(get_ip_addr(val, &opt.proxy_ip) == -1) {
          if(opt.force) {
            printout(vLESS, "Cannot determinete proxy ip addr. Disabling proxy support.");
            opt.proxy = 0;
          } else wpAbort("Cannot determinete proxy ip addr");
        } 
      }
      else if(!strncasecmp(com, "proxy_port", 11))
          opt.proxy_port = atoi(val);
      else if(!strncasecmp(com, "proxy_user", 11))
          opt.proxy_user = cpy(val);
      else if(!strncasecmp(com, "proxy_pass", 11))
          opt.proxy_pass = cpy(val);
      else if(!strncasecmp(com, "proxy_bind", 11))
          opt.proxy_bind = !strncasecmp(val, "on", 3);
      else if(!strncasecmp(com, "passwordfile", 13) || !strncasecmp(com, "password_file", 14))
          read_password_file(val);
      else return -1;
      return 0;
    case 'r':
        if(!strncasecmp(com, "rate", 5)) {
          opt.speed_limit = atoi(val);
          while(*val) {
            if(*val == 'K') opt.speed_limit *= 1024;
            if(*val == 'M') opt.speed_limit *= 1024 * 1024;
            val++;
          }
          printout(vDEBUG, "Rate-Limit is set to %d Bytes per second\n", opt.speed_limit);
        } else if(!strncasecmp(com, "retry_count", 12))
            opt.retry = atoi(val);
        else if(!strncasecmp(com, "relative_cwd", 13))
            opt.relative_cwds = !strncasecmp(val, "on", 3);
        else return -1;
        return 0;
  case 's':
      //if(!strncmp(com, "script_file", 12))
        //load_script(val);
      //else
      if(!strncasecmp(com, "sort_urls", 10))
        opt.sorturls = !strncasecmp(val, "on", 3);
      else return -1;
      return 0;
  case 't':
      if(!strncasecmp(com, "timeout", 8))
        opt.timeout         = atoi(val);
      else if(!strncasecmp(com, "timestamping", 13))
        opt.timestamping    = !strncasecmp(val, "on", 3);
      else if(!strncasecmp(com, "timeoffset", 11))
        opt.time_offset     = atoi(val);
      else if(!strncasecmp(com, "timeoffset", 11))
        opt.time_deviation  = atoi(val);
      else if(!strncasecmp(com, "transfer_type", 14)) {
        if(!strncasecmp(val, "auto", 5)) opt.binary = TYPE_UNDEFINED;
        else if(!strncasecmp(val, "ascii", 6))  opt.binary = TYPE_A;
        else if(!strncasecmp(val, "binary", 7)) opt.binary = TYPE_I;
        else return -2;
      } else return -1;
      return 0;
  case 'v':
      if(!strncasecmp(com, "verbosity", 10)) {
        char * levels[] = {"quite", "less", "normal", "more", "debug"};
        int i;
        for(i=0;i<5;i++)
          if(!strcasecmp(val, levels[i])) {
            opt.verbose = i;
            return 0;
          }
        return -2;
      } else return -1;
  case 'w':
      if(!strncasecmp(com, "wait_retry", 11))
        opt.retry_interval = atoi(val);
      else return -1;
      return 0;
  }
  return -1;  
}
/* read the password file and store its contents in a linked list */
/* TODO USS take the .netrc-file ... (there are implementations of wget and fetchmail. they should do the trick...) */
void read_password_file(char * f) {
	FILE * fp;
	char * line;
	char * tmp;
	char * user;
	char * pass;
	if(!file_exists(f)) {
		printout(vMORE, "password_file '%s' cannot be read. skipping\n", f);
		return;
	}
	printout(vDEBUG, "Reading password-file '%s'", f);
	fp = fopen(f, "r");
	while( (tmp = line = read_line(fp)) ) {
		while(isspace(*tmp) && *tmp) tmp++;
		strtok(tmp, "\t");
		user = strtok(NULL, "\t");
		pass = strtok(NULL, "\t");
		if(*tmp == 0 || *tmp == '#' || user == NULL || pass == NULL) {
			free(line);
			continue;
		}
		if(pass[strlen(pass)-2] == '\r') pass[strlen(pass)-2] = 0;
		else if(pass[strlen(pass)-1] == '\n') pass[strlen(pass)-1] = 0;
		opt.pl = password_list_add(opt.pl, cpy(tmp), cpy(user), cpy(pass));
		printout(vNORMAL, "added %s:%s@%s to the password-list (%x)\n", user, pass, tmp, opt.pl);
		free(line);
	}
}
/* reads a wputrc file. parses its options and gives error-reports if necessary */
void readwputrc(char * f) {
    FILE * fp;
    char * file;
    char * line;
    int    ln   = 1;

    if(f == NULL) {
        char * home = home_dir();
        file = malloc(strlen(home) + 10); /* home + slash + (.wputrc | wput.ini) + 0-char */
        sprintf(file, "%s/%s", home, WPUTRC_FILENAME);
        free(home);
    } else file = cpy(f);

    printout(vDEBUG, "Reading wputrc-file: %s\n", file);
    
    if(!file_exists(file)) {
        printout(vDEBUG, "wputrc-file '%s' is not readable. skipping.\n", file);
        free(file);
        return;
    }
    
    fp = fopen (file, "r");
    if(!fp) {
      printout(vLESS, "Fatal error while opening '%s': %s\n", file, strerror (errno));
      free(file);
      return;
    }
    
  while ((line = read_line (fp))) {
    char * tmp = line;
    char * com;
    char * val;
    /* skip leading spaces */
    while(isspace(*tmp) && *tmp) tmp++;
    
    /* discard comment lines */
    if(*tmp == '#' || *tmp == ';' || *tmp == 0) {
        free(line);
        continue;
    }
    com = tmp;
    
    /* search for space, end or '=' */
    while(!isspace(*tmp) && *tmp && *tmp != '=') tmp++;
    *tmp++= 0;
    
    while((isspace(*tmp) || *tmp == '=') && *tmp) tmp++;
    val = tmp;
    
    /* suppress the new-line-char */
    while(*tmp != 0 && *tmp != '\n') tmp++;
    if(*(tmp-1) == '\r') *(tmp-1) = 0;
    else                 * tmp    = 0;

    /* we mis-use tmp to store the ret_val, and print a message if something was not parse-able */
    tmp = (char *) set_option(com, val);
    if(tmp == (char *) -1) printout(vLESS, "%s#%d: Option '%s' not recognized\n", file, ln, com);
    if(tmp == (char *) -2) printout(vLESS, "%s#%d: Unknow value '%s' for '%s'\n", file, ln, val, com);
    free(line);
    ln++;
  }
  free(file);
}

/* parses all the commandline-options available. */
void commandlineoptions(int argc, char * argv[]){
    int c;

    /* TODO IMP windows doesn't automatically fill *.txt with the 
     * TODO IMP corresponding filenames. So this must be done by us (*urgs*) */

    int option_index = 0;
    static struct option long_options[] =
      {
        {"append-output", 1, 0, 'a'},    //0
        {"ascii", 0, 0, 'A'},
        {"background", 1, 0, 'b'},
        {"binary", 0, 0, 'B'},
        {"bind-address", 1, 0, 0},
        {"compile-options", 0, 0, 0},    //5
        {"debug", 0, 0, 'd'},
        {"dont-continue", 0, 0, 0},
        {"help", 0, 0, 'h'},  
        {"input-file", 1, 0, 'i'},      
        {"input-pipe", 1, 0, 'I'},      //10
        {"less-verbose", 0, 0, 0},      
        {"limit-rate", 1, 0, 'l'},
        {"output-file", 1, 0, 'o'},        
        {"peace", 0, 0, 'f'},           
        {"port-mode", 0, 0, 'p'},       //15
        {"proxy", 1, 0, 'Y'},  
        {"proxy-user", 1, 0, 0},
        {"proxy-pass", 1, 0, 0},
        {"quiet", 0, 0, 'q'},
        {"random-wait", 0, 0, 0},       //20
        {"relative", 0, 0, 0},          
        {"remove-source-files", 1, 0, 'R'}, 
        {"reupload", 0, 0, 'u'},        
        {"script", 1, 0, 's'},
        {"skip-existing", 0, 0, 0},     //25
        {"skip-larger", 0, 0, 0},       
        {"sort", 0, 0, 's'},            
        {"timeoffset", 1, 0, 0},        
        {"timeout", 1, 0, 'T'},
        {"timestamping", 0, 0, 'N'},    //30
        {"tries", 1, 0, 't'},           
        {"use-proxy", 1, 0, 'Y'},       
        {"verbose", 0, 0, 'v'},         
        {"version", 0, 0, 'V'},
        {"wait", 1, 0, 'w'},            //35
        {"waitretry", 1, 0, 0},         
        {0, 0, 0, 0}                    
      };
    while (1)
    {
        c = getopt_long (argc, argv, "Vhbo:a:dqvn:i:I:t:NT:w:Rl:pABfsS:u",
                           long_options, &option_index);
                
        if (c == -1)
                break;
        
        switch (c)
        {
        case 0:
            switch(option_index) {
            case 11:  //less-verbose
                opt.verbose--;  break;
            case  4: set_option("bind-address", optarg);
                                break;
	    case  7: if(opt.resume_table.large_small == RESUME_TABLE_RESUME)
		        opt.resume_table.large_small =  RESUME_TABLE_UPLOAD;
		     break;     
            case 20: //random-wait
				opt.random_wait = 1;	break;
            case 21: //relative
                opt.relative_cwds = 1;  break;
            case 15: //port-mode
                opt.portmode = 1;        break;
            case 17: set_option("proxy_user", optarg);  break;
            case 18: set_option("proxy_pass", optarg);  break;
            case  5: //compile-options
                fprintf(opt.output, "wput version: %s\n\n#defined options:\n", version);
#ifdef TIMER_GETTIMEOFDAY 
                fprintf(opt.output, "TIMER_GETTIMEOFDAY\n");
#endif
                fprintf(opt.output, "\nUsing %d-Bytes for UINT64\n", sizeof(UINT64));
                exit(0);
            case 26: //skip-larger
                opt.resume_table.large_small = RESUME_TABLE_SKIP;   break;
            case 25: //skip-existing
                opt.resume_table.large_small = RESUME_TABLE_SKIP;
                opt.resume_table.large_large = RESUME_TABLE_SKIP;
                opt.resume_table.small_large = RESUME_TABLE_SKIP;   break;
            case 28: //timeoffset
                set_option("timeoffset", optarg);                   break;
            case 36: //waitretry
                opt.retry_interval = atoi(optarg);                  break;
            default:
                fprintf(stderr, "Option %s should not appear here :|\n", long_options[option_index].name);
            }
            break;
        case 'o': 
        case 'a': opt.output = fopen(optarg, (c == 'o') ? "w" : "a");
                  if(opt.output == NULL) { perror("Unable to open logfile"); exit(1); }
                  opt.barstyle = 0;
                  break;
#ifndef WIN32
        case 'b': opt.background = 1;           break;
#endif
        case 't': 
                  opt.retry = atoi(optarg);
                  if(opt.retry <= 0) opt.retry = -1;
                  break;
        case 'T': opt.timeout = atoi(optarg);   break;
        case 'p': opt.portmode = 1;             break;
        case 'n':
                  if(optarg[0] == 'v')      opt.verbose--;
                  if(optarg[0] == 'c') 
                    if(opt.resume_table.large_small == RESUME_TABLE_RESUME)
                       opt.resume_table.large_small =  RESUME_TABLE_UPLOAD;
                  break;
        case 'u': opt.resume_table.large_large = RESUME_TABLE_UPLOAD; break;
        case 'N': opt.timestamping = 1;         break;
        case 'v': opt.verbose++;                break;
        case 'q': opt.verbose=0;                break;
        case 'd': opt.verbose=vDEBUG;           break;
        case 'w': opt.wait   =atoi(optarg);     break;
        case 'A': opt.binary = TYPE_A;          break;
        case 'B': opt.binary = TYPE_I;          break;
        case 'f': opt.force  = 0;               break;
        case 's': opt.sorturls = 1;             break;
        case 'S': wpAbort("TODO SCRIPTING\n");  break;
        case 'l': set_option("rate", optarg);   break;
        case 'i': 
                  if(!strncmp(optarg, "-", 2)) {
                    printout(vDEBUG, "Reading URLs from stdin\n");
                    opt.input = stdin;
                  } else {
                    printout(vDEBUG, "Reading URLs from `%s'\n", optarg);
                    opt.input = fopen(optarg, "r");
                    if(opt.input == NULL) {
                        perror(optarg);
                        exit(1);
                    }
                  }
                  break;
        case 'I': printout(vNORMAL, "Warning: You supplied an input-pipe. "
                      "This is only to be used as fallback, if no filename "
                      "can be found from the URL. This might not be the desired "
                      "behavour. TODO\n");
                  opt.input_pipe = optarg;      break;
        case 'R': opt.unlink = 1;               break;
        case 'Y': set_option("proxy", optarg);  break;
        case 'V':
            fprintf(opt.output, "wput version: %s\n", version);
            exit(0);
        case 'h':
        default:
            fprintf(stderr, "Usage: %s\n", main_menu);
            exit(0);
        }
    }
    
    /* TODO NRV check if we got any input urls. otherwise print usage information */
    while(optind < argc) {
        if(!strncmp(argv[optind], "ftp://", 6))
            queue_add_url(cpy(argv[optind]));
        else
            queue_add_file(cpy(argv[optind]));
        optind++;
    }
}
