doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
main.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: main.c,v 1.247 2004/03/17 12:46:48 bagder Exp $
22  ***************************************************************************/
23 
24 /* This is now designed to have its own local setup.h */
25 #include "setup.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <ctype.h>
34 #include <errno.h>
35 
36 #include <curl/curl.h>
37 
38 #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
39 #include <curl/mprintf.h>
40 
41 #include "urlglob.h"
42 #include "writeout.h"
43 #include "getpass.h"
44 #include "homedir.h"
45 #ifdef USE_MANUAL
46 #include "hugehelp.h"
47 #endif
48 #ifdef USE_ENVIRONMENT
49 #include "writeenv.h"
50 #endif
51 
52 #define CURLseparator "--_curl_--"
53 
54 #if defined(WIN32)&&!defined(__CYGWIN32__)
55 #include <winsock2.h>
56 #endif
57 
58 #ifdef __NOVELL_LIBC__
59 #include <screen.h>
60 #endif
61 
62 #ifdef TIME_WITH_SYS_TIME
63 /* We can include both fine */
64 #include <sys/time.h>
65 #include <time.h>
66 #else
67 #ifdef HAVE_SYS_TIME_H
68 # include <sys/time.h>
69 #else
70 # include <time.h>
71 #endif
72 #endif
73 
74 
75 #include "version.h"
76 
77 #ifdef HAVE_IO_H /* typical win32 habit */
78 #include <io.h>
79 #endif
80 
81 #ifdef HAVE_UNISTD_H
82 #include <unistd.h>
83 #endif
84 
85 #ifdef HAVE_FCNTL_H
86 #include <fcntl.h>
87 #endif
88 
89 #ifdef HAVE_UTIME_H
90 #include <utime.h>
91 #else
92 #ifdef HAVE_SYS_UTIME_H
93 #include <sys/utime.h>
94 #endif
95 
96 #endif
97 
98 #ifdef HAVE_LIMITS_H
99 #include <limits.h>
100 #endif
101 
102 #ifdef HAVE_SYS_POLL_H
103 #include <sys/poll.h>
104 #endif
105 
106 #include <strtoofft.h> /* header from the libcurl directory */
107 
108 /* The last #include file should be: */
109 #ifdef CURLDEBUG
110 /* This is low-level hard-hacking memory leak tracking and similar. Using
111  the library level code from this client-side is ugly, but we do this
112  anyway for convenience. */
113 #include "memdebug.h"
114 #endif
115 
116 #define DEFAULT_MAXREDIRS 50L
117 
118 #ifdef __DJGPP__
119 void *xmalloc(size_t);
120 char *msdosify(char *);
121 char *rename_if_dos_device_name(char *);
122 void xfree(void *);
123 struct pollfd {
124  int fd;
125  int events; /* in param: what to poll for */
126  int revents; /* out param: what events occured */
127  };
128 int poll (struct pollfd *, int, int);
129 #endif /* __DJGPP__ */
130 
131 #ifndef __cplusplus
132 #ifndef typedef_bool
133 typedef char bool;
134 #endif
135 #endif
136 
137 #define CURL_PROGRESS_STATS 0 /* default progress display */
138 #define CURL_PROGRESS_BAR 1
139 
144 #ifndef MIN
145 #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
146 #endif
147 
148 typedef enum {
156 } HttpReq;
157 
158 /* Just a set of bits */
159 #define CONF_DEFAULT 0
160 
161 #define CONF_AUTO_REFERER (1<<4) /* the automatic referer-system please! */
162 #define CONF_VERBOSE (1<<5) /* talk a lot */
163 #define CONF_HEADER (1<<8) /* throw the header out too */
164 #define CONF_NOPROGRESS (1<<10) /* shut off the progress meter */
165 #define CONF_NOBODY (1<<11) /* use HEAD to get http document */
166 #define CONF_FAILONERROR (1<<12) /* no output on http error codes >= 300 */
167 #define CONF_FTPLISTONLY (1<<16) /* Use NLST when listing ftp dir */
168 #define CONF_FTPAPPEND (1<<20) /* Append instead of overwrite on upload! */
169 #define CONF_NETRC (1<<22) /* read user+password from .netrc */
170 #define CONF_FOLLOWLOCATION (1<<23) /* use Location: Luke! */
171 #define CONF_GETTEXT (1<<24) /* use ASCII/text for transfer */
172 #define CONF_HTTPPOST (1<<25) /* multipart/form-data HTTP POST */
173 #define CONF_MUTE (1<<28) /* force NOPROGRESS */
174 
175 #define CONF_NETRC_OPT (1<<29) /* read user+password from either
176  * .netrc or URL*/
177 #define CONF_UNRESTRICTED_AUTH (1<<30)
178 /* Send authentication (user+password) when following
179  * locations, even when hostname changed */
180 
181 #ifndef HAVE_STRDUP
182 /* Ultrix doesn't have strdup(), so make a quick clone: */
183 char *strdup(char *str)
184 {
185  int len;
186  char *newstr;
187 
188  len = strlen(str);
189  newstr = (char *) malloc((len+1)*sizeof(char));
190  if (!newstr)
191  return (char *)NULL;
192 
193  strcpy(newstr,str);
194 
195  return newstr;
196 
197 }
198 #endif
199 
200 #ifdef WIN32
201 #include <direct.h>
202 #define F_OK 0
203 #define mkdir(x,y) (mkdir)(x)
204 #endif
205 
206 #ifdef VMS
207 #include "curlmsg_vms.h"
208 #endif
209 
210 /*
211  * This is the main global constructor for the app. Call this before
212  * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
213  * used, or havoc may be the result.
214  */
215 static CURLcode main_init(void)
216 {
218 }
219 
220 /*
221  * This is the main global destructor for the app. Call this after
222  * _all_ libcurl usage is done.
223  */
224 static void main_free(void)
225 {
227 }
228 
229 static int SetHTTPrequest(HttpReq req, HttpReq *store)
230 {
231  if((*store == HTTPREQ_UNSPEC) ||
232  (*store == req)) {
233  *store = req;
234  return 0;
235  }
236  fprintf(stderr, "You can only select one HTTP request!\n");
237  return 1;
238 }
239 
240 static void helpf(const char *fmt, ...)
241 {
242  va_list ap;
243  if(fmt) {
244  va_start(ap, fmt);
245  fputs("curl: ", stderr); /* prefix it */
246  vfprintf(stderr, fmt, ap);
247  va_end(ap);
248  }
249  fprintf(stderr, "curl: try 'curl --help' "
250 #ifdef USE_MANUAL
251  "or 'curl --manual' "
252 #endif
253  "for more information\n");
254 }
255 
256 /*
257  * A chain of these nodes contain URL to get and where to put the URL's
258  * contents.
259  */
260 struct getout {
261  struct getout *next; /* next one */
262  char *url; /* the URL we deal with */
263  char *outfile; /* where to store the output */
264  char *infile; /* file to upload, if GETOUT_UPLOAD is set */
265  int flags; /* options */
266 };
267 #define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
268 #define GETOUT_URL (1<<1) /* set when URL is deemed done */
269 #define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
270 #define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
271 #define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
272 
273 
274 static void help(void)
275 {
276  int i;
277  static const char *helptext[]={
278  "Usage: curl [options...] <url>",
279  "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
280  " -a/--append Append to target file when uploading (F)",
281  " -A/--user-agent <string> User-Agent to send to server (H)",
282  " --anyauth Tell curl to choose authentication method (H)",
283  " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
284  " --basic Enable HTTP Basic Authentication (H)",
285  " -B/--use-ascii Use ASCII/text transfer",
286  " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
287  " -C/--continue-at <offset> Resumed transfer offset",
288  " -d/--data <data> HTTP POST data (H)",
289  " --data-ascii <data> HTTP POST ASCII data (H)",
290  " --data-binary <data> HTTP POST binary data (H)",
291  " --negotiate Enable HTTP Negotiate Authentication (H)",
292  " --digest Enable HTTP Digest Authentication (H)",
293  " --disable-eprt Prevent curl from using EPRT or LPRT (F)",
294  " --disable-epsv Prevent curl from using EPSV (F)",
295  " -D/--dump-header <file> Write the headers to this file",
296  " --egd-file <file> EGD socket path for random data (SSL)",
297 #ifdef USE_ENVIRONMENT
298  " --environment Write result codes to environment variables (RISC OS)",
299 #endif
300  " -e/--referer Referer URL (H)",
301  " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
302  " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
303  " --key <key> Private key file name (SSL)",
304  " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
305  " --pass <pass> Pass phrase for the private key (SSL)",
306  " --engine <eng> Crypto engine to use (SSL)",
307  " --cacert <file> CA certificate to verify peer against (SSL)",
308  " --capath <directory> CA directory (made using c_rehash) to verify",
309  " peer against (SSL)",
310  " --ciphers <list> SSL ciphers to use (SSL)",
311  " --compressed Request compressed response (using deflate or gzip)",
312  " --connect-timeout <seconds> Maximum time allowed for connection",
313  " --create-dirs Create necessary local directory hierarchy",
314  " --crlf Convert LF to CRLF in upload",
315  " -f/--fail Fail silently (no output at all) on errors (H)",
316  " --ftp-create-dirs Create the remote dirs if not present (F)",
317  " --ftp-pasv Use PASV instead of PORT (F)",
318  " --ftp-ssl Enable SSL/TLS for the ftp transfer (F)",
319  " -F/--form <name=content> Specify HTTP multipart POST data (H)",
320  " -g/--globoff Disable URL sequences and ranges using {} and []",
321  " -G/--get Send the -d data with a HTTP GET (H)",
322  " -h/--help This help text",
323  " -H/--header <line> Custom header to pass to server (H)",
324  " -i/--include Include protocol headers in the output (H/F)",
325  " -I/--head Show document info only",
326  " -j/--junk-session-cookies Ignore session cookies read from file (H)",
327  " --interface <interface> Specify network interface to use",
328  " --krb4 <level> Enable krb4 with specified security level (F)",
329  " -k/--insecure Allow curl to connect to SSL sites without certs (H)",
330  " -K/--config Specify which config file to read",
331  " -l/--list-only List only names of an FTP directory (F)",
332  " --limit-rate <rate> Limit transfer speed to this rate",
333  " -L/--location Follow Location: hints (H)",
334  " --location-trusted Follow Location: and send authentication even ",
335  " to other hostnames (H)",
336  " -m/--max-time <seconds> Maximum time allowed for the transfer",
337  " --max-redirs <num> Maximum number of redirects allowed (H)",
338  " --max-filesize <bytes> Maximum file size to download (H/F)",
339  " -M/--manual Display the full manual",
340  " -n/--netrc Must read .netrc for user name and password",
341  " --netrc-optional Use either .netrc or URL; overrides -n",
342  " --ntlm Enable HTTP NTLM authentication (H)",
343  " -N/--no-buffer Disable buffering of the output stream",
344  " -o/--output <file> Write output to <file> instead of stdout",
345  " -O/--remote-name Write output to a file named as the remote file",
346  " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
347  " --proxy-ntlm Enable NTLM authentication on the proxy (H)",
348  " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
349  " -q If used as the first parameter disables .curlrc",
350  " -Q/--quote <cmd> Send command(s) to server before file transfer (F)",
351  " -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server",
352  " --random-file <file> File for reading random data from (SSL)",
353  " -R/--remote-time Set the remote file's time on the local output",
354  " -s/--silent Silent mode. Don't output anything",
355  " -S/--show-error Show error. With -s, make curl show errors when they occur",
356  " --socks <host[:port]> Use SOCKS5 proxy on given host + port",
357  " --stderr <file> Where to redirect stderr. - means stdout",
358  " -t/--telnet-option <OPT=val> Set telnet option",
359  " --trace <file> Dump a network/debug trace to the given file",
360  " --trace-ascii <file> Like --trace but without the hex output",
361  " -T/--upload-file <file> Transfer/upload <file> to remote site",
362  " --url <URL> Another way to specify URL to work with",
363  " -u/--user <user[:password]> Specify user and password to use",
364  " Overrides -n and --netrc-optional",
365  " -U/--proxy-user <user[:password]> Specify Proxy authentication",
366  " -v/--verbose Make the operation more talkative",
367  " -V/--version Show version number and quit",
368 #ifdef __DJGPP__
369  " --wdebug Turn on WATT-32 debugging under DJGPP",
370 #endif
371  " -w/--write-out [format] What to output after completion",
372  " -x/--proxy <host[:port]> Use HTTP proxy on given port",
373  " -X/--request <command> Specify request command to use",
374  " -y/--speed-time Time needed to trig speed-limit abort. Defaults to 30",
375  " -Y/--speed-limit Stop transfer if below speed-limit for 'speed-time' secs",
376  " -z/--time-cond <time> Transfer based on a time condition",
377  " -0/--http1.0 Use HTTP 1.0 (H)",
378  " -1/--tlsv1 Use TLSv1 (SSL)",
379  " -2/--sslv2 Use SSLv2 (SSL)",
380  " -3/--sslv3 Use SSLv3 (SSL)",
381  " -4/--ipv4 Resolve name to IPv4 address",
382  " -6/--ipv6 Resolve name to IPv6 address",
383  " -#/--progress-bar Display transfer progress as a progress bar",
384  NULL
385  };
386  for(i=0; helptext[i]; i++) {
387  puts(helptext[i]);
388 #ifdef __NOVELL_LIBC__
389  if (i && ((i % 23) == 0))
390  pressanykey();
391 #endif
392  }
393 }
394 
395 struct LongShort {
396  const char *letter;
397  const char *lname;
399 };
400 
401 struct Configurable {
403  char *random_file;
404  char *egd_file;
405  char *useragent;
406  char *cookie; /* single line with specified cookies */
407  char *cookiejar; /* write to this file */
408  char *cookiefile; /* read from this file */
409  bool cookiesession; /* new session? */
410  bool encoding; /* Accept-Encoding please */
411  long authtype; /* auth bitmask */
417  char *postfields;
419  char *referer;
420  long timeout;
422  long maxredirs;
424  char *headerfile;
425  char *ftpport;
426  char *iface;
427  unsigned short porttouse;
428  char *range;
431  bool showerror;
432  char *userpwd;
434  char *proxy;
436  long conf;
437 
438  struct getout *url_list; /* point to the first node */
439  struct getout *url_last; /* point to the last/current node */
440 
441  struct getout *url_get; /* point to the node to fill in URL */
442  struct getout *url_out; /* point to the node to fill in outfile */
443 
444  char *cipher_list;
445  char *cert;
446  char *cert_type;
447  char *cacert;
448  char *capath;
449  char *key;
450  char *key_type;
451  char *key_passwd;
452  char *engine;
453  bool crlf;
455  char *krb4level;
456  char *trace_dump; /* file to dump the network trace to, or NULL */
460 
463  bool nobuffer;
464  bool globoff;
466  bool insecure_ok; /* set TRUE to allow insecure SSL connects */
469  bool proxyntlm;
470 
471  char *writeout; /* %-styled format string to output */
472  bool writeenv; /* write results to environment, if available */
473 
474  FILE *errors; /* if stderr redirect is requested */
476 
477  struct curl_slist *quote;
480 
484  time_t condtime;
485 
487 
490 
492 
494 
495  /* for bandwidth limiting features: */
496 
497  size_t sendpersecond; /* send to peer */
498  size_t recvpersecond; /* receive from peer */
499 
500  time_t lastsendtime;
501  size_t lastsendsize;
502 
503  time_t lastrecvtime;
504  size_t lastrecvsize;
505 
506  bool ftp_ssl;
507 
508  char *socks5proxy;
509 };
510 
511 /* global variable to hold info about libcurl */
512 static curl_version_info_data *curlinfo;
513 
514 static void parseconfig(const char *filename,
515  struct Configurable *config);
516 static char *my_get_line(FILE *fp);
517 static int create_dir_hierarchy(char *outfile);
518 
519 static void GetStr(char **string,
520  char *value)
521 {
522  if(*string)
523  free(*string);
524  if(value)
525  *string = strdup(value);
526  else
527  *string = NULL;
528 }
529 
530 static char *file2string(FILE *file)
531 {
532  char buffer[256];
533  char *ptr;
534  char *string=NULL;
535  size_t len=0;
536  size_t stringlen;
537 
538  if(file) {
539  while(fgets(buffer, sizeof(buffer), file)) {
540  ptr= strchr(buffer, '\r');
541  if(ptr)
542  *ptr=0;
543  ptr= strchr(buffer, '\n');
544  if(ptr)
545  *ptr=0;
546  stringlen=strlen(buffer);
547  if(string)
548  string = realloc(string, len+stringlen+1);
549  else
550  string = malloc(stringlen+1);
551 
552  strcpy(string+len, buffer);
553 
554  len+=stringlen;
555  }
556  return string;
557  }
558  else
559  return NULL; /* no string */
560 }
561 
562 static char *file2memory(FILE *file, long *size)
563 {
564  char buffer[1024];
565  char *string=NULL;
566  char *newstring=NULL;
567  size_t len=0;
568  long stringlen=0;
569 
570  if(file) {
571  while((len = fread(buffer, 1, sizeof(buffer), file))) {
572  if(string) {
573  newstring = realloc(string, len+stringlen);
574  if(newstring)
575  string = newstring;
576  else
577  break; /* no more strings attached! :-) */
578  }
579  else
580  string = malloc(len);
581  memcpy(&string[stringlen], buffer, len);
582  stringlen+=len;
583  }
584  *size = stringlen;
585  return string;
586  }
587  else
588  return NULL; /* no string */
589 }
590 
591 static void clean_getout(struct Configurable *config)
592 {
593  struct getout *node=config->url_list;
594  struct getout *next;
595 
596  while(node) {
597  next = node->next;
598  if(node->url)
599  free(node->url);
600  if(node->outfile)
601  free(node->outfile);
602  if(node->infile)
603  free(node->infile);
604  free(node);
605 
606  node = next; /* GOTO next */
607  }
608 }
609 
610 static struct getout *new_getout(struct Configurable *config)
611 {
612  struct getout *node =malloc(sizeof(struct getout));
613  struct getout *last= config->url_last;
614  if(node) {
615  /* clear the struct */
616  memset(node, 0, sizeof(struct getout));
617 
618  /* append this new node last in the list */
619  if(last)
620  last->next = node;
621  else
622  config->url_list = node; /* first node */
623 
624  /* move the last pointer */
625  config->url_last = node;
626  }
627  return node;
628 }
629 
630 /* Structure for storing the information needed to build a multiple files
631  * section
632 */
633 struct multi_files {
634  struct curl_forms form;
635  struct multi_files *next;
636 };
637 
638 /* Add a new list entry possibly with a type_name
639  */
640 static struct multi_files *
641 AddMultiFiles (const char *file_name,
642  const char *type_name,
643  const char *show_filename,
644  struct multi_files **multi_start,
645  struct multi_files **multi_current)
646 {
647  struct multi_files *multi;
648  struct multi_files *multi_type = NULL;
649  struct multi_files *multi_name = NULL;
650  multi = (struct multi_files *)malloc(sizeof(struct multi_files));
651  if (multi) {
652  memset(multi, 0, sizeof(struct multi_files));
653  multi->form.option = CURLFORM_FILE;
654  multi->form.value = file_name;
655  }
656  else
657  return NULL;
658 
659  if (!*multi_start)
660  *multi_start = multi;
661 
662  if (type_name) {
663  multi_type = (struct multi_files *)malloc(sizeof(struct multi_files));
664  if (multi_type) {
665  memset(multi_type, 0, sizeof(struct multi_files));
666  multi_type->form.option = CURLFORM_CONTENTTYPE;
667  multi_type->form.value = type_name;
668  multi->next = multi_type;
669 
670  multi = multi_type;
671  }
672  else {
673  free (multi);
674  return NULL;
675  }
676  }
677  if (show_filename) {
678  multi_name = (struct multi_files *)malloc(sizeof(struct multi_files));
679  if (multi_name) {
680  memset(multi_name, 0, sizeof(struct multi_files));
681  multi_name->form.option = CURLFORM_FILENAME;
682  multi_name->form.value = show_filename;
683  multi->next = multi_name;
684 
685  multi = multi_name;
686  }
687  else {
688  free (multi);
689  return NULL;
690  }
691  }
692 
693  if (*multi_current)
694  (*multi_current)->next = multi;
695 
696  *multi_current = multi;
697 
698  return *multi_current;
699 }
700 
701 /* Free the items of the list.
702  */
703 static void FreeMultiInfo (struct multi_files *multi_start)
704 {
705  struct multi_files *multi;
706  while (multi_start) {
707  multi = multi_start;
708  multi_start = multi_start->next;
709  free (multi);
710  }
711 }
712 
713 /***************************************************************************
714  *
715  * formparse()
716  *
717  * Reads a 'name=value' paramter and builds the appropriate linked list.
718  *
719  * Specify files to upload with 'name=@filename'. Supports specified
720  * given Content-Type of the files. Such as ';type=<content-type>'.
721  *
722  * You may specify more than one file for a single name (field). Specify
723  * multiple files by writing it like:
724  *
725  * 'name=@filename,filename2,filename3'
726  *
727  * If you want content-types specified for each too, write them like:
728  *
729  * 'name=@filename;type=image/gif,filename2,filename3'
730  *
731  * If you want custom headers added for a single part, write them in a separate
732  * file and do like this:
733  *
734  * 'name=foo;headers=@headerfile' or why not
735  * 'name=@filemame;headers=@headerfile'
736  *
737  * To upload a file, but to fake the file name that will be included in the
738  * formpost, do like this:
739  *
740  * 'name=@filename;filename=/dev/null'
741  *
742  * This function uses curl_formadd to fulfill it's job. Is heavily based on
743  * the old curl_formparse code.
744  *
745  ***************************************************************************/
746 
747 #define FORM_FILE_SEPARATOR ','
748 #define FORM_TYPE_SEPARATOR ';'
749 
750 static int formparse(char *input,
751  struct curl_httppost **httppost,
752  struct curl_httppost **last_post)
753 {
754  /* nextarg MUST be a string in the format 'name=contents' and we'll
755  build a linked list with the info */
756  char name[256];
757  char *contents;
758  char major[128];
759  char minor[128];
760  char *contp;
761  const char *type = NULL;
762  char *sep;
763  char *sep2;
764 
765  /* Preallocate contents to the length of input to make sure we don't
766  overwrite anything. */
767  contents = malloc(strlen(input));
768  contents[0] = '\000';
769 
770  if(1 <= sscanf(input, "%255[^=]=%[^\n]", name, contents)) {
771  /* the input was using the correct format */
772  contp = contents;
773 
774  if('@' == contp[0]) {
775  struct multi_files *multi_start = NULL, *multi_current = NULL;
776  /* we use the @-letter to indicate file name(s) */
777  contp++;
778 
779  multi_start = multi_current=NULL;
780 
781  do {
782  /* since this was a file, it may have a content-type specifier
783  at the end too, or a filename. Or both. */
784  char *ptr;
785  char *filename=NULL;
786 
787  sep=strchr(contp, FORM_TYPE_SEPARATOR);
788  sep2=strchr(contp, FORM_FILE_SEPARATOR);
789 
790  /* pick the closest */
791  if(sep2 && (sep2 < sep)) {
792  sep = sep2;
793 
794  /* no type was specified! */
795  }
796 
797  type = NULL;
798 
799  if(sep) {
800 
801  /* if we got here on a comma, don't do much */
802  if(FORM_FILE_SEPARATOR == *sep)
803  ptr = NULL;
804  else
805  ptr = sep+1;
806 
807  *sep=0; /* terminate file name at separator */
808 
809  while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
810 
811  /* pass all white spaces */
812  while(isspace((int)*ptr))
813  ptr++;
814 
815  if(curl_strnequal("type=", ptr, 5)) {
816 
817  /* set type pointer */
818  type = &ptr[5];
819 
820  /* verify that this is a fine type specifier */
821  if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
822  major, minor)) {
823  fprintf(stderr, "Illegally formatted content-type field!\n");
824  free(contents);
825  FreeMultiInfo (multi_start);
826  return 2; /* illegal content-type syntax! */
827  }
828  /* now point beyond the content-type specifier */
829  sep = (char *)type + strlen(major)+strlen(minor)+1;
830 
831  *sep=0; /* zero terminate type string */
832 
833  ptr=sep+1;
834  }
835  else if(curl_strnequal("filename=", ptr, 9)) {
836  filename = &ptr[9];
837  ptr=strchr(filename, FORM_TYPE_SEPARATOR);
838  if(!ptr) {
839  ptr=strchr(filename, FORM_FILE_SEPARATOR);
840  }
841  if(ptr) {
842  *ptr=0; /* zero terminate */
843  ptr++;
844  }
845  }
846  else
847  /* confusion, bail out of loop */
848  break;
849  }
850  /* find the following comma */
851  if(ptr)
852  sep=strchr(ptr, FORM_FILE_SEPARATOR);
853  else
854  sep=NULL;
855  }
856  else {
857  sep=strchr(contp, FORM_FILE_SEPARATOR);
858  }
859  if(sep) {
860  /* the next file name starts here */
861  *sep =0;
862  sep++;
863  }
864  /* if type == NULL curl_formadd takes care of the problem */
865 
866  if (!AddMultiFiles (contp, type, filename, &multi_start,
867  &multi_current)) {
868  fprintf(stderr, "Error building form post!\n");
869  free(contents);
870  FreeMultiInfo (multi_start);
871  return 3;
872  }
873  contp = sep; /* move the contents pointer to after the separator */
874 
875  } while(sep && *sep); /* loop if there's another file name */
876 
877  /* now we add the multiple files section */
878  if (multi_start) {
879  struct curl_forms *forms = NULL;
880  struct multi_files *ptr = multi_start;
881  unsigned int i, count = 0;
882  while (ptr) {
883  ptr = ptr->next;
884  ++count;
885  }
886  forms =
887  (struct curl_forms *)malloc((count+1)*sizeof(struct curl_forms));
888  if (!forms)
889  {
890  fprintf(stderr, "Error building form post!\n");
891  free(contents);
892  FreeMultiInfo (multi_start);
893  return 4;
894  }
895  for (i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
896  {
897  forms[i].option = ptr->form.option;
898  forms[i].value = ptr->form.value;
899  }
900  forms[count].option = CURLFORM_END;
901  FreeMultiInfo (multi_start);
902  if (curl_formadd (httppost, last_post,
903  CURLFORM_COPYNAME, name,
904  CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
905  fprintf(stderr, "curl_formadd failed!\n");
906  free(forms);
907  free(contents);
908  return 5;
909  }
910  free(forms);
911  }
912  }
913  else {
914  if( contp[0]=='<' ) {
915  if (curl_formadd (httppost, last_post,
916  CURLFORM_COPYNAME, name,
917  CURLFORM_FILECONTENT, contp+1, CURLFORM_END) != 0) {
918  fprintf(stderr, "curl_formadd failed!\n");
919  free(contents);
920  return 6;
921  }
922  }
923  else {
924  if (curl_formadd (httppost, last_post,
925  CURLFORM_COPYNAME, name,
926  CURLFORM_COPYCONTENTS, contp, CURLFORM_END) != 0) {
927  fprintf(stderr, "curl_formadd failed!\n");
928  free(contents);
929  return 7;
930  }
931  }
932  }
933 
934  }
935  else {
936  fprintf(stderr, "Illegally formatted input field!\n");
937  free(contents);
938  return 1;
939  }
940  free(contents);
941  return 0;
942 }
943 
944 
945 typedef enum {
957 
958 static const char *param2text(int res)
959 {
960  ParameterError error = (ParameterError)res;
961  switch(error) {
963  return "had unsupported trailing garbage";
965  return "is unknown";
967  return "is ambiguous";
969  return "requires parameter";
970  case PARAM_BAD_USE:
971  return "is badly used here";
972  case PARAM_BAD_NUMERIC:
973  return "expected a proper numerical parameter";
975  return "the installed libcurl version doesn't support this";
976  default:
977  return "unknown error";
978  }
979 }
980 
981 static void cleanarg(char *str)
982 {
983 #ifdef HAVE_WRITABLE_ARGV
984  /* now that GetStr has copied the contents of nextarg, wipe the next
985  * argument out so that the username:password isn't displayed in the
986  * system process list */
987  if (str) {
988  size_t len = strlen(str);
989  memset(str, ' ', len);
990  }
991 #else
992  (void)str;
993 #endif
994 }
995 
996 /*
997  * Parse the string and write the integer in the given address. Return
998  * non-zero on failure, zero on success.
999  *
1000  * The string must start with a digit to be valid.
1001  */
1002 
1003 static int str2num(long *val, char *str)
1004 {
1005  int retcode = 0;
1006  if(isdigit((int)*str))
1007  *val = atoi(str);
1008  else
1009  retcode = 1; /* badness */
1010  return retcode;
1011 }
1012 
1021 static int str2offset(curl_off_t *val, char *str)
1022 {
1023 #if SIZEOF_CURL_OFF_T > 4
1024  /* Ugly, but without going through a bunch of rigmarole, we don't have the
1025  * definitions for LLONG_{MIN,MAX} or LONG_LONG_{MIN,MAX}.
1026  */
1027 #ifndef LLONG_MAX
1028 #ifdef _MSC_VER
1029 #define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFi64
1030 #define LLONG_MIN (curl_off_t)0x8000000000000000i64
1031 #else
1032 #define LLONG_MAX (curl_off_t)0x7FFFFFFFFFFFFFFFLL
1033 #define LLONG_MIN (curl_off_t)0x8000000000000000LL
1034 #endif
1035 #endif
1036 
1037  /* this is a duplicate of the function that is also used in libcurl */
1038  *val = strtoofft(str, NULL, 0);
1039 
1040  if ((*val == LLONG_MAX || *val == LLONG_MIN) && errno == ERANGE)
1041  return 1;
1042 #else
1043  *val = strtol(str, NULL, 0);
1044  if ((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE)
1045  return 1;
1046 #endif
1047  return 0;
1048 }
1049 
1050 static void checkpasswd(const char *kind, /* for what purpose */
1051  char **userpwd) /* pointer to allocated string */
1052 {
1053  char *ptr = strchr(*userpwd, ':');
1054  if(!ptr) {
1055  /* no password present, prompt for one */
1056  char passwd[256]="";
1057  char prompt[256];
1058  size_t passwdlen;
1059  size_t userlen = strlen(*userpwd);
1060  char *passptr;
1061 
1062  /* build a nice-looking prompt */
1063  curl_msnprintf(prompt, sizeof(prompt),
1064  "Enter %s password for user '%s':",
1065  kind, *userpwd);
1066 
1067  /* get password */
1068  getpass_r(prompt, passwd, sizeof(passwd));
1069  passwdlen = strlen(passwd);
1070 
1071  /* extend the allocated memory area to fit the password too */
1072  passptr = realloc(*userpwd,
1073  passwdlen + 1 + /* an extra for the colon */
1074  userlen + 1); /* an extra for the zero */
1075 
1076  if(passptr) {
1077  /* append the password separated with a colon */
1078  passptr[userlen]=':';
1079  memcpy(&passptr[userlen+1], passwd, passwdlen+1);
1080  *userpwd = passptr;
1081  }
1082  }
1083 }
1084 
1085 static ParameterError getparameter(char *flag, /* f or -long-flag */
1086  char *nextarg, /* NULL if unset */
1087  bool *usedarg, /* set to TRUE if the arg
1088  has been used */
1089  struct Configurable *config)
1090 {
1091  char letter;
1092  char subletter=0; /* subletters can only occur on long options */
1093 
1094  const char *parse=NULL;
1095  unsigned int j;
1096  time_t now;
1097  int hit=-1;
1098  bool longopt=FALSE;
1099  bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
1100 
1101 
1102  /* single-letter,
1103  long-name,
1104  boolean whether it takes an additional argument
1105  */
1106  struct LongShort aliases[]= {
1107  /* all these ones, starting with "*" or "$" as a short-option have *no*
1108  short option to mention. */
1109  {"*", "url", TRUE},
1110  {"*a", "random-file", TRUE},
1111  {"*b", "egd-file", TRUE},
1112  {"*c", "connect-timeout", TRUE},
1113  {"*d", "ciphers", TRUE},
1114  {"*e", "disable-epsv", FALSE},
1115 #ifdef USE_ENVIRONMENT
1116  {"*f", "environment", FALSE},
1117 #endif
1118  {"*g", "trace", TRUE},
1119  {"*h", "trace-ascii", TRUE},
1120  {"*i", "limit-rate", TRUE},
1121  {"*j", "compressed", FALSE}, /* might take an arg someday */
1122  {"*k", "digest", FALSE},
1123  {"*l", "negotiate", FALSE},
1124  {"*m", "ntlm", FALSE},
1125  {"*n", "basic", FALSE},
1126  {"*o", "anyauth", FALSE},
1127 #ifdef __DJGPP__
1128  {"*p", "wdebug", FALSE},
1129 #endif
1130  {"*q", "ftp-create-dirs", FALSE},
1131  {"*r", "create-dirs", FALSE},
1132  {"*s", "max-redirs", TRUE},
1133  {"*t", "proxy-ntlm", FALSE},
1134  {"*u", "crlf", FALSE},
1135  {"*v", "stderr", TRUE},
1136  {"*w", "interface", TRUE},
1137  {"*x", "krb4", TRUE},
1138  {"*y", "max-filesize", TRUE},
1139  {"*z", "disable-eprt", FALSE},
1140  {"$a", "ftp-ssl", FALSE},
1141  {"$b", "ftp-pasv", FALSE},
1142  {"$c", "socks5", TRUE},
1143  {"0", "http1.0", FALSE},
1144  {"1", "tlsv1", FALSE},
1145  {"2", "sslv2", FALSE},
1146  {"3", "sslv3", FALSE},
1147  {"4", "ipv4", FALSE},
1148  {"6", "ipv6", FALSE},
1149  {"a", "append", FALSE},
1150  {"A", "user-agent", TRUE},
1151  {"b", "cookie", TRUE},
1152  {"B", "use-ascii", FALSE},
1153  {"c", "cookie-jar", TRUE},
1154  {"C", "continue-at", TRUE},
1155  {"d", "data", TRUE},
1156  {"da", "data-ascii", TRUE},
1157  {"db", "data-binary", TRUE},
1158  {"D", "dump-header", TRUE},
1159  {"e", "referer", TRUE},
1160  {"E", "cert", TRUE},
1161  {"Ea", "cacert", TRUE},
1162  {"Eb","cert-type", TRUE},
1163  {"Ec","key", TRUE},
1164  {"Ed","key-type", TRUE},
1165  {"Ee","pass", TRUE},
1166  {"Ef","engine", TRUE},
1167  {"Eg","capath ", TRUE},
1168  {"f", "fail", FALSE},
1169  {"F", "form", TRUE},
1170  {"g", "globoff", FALSE},
1171  {"G", "get", FALSE},
1172  {"h", "help", FALSE},
1173  {"H", "header", TRUE},
1174  {"i", "include", FALSE},
1175  {"I", "head", FALSE},
1176  {"j", "junk-session-cookies", FALSE},
1177  {"k", "insecure", FALSE},
1178  {"K", "config", TRUE},
1179  {"l", "list-only", FALSE},
1180  {"L", "location", FALSE},
1181  {"Lt", "location-trusted", FALSE},
1182  {"m", "max-time", TRUE},
1183  {"M", "manual", FALSE},
1184  {"n", "netrc", FALSE},
1185  {"no", "netrc-optional", FALSE},
1186  {"N", "no-buffer", FALSE},
1187  {"o", "output", TRUE},
1188  {"O", "remote-name", FALSE},
1189  {"p", "proxytunnel", FALSE},
1190  {"P", "ftpport", TRUE}, /* older version */
1191  {"P", "ftp-port", TRUE},
1192  {"q", "disable", FALSE},
1193  {"Q", "quote", TRUE},
1194  {"r", "range", TRUE},
1195  {"R", "remote-time", FALSE},
1196  {"s", "silent", FALSE},
1197  {"S", "show-error", FALSE},
1198  {"t", "telnet-options", TRUE},
1199  {"T", "upload-file", TRUE},
1200  {"u", "user", TRUE},
1201  {"U", "proxy-user", TRUE},
1202  {"v", "verbose", FALSE},
1203  {"V", "version", FALSE},
1204  {"w", "write-out", TRUE},
1205  {"x", "proxy", TRUE},
1206  {"X", "request", TRUE},
1207  {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
1208  {"Y", "speed-limit", TRUE},
1209  {"y", "speed-time", TRUE},
1210  {"z", "time-cond", TRUE},
1211  {"#", "progress-bar",FALSE},
1212  };
1213 
1214  if(('-' != flag[0]) ||
1215  (('-' == flag[0]) && ('-' == flag[1]))) {
1216  /* this should be a long name */
1217  char *word=('-' == flag[0])?flag+2:flag;
1218  size_t fnam=strlen(word);
1219  int numhits=0;
1220  for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1221  if(curl_strnequal(aliases[j].lname, word, fnam)) {
1222  longopt = TRUE;
1223  numhits++;
1224  if(curl_strequal(aliases[j].lname, word)) {
1225  parse = aliases[j].letter;
1226  hit = j;
1227  numhits = 1; /* a single unique hit */
1228  break;
1229  }
1230  parse = aliases[j].letter;
1231  hit = j;
1232  }
1233  }
1234  if(numhits>1) {
1235  /* this is at least the second match! */
1236  return PARAM_OPTION_AMBIGUOUS;
1237  }
1238  if(hit < 0) {
1239  return PARAM_OPTION_UNKNOWN;
1240  }
1241  }
1242  else {
1243  flag++; /* prefixed with one dash, pass it */
1244  hit=-1;
1245  parse = flag;
1246  }
1247 
1248  do {
1249  /* we can loop here if we have multiple single-letters */
1250 
1251  if(!longopt)
1252  letter = parse?(char)*parse:'\0';
1253  else {
1254  letter = parse[0];
1255  subletter = parse[1];
1256  }
1257  *usedarg = FALSE; /* default is that we don't use the arg */
1258 
1259 #if 0
1260  fprintf(stderr, "OPTION: %c %s\n", letter, nextarg?nextarg:"<null>");
1261 #endif
1262  if(hit < 0) {
1263  for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
1264  if(letter == aliases[j].letter[0]) {
1265  hit = j;
1266  break;
1267  }
1268  }
1269  if(hit < 0) {
1270  return PARAM_OPTION_UNKNOWN;
1271  }
1272  }
1273  if(hit < 0) {
1274  return PARAM_OPTION_UNKNOWN;
1275  }
1276  if(!longopt && aliases[hit].extraparam && parse[1]) {
1277  nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
1278  singleopt=TRUE; /* don't loop anymore after this */
1279  }
1280  else if(!nextarg && aliases[hit].extraparam) {
1281  return PARAM_REQUIRES_PARAMETER;
1282  }
1283  else if(nextarg && aliases[hit].extraparam)
1284  *usedarg = TRUE; /* mark it as used */
1285 
1286  switch(letter) {
1287  case '*': /* options without a short option */
1288  switch(subletter) {
1289  case 'a': /* random-file */
1290  GetStr(&config->random_file, nextarg);
1291  break;
1292  case 'b': /* egd-file */
1293  GetStr(&config->egd_file, nextarg);
1294  break;
1295  case 'c': /* connect-timeout */
1296  if(str2num(&config->connecttimeout, nextarg))
1297  return PARAM_BAD_NUMERIC;
1298  break;
1299  case 'd': /* ciphers */
1300  GetStr(&config->cipher_list, nextarg);
1301  break;
1302  case 'e': /* --disable-epsv */
1303  config->disable_epsv ^= TRUE;
1304  break;
1305 #ifdef USE_ENVIRONMENT
1306  case 'f':
1307  config->writeenv ^= TRUE;
1308  break;
1309 #endif
1310  case 'g': /* --trace */
1311  GetStr(&config->trace_dump, nextarg);
1312  break;
1313  case 'h': /* --trace-ascii */
1314  GetStr(&config->trace_dump, nextarg);
1315  config->trace_ascii = TRUE;
1316  break;
1317  case 'i': /* --limit-rate */
1318  {
1319  /* We support G, M, K too */
1320  char *unit;
1321  unsigned long value = strtol(nextarg, &unit, 0);
1322  switch(nextarg[strlen(nextarg)-1]) {
1323  case 'G':
1324  case 'g':
1325  value *= 1024*1024*1024;
1326  break;
1327  case 'M':
1328  case 'm':
1329  value *= 1024*1024;
1330  break;
1331  case 'K':
1332  case 'k':
1333  value *= 1024;
1334  break;
1335  }
1336  config->recvpersecond = value;
1337  config->sendpersecond = value;
1338  }
1339  break;
1340 
1341  case 'j': /* --compressed */
1342  config->encoding ^= TRUE;
1343  break;
1344 
1345  case 'k': /* --digest */
1346  config->authtype = CURLAUTH_DIGEST;
1347  break;
1348 
1349  case 'l': /* --negotiate */
1350  if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
1351  config->authtype = CURLAUTH_GSSNEGOTIATE;
1352  else
1354  break;
1355 
1356  case 'm': /* --ntlm */
1357  if(curlinfo->features & CURL_VERSION_NTLM)
1358  config->authtype = CURLAUTH_NTLM;
1359  else
1361  break;
1362 
1363  case 'n': /* --basic for completeness */
1364  config->authtype = CURLAUTH_BASIC;
1365  break;
1366 
1367  case 'o': /* --anyauth, let libcurl pick it */
1368  config->authtype = CURLAUTH_ANY;
1369  break;
1370 
1371 #ifdef __DJGPP__
1372  case 'p': /* --wdebug */
1373  dbug_init();
1374  break;
1375 #endif
1376  case 'q': /* --ftp-create-dirs */
1377  config->ftp_create_dirs ^= TRUE;
1378  break;
1379 
1380  case 'r': /* --create-dirs */
1381  config->create_dirs = TRUE;
1382  break;
1383 
1384  case 's': /* --max-redirs */
1385  /* specified max no of redirects (http(s)) */
1386  if(str2num(&config->maxredirs, nextarg))
1387  return PARAM_BAD_NUMERIC;
1388  break;
1389 
1390  case 't': /* --proxy-ntlm */
1391  config->proxyntlm ^= TRUE;
1392  break;
1393 
1394  case 'u': /* --crlf */
1395  /* LF -> CRLF conversinon? */
1396  config->crlf = TRUE;
1397  break;
1398 
1399  case 'v': /* --stderr */
1400  if(strcmp(nextarg, "-")) {
1401  config->errors = fopen(nextarg, "wt");
1402  config->errors_fopened = TRUE;
1403  }
1404  else
1405  config->errors = stdout;
1406  break;
1407  case 'w': /* --interface */
1408  /* interface */
1409  GetStr(&config->iface, nextarg);
1410  break;
1411  case 'x': /* --krb4 */
1412  /* krb4 level string */
1413  if(curlinfo->features & CURL_VERSION_KERBEROS4)
1414  GetStr(&config->krb4level, nextarg);
1415  else
1417  break;
1418  case 'y': /* --max-filesize */
1419  if(str2offset(&config->max_filesize, nextarg))
1420  return PARAM_BAD_NUMERIC;
1421  break;
1422  case 'z': /* --disable-eprt */
1423  config->disable_eprt ^= TRUE;
1424  break;
1425 
1426  default: /* the URL! */
1427  {
1428  struct getout *url;
1429  if(config->url_get || (config->url_get=config->url_list)) {
1430  /* there's a node here, if it already is filled-in continue to find
1431  an "empty" node */
1432  while(config->url_get && (config->url_get->flags&GETOUT_URL))
1433  config->url_get = config->url_get->next;
1434  }
1435 
1436  /* now there might or might not be an available node to fill in! */
1437 
1438  if(config->url_get)
1439  /* existing node */
1440  url = config->url_get;
1441  else
1442  /* there was no free node, create one! */
1443  url=new_getout(config);
1444 
1445  if(url) {
1446  /* fill in the URL */
1447  GetStr(&url->url, nextarg);
1448  url->flags |= GETOUT_URL;
1449  }
1450  }
1451  }
1452  break;
1453  case '$': /* more options without a short option */
1454  switch(subletter) {
1455  case 'a': /* --ftp-ssl */
1456  config->ftp_ssl ^= TRUE;
1457  break;
1458  case 'b': /* --ftp-pasv */
1459  if(config->ftpport)
1460  free(config->ftpport);
1461  config->ftpport = NULL;
1462  break;
1463  case 'c': /* --socks specifies a socks5 proxy to use */
1464  GetStr(&config->socks5proxy, nextarg);
1465  break;
1466  }
1467  break;
1468  case '#': /* added 19990617 larsa */
1469  config->progressmode ^= CURL_PROGRESS_BAR;
1470  break;
1471  case '0':
1472  /* HTTP version 1.0 */
1474  break;
1475  case '1':
1476  /* TLS version 1 */
1478  break;
1479  case '2':
1480  /* SSL version 2 */
1482  break;
1483  case '3':
1484  /* SSL version 3 */
1486  break;
1487  case '4':
1488  /* IPv4 */
1489  config->ip_version = 4;
1490  break;
1491  case '6':
1492  /* IPv6 */
1493  config->ip_version = 6;
1494  break;
1495  case 'a':
1496  /* This makes the FTP sessions use APPE instead of STOR */
1497  config->conf ^= CONF_FTPAPPEND;
1498  break;
1499  case 'A':
1500  /* This specifies the User-Agent name */
1501  GetStr(&config->useragent, nextarg);
1502  break;
1503  case 'b': /* cookie string coming up: */
1504  if(nextarg[0] == '@') {
1505  nextarg++;
1506  }
1507  else if(strchr(nextarg, '=')) {
1508  /* A cookie string must have a =-letter */
1509  GetStr(&config->cookie, nextarg);
1510  break;
1511  }
1512  /* We have a cookie file to read from! */
1513  GetStr(&config->cookiefile, nextarg);
1514  break;
1515  case 'B':
1516  /* use ASCII/text when transfering */
1517  config->conf ^= CONF_GETTEXT;
1518  break;
1519  case 'c':
1520  /* get the file name to dump all cookies in */
1521  GetStr(&config->cookiejar, nextarg);
1522  break;
1523  case 'C':
1524  /* This makes us continue an ftp transfer at given position */
1525  if(!curl_strequal(nextarg, "-")) {
1526  if(str2offset(&config->resume_from, nextarg))
1527  return PARAM_BAD_NUMERIC;
1528  config->resume_from_current = FALSE;
1529  }
1530  else {
1531  config->resume_from_current = TRUE;
1532  config->resume_from = 0;
1533  }
1534  config->use_resume=TRUE;
1535  break;
1536  case 'd':
1537  /* postfield data */
1538  {
1539  char *postdata=NULL;
1540 
1541  if('@' == *nextarg) {
1542  /* the data begins with a '@' letter, it means that a file name
1543  or - (stdin) follows */
1544  FILE *file;
1545 
1546  nextarg++; /* pass the @ */
1547 
1548  if(curl_strequal("-", nextarg))
1549  file = stdin;
1550  else
1551  file = fopen(nextarg, "rb");
1552 
1553  if(subletter == 'b') /* forced binary */
1554  postdata = file2memory(file, &config->postfieldsize);
1555  else
1556  postdata = file2string(file);
1557  if(file && (file != stdin))
1558  fclose(file);
1559  }
1560  else {
1561  GetStr(&postdata, nextarg);
1562  }
1563 
1564  if(config->postfields) {
1565  /* we already have a string, we append this one
1566  with a separating &-letter */
1567  char *oldpost=config->postfields;
1568  config->postfields=aprintf("%s&%s", oldpost, postdata);
1569  free(oldpost);
1570  free(postdata);
1571  }
1572  else
1573  config->postfields=postdata;
1574  }
1575  /*
1576  We can't set the request type here, as this data might be used in
1577  a simple GET if -G is used. Already or soon.
1578 
1579  if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
1580  return PARAM_BAD_USE;
1581  */
1582  break;
1583  case 'D':
1584  /* dump-header to given file name */
1585  GetStr(&config->headerfile, nextarg);
1586  break;
1587  case 'e':
1588  {
1589  char *ptr = strstr(nextarg, ";auto");
1590  if(ptr) {
1591  /* Automatic referer requested, this may be combined with a
1592  set initial one */
1593  config->conf |= CONF_AUTO_REFERER;
1594  *ptr = 0; /* zero terminate here */
1595  }
1596  GetStr(&config->referer, nextarg);
1597  }
1598  break;
1599  case 'E':
1600  switch(subletter) {
1601  case 'a': /* CA info PEM file */
1602  /* CA info PEM file */
1603  GetStr(&config->cacert, nextarg);
1604  break;
1605  case 'b': /* cert file type */
1606  GetStr(&config->cert_type, nextarg);
1607  break;
1608  case 'c': /* private key file */
1609  GetStr(&config->key, nextarg);
1610  break;
1611  case 'd': /* private key file type */
1612  GetStr(&config->key_type, nextarg);
1613  break;
1614  case 'e': /* private key passphrase */
1615  GetStr(&config->key_passwd, nextarg);
1616  cleanarg(nextarg);
1617  break;
1618  case 'f': /* crypto engine */
1619  GetStr(&config->engine, nextarg);
1620  break;
1621  case 'g': /* CA info PEM file */
1622  /* CA cert directory */
1623  GetStr(&config->capath, nextarg);
1624  break;
1625  default: /* certificate file */
1626  {
1627  char *ptr = strchr(nextarg, ':');
1628  /* Since we live in a world of weirdness and confusion, the win32
1629  dudes can use : when using drive letters and thus
1630  c:\file:password needs to work. In order not to break
1631  compatibility, we still use : as separator, but we try to detect
1632  when it is used for a file name! On windows. */
1633 #ifdef WIN32
1634  if(ptr &&
1635  (ptr == &nextarg[1]) &&
1636  (nextarg[2] == '\\') &&
1637  (isalpha((int)nextarg[0])) )
1638  /* colon in the second column, followed by a backslash, and the
1639  first character is an alphabetic letter:
1640 
1641  this is a drive letter colon */
1642  ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
1643 #endif
1644  if(ptr) {
1645  /* we have a password too */
1646  *ptr=0;
1647  ptr++;
1648  GetStr(&config->key_passwd, ptr);
1649  }
1650  GetStr(&config->cert, nextarg);
1651  cleanarg(nextarg);
1652  }
1653  }
1654  break;
1655  case 'f':
1656  /* fail hard on errors */
1657  config->conf ^= CONF_FAILONERROR;
1658  break;
1659  case 'F':
1660  /* "form data" simulation, this is a little advanced so lets do our best
1661  to sort this out slowly and carefully */
1662  if(formparse(nextarg,
1663  &config->httppost,
1664  &config->last_post))
1665  return PARAM_BAD_USE;
1666  if(SetHTTPrequest(HTTPREQ_POST, &config->httpreq))
1667  return PARAM_BAD_USE;
1668  break;
1669 
1670  case 'g': /* g disables URLglobbing */
1671  config->globoff ^= TRUE;
1672  break;
1673 
1674  case 'G': /* HTTP GET */
1675  config->use_httpget = TRUE;
1676  break;
1677 
1678  case 'h': /* h for help */
1679  help();
1680  return PARAM_HELP_REQUESTED;
1681  case 'H':
1682  /* A custom header to append to a list */
1683  config->headers = curl_slist_append(config->headers, nextarg);
1684  break;
1685  case 'i':
1686  config->conf ^= CONF_HEADER; /* include the HTTP header as well */
1687  break;
1688  case 'j':
1689  config->cookiesession ^= TRUE;
1690  break;
1691  case 'I':
1692  /*
1693  * This is a bit tricky. We either SET both bits, or we clear both
1694  * bits. Let's not make any other outcomes from this.
1695  */
1696  if((CONF_HEADER|CONF_NOBODY) !=
1697  (config->conf&(CONF_HEADER|CONF_NOBODY)) ) {
1698  /* one of them weren't set, set both */
1699  config->conf |= (CONF_HEADER|CONF_NOBODY);
1700  if(SetHTTPrequest(HTTPREQ_HEAD, &config->httpreq))
1701  return PARAM_BAD_USE;
1702  }
1703  else {
1704  /* both were set, clear both */
1705  config->conf &= ~(CONF_HEADER|CONF_NOBODY);
1706  if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq))
1707  return PARAM_BAD_USE;
1708  }
1709  break;
1710  case 'k': /* allow insecure SSL connects */
1711  config->insecure_ok ^= TRUE;
1712  break;
1713  case 'K': /* parse config file */
1714  parseconfig(nextarg, config);
1715  break;
1716  case 'l':
1717  config->conf ^= CONF_FTPLISTONLY; /* only list the names of the FTP dir */
1718  break;
1719  case 'L':
1720  config->conf ^= CONF_FOLLOWLOCATION; /* Follow Location: HTTP headers */
1721  switch (subletter) {
1722  case 't':
1723  /* Continue to send authentication (user+password) when following
1724  * locations, even when hostname changed */
1725  config->conf ^= CONF_UNRESTRICTED_AUTH;
1726  break;
1727  }
1728  break;
1729  case 'm':
1730  /* specified max time */
1731  if(str2num(&config->timeout, nextarg))
1732  return PARAM_BAD_NUMERIC;
1733  break;
1734  case 'M': /* M for manual, huge help */
1735 #ifdef USE_MANUAL
1736  hugehelp();
1737  return PARAM_HELP_REQUESTED;
1738 #else
1739  fprintf(stderr,
1740  "curl: built-in manual was disabled at build-time!\n");
1741  return PARAM_OPTION_UNKNOWN;
1742 #endif
1743  case 'n':
1744  switch(subletter) {
1745  case 'o': /* CA info PEM file */
1746  /* use .netrc or URL */
1747  config->conf ^= CONF_NETRC_OPT;
1748  break;
1749  default:
1750  /* pick info from .netrc, if this is used for http, curl will
1751  automatically enfore user+password with the request */
1752  config->conf ^= CONF_NETRC;
1753  break;
1754  }
1755  break;
1756  case 'N':
1757  /* disable the output I/O buffering */
1758  config->nobuffer ^= 1;
1759  break;
1760  case 'o':
1761  case 'O':
1762  /* output file */
1763  {
1764  struct getout *url;
1765  if(config->url_out || (config->url_out=config->url_list)) {
1766  /* there's a node here, if it already is filled-in continue to find
1767  an "empty" node */
1768  while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
1769  config->url_out = config->url_out->next;
1770  }
1771 
1772  /* now there might or might not be an available node to fill in! */
1773 
1774  if(config->url_out)
1775  /* existing node */
1776  url = config->url_out;
1777  else
1778  /* there was no free node, create one! */
1779  url=new_getout(config);
1780 
1781  if(url) {
1782  /* fill in the outfile */
1783  if('o' == letter)
1784  GetStr(&url->outfile, nextarg);
1785  else {
1786  url->outfile=NULL; /* leave it */
1787  url->flags |= GETOUT_USEREMOTE;
1788  }
1789  url->flags |= GETOUT_OUTFILE;
1790  }
1791  }
1792  break;
1793  case 'P':
1794  /* This makes the FTP sessions use PORT instead of PASV */
1795  /* use <eth0> or <192.168.10.10> style addresses. Anything except
1796  this will make us try to get the "default" address.
1797  NOTE: this is a changed behaviour since the released 4.1!
1798  */
1799  GetStr(&config->ftpport, nextarg);
1800  break;
1801  case 'p':
1802  /* proxy tunnel for non-http protocols */
1803  config->proxytunnel ^= TRUE;
1804  break;
1805 
1806  case 'q': /* if used first, already taken care of, we do it like
1807  this so we don't cause an error! */
1808  break;
1809  case 'Q':
1810  /* QUOTE command to send to FTP server */
1811  switch(nextarg[0]) {
1812  case '-':
1813  /* prefixed with a dash makes it a POST TRANSFER one */
1814  nextarg++;
1815  config->postquote = curl_slist_append(config->postquote, nextarg);
1816  break;
1817  case '+':
1818  /* prefixed with a plus makes it a just-before-transfer one */
1819  nextarg++;
1820  config->prequote = curl_slist_append(config->prequote, nextarg);
1821  break;
1822  default:
1823  config->quote = curl_slist_append(config->quote, nextarg);
1824  }
1825  break;
1826  case 'r':
1827  /* byte range requested */
1828  GetStr(&config->range, nextarg);
1829  break;
1830  case 'R':
1831  /* use remote file's time */
1832  config->remote_time ^= TRUE;
1833  break;
1834  case 's':
1835  /* don't show progress meter, don't show errors : */
1836  config->conf |= (CONF_MUTE|CONF_NOPROGRESS);
1837  config->showerror ^= TRUE; /* toggle off */
1838  break;
1839  case 'S':
1840  /* show errors */
1841  config->showerror ^= TRUE; /* toggle on if used with -s */
1842  break;
1843  case 't':
1844  /* Telnet options */
1845  config->telnet_options =
1846  curl_slist_append(config->telnet_options, nextarg);
1847  break;
1848  case 'T':
1849  /* we are uploading */
1850  {
1851  struct getout *url;
1852  if(config->url_out || (config->url_out=config->url_list)) {
1853  /* there's a node here, if it already is filled-in continue to find
1854  an "empty" node */
1855  while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
1856  config->url_out = config->url_out->next;
1857  }
1858 
1859  /* now there might or might not be an available node to fill in! */
1860 
1861  if(config->url_out)
1862  /* existing node */
1863  url = config->url_out;
1864  else
1865  /* there was no free node, create one! */
1866  url=new_getout(config);
1867 
1868  if(url) {
1869  url->flags |= GETOUT_UPLOAD; /* mark -T used */
1870  if(!*nextarg)
1871  url->flags |= GETOUT_NOUPLOAD;
1872  else {
1873  /* "-" equals stdin, but keep the string around for now */
1874  GetStr(&url->infile, nextarg);
1875  }
1876  }
1877  }
1878  break;
1879  case 'u':
1880  /* user:password */
1881  GetStr(&config->userpwd, nextarg);
1882  cleanarg(nextarg);
1883  checkpasswd("host", &config->userpwd);
1884  break;
1885  case 'U':
1886  /* Proxy user:password */
1887  GetStr(&config->proxyuserpwd, nextarg);
1888  cleanarg(nextarg);
1889  checkpasswd("proxy", &config->proxyuserpwd);
1890  break;
1891  case 'v':
1892  config->conf ^= CONF_VERBOSE; /* talk a lot */
1893  break;
1894  case 'V':
1895  {
1896  const char **proto;
1897 
1898  printf(CURL_ID "%s\n", curl_version());
1899  if (curlinfo->protocols) {
1900  printf("Protocols: ");
1901  for (proto=curlinfo->protocols; *proto; ++proto) {
1902  printf("%s ", *proto);
1903  }
1904  puts(""); /* newline */
1905  }
1906  if(curlinfo->features) {
1907  unsigned int i;
1908  struct feat {
1909  const char *name;
1910  int bitmask;
1911  };
1912  struct feat feats[] = {
1913  {"IPv6", CURL_VERSION_IPV6},
1914  {"krb4", CURL_VERSION_KERBEROS4},
1915  {"SSL", CURL_VERSION_SSL},
1916  {"libz", CURL_VERSION_LIBZ},
1917  {"NTLM", CURL_VERSION_NTLM},
1918  {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
1919  {"Debug", CURL_VERSION_DEBUG},
1920  {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
1921  {"SPNEGO", CURL_VERSION_SPNEGO},
1922  {"Largefile", CURL_VERSION_LARGEFILE}
1923  };
1924  printf("Features: ");
1925  for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
1926  if(curlinfo->features & feats[i].bitmask)
1927  printf("%s ", feats[i].name);
1928  }
1929  puts(""); /* newline */
1930  }
1931  }
1932  return PARAM_HELP_REQUESTED;
1933  case 'w':
1934  /* get the output string */
1935  if('@' == *nextarg) {
1936  /* the data begins with a '@' letter, it means that a file name
1937  or - (stdin) follows */
1938  FILE *file;
1939  nextarg++; /* pass the @ */
1940  if(curl_strequal("-", nextarg))
1941  file = stdin;
1942  else
1943  file = fopen(nextarg, "r");
1944  config->writeout = file2string(file);
1945  if(file && (file != stdin))
1946  fclose(file);
1947  }
1948  else
1949  GetStr(&config->writeout, nextarg);
1950  break;
1951  case 'x':
1952  /* proxy */
1953  GetStr(&config->proxy, nextarg);
1954  break;
1955  case 'X':
1956  /* set custom request */
1957  GetStr(&config->customrequest, nextarg);
1958  break;
1959  case 'y':
1960  /* low speed time */
1961  if(str2num(&config->low_speed_time, nextarg))
1962  return PARAM_BAD_NUMERIC;
1963  if(!config->low_speed_limit)
1964  config->low_speed_limit = 1;
1965  break;
1966  case 'Y':
1967  /* low speed limit */
1968  if(str2num(&config->low_speed_limit, nextarg))
1969  return PARAM_BAD_NUMERIC;
1970  if(!config->low_speed_time)
1971  config->low_speed_time=30;
1972  break;
1973  case 'z': /* time condition coming up */
1974  switch(*nextarg) {
1975  case '+':
1976  nextarg++;
1977  default:
1978  /* If-Modified-Since: (section 14.28 in RFC2068) */
1980  break;
1981  case '-':
1982  /* If-Unmodified-Since: (section 14.24 in RFC2068) */
1984  nextarg++;
1985  break;
1986  case '=':
1987  /* Last-Modified: (section 14.29 in RFC2068) */
1988  config->timecond = CURL_TIMECOND_LASTMOD;
1989  nextarg++;
1990  break;
1991  }
1992  now=time(NULL);
1993  config->condtime=curl_getdate(nextarg, &now);
1994  if(-1 == (int)config->condtime) {
1995  /* now let's see if it is a file name to get the time from instead! */
1996  struct stat statbuf;
1997  if(-1 == stat(nextarg, &statbuf)) {
1998  /* failed, remove time condition */
1999  config->timecond = CURL_TIMECOND_NONE;
2000  }
2001  else {
2002  /* pull the time out from the file */
2003  config->condtime = statbuf.st_mtime;
2004  }
2005  }
2006  break;
2007  default: /* unknown flag */
2008  return PARAM_OPTION_UNKNOWN;
2009  }
2010  hit = -1;
2011 
2012  } while(!longopt && !singleopt && *++parse && !*usedarg);
2013 
2014  return PARAM_OK;
2015 }
2016 
2017 
2018 static void parseconfig(const char *filename,
2019  struct Configurable *config)
2020 {
2021  int res;
2022  FILE *file;
2023  char filebuffer[512];
2024  bool usedarg;
2025  char *home;
2026 
2027  if(!filename || !*filename) {
2028  /* NULL or no file name attempts to load .curlrc from the homedir! */
2029 
2030 #define CURLRC DOT_CHAR "curlrc"
2031 
2032 #ifndef AMIGA
2033  filename = CURLRC; /* sensible default */
2034  home = homedir(); /* portable homedir finder */
2035  if(home) {
2036  if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
2037  snprintf(filebuffer, sizeof(filebuffer),
2038  "%s%s%s", home, DIR_CHAR, CURLRC);
2039 
2040  filename = filebuffer;
2041  }
2042  free(home); /* we've used it, now free it */
2043  }
2044 
2045 # else /* AmigaOS */
2046  /* On AmigaOS all the config files are into env:
2047  */
2048  filename = "ENV:" CURLRC;
2049 
2050 #endif
2051  }
2052 
2053  if(strcmp(filename,"-"))
2054  file = fopen(filename, "r");
2055  else
2056  file = stdin;
2057 
2058  if(file) {
2059  char *line;
2060  char *aline;
2061  char *option;
2062  char *param;
2063  int lineno=0;
2064  bool alloced_param;
2065 
2066 #define isseparator(x) (((x)=='=') || ((x) == ':'))
2067 
2068  while (NULL != (aline = my_get_line(file))) {
2069  lineno++;
2070  line = aline;
2071  alloced_param=FALSE;
2072 
2073  /* lines with # in the fist column is a comment! */
2074  while(*line && isspace((int)*line))
2075  line++;
2076 
2077  switch(*line) {
2078  case '#':
2079  case '/':
2080  case '\r':
2081  case '\n':
2082  case '*':
2083  case '\0':
2084  free(aline);
2085  continue;
2086  }
2087 
2088  /* the option keywords starts here */
2089  option = line;
2090  while(*line && !isspace((int)*line) && !isseparator(*line))
2091  line++;
2092  /* ... and has ended here */
2093 
2094  if(*line)
2095  *line++=0; /* zero terminate, we have a local copy of the data */
2096 
2097 #ifdef DEBUG_CONFIG
2098  fprintf(stderr, "GOT: %s\n", option);
2099 #endif
2100 
2101  /* pass spaces and separator(s) */
2102  while(*line && (isspace((int)*line) || isseparator(*line)))
2103  line++;
2104 
2105  /* the parameter starts here (unless quoted) */
2106  if(*line == '\"') {
2107  char *ptr;
2108  /* quoted parameter, do the qoute dance */
2109  line++;
2110  param=strdup(line); /* parameter */
2111  alloced_param=TRUE;
2112 
2113  ptr=param;
2114  while(*line && (*line != '\"')) {
2115  if(*line == '\\') {
2116  char out;
2117  line++;
2118 
2119  /* default is to output the letter after the backslah */
2120  switch(out = *line) {
2121  case '\0':
2122  continue; /* this'll break out of the loop */
2123  case 't':
2124  out='\t';
2125  break;
2126  case 'n':
2127  out='\n';
2128  break;
2129  case 'r':
2130  out='\r';
2131  break;
2132  case 'v':
2133  out='\v';
2134  break;
2135  }
2136  *ptr++=out;
2137  line++;
2138  }
2139  else
2140  *ptr++=*line++;
2141  }
2142  *ptr=0; /* always zero terminate */
2143 
2144  }
2145  else {
2146  param=line; /* parameter starts here */
2147  while(*line && !isspace((int)*line))
2148  line++;
2149  *line=0; /* zero terminate */
2150  }
2151 
2152  if (param && !*param) {
2153  /* do this so getparameter can check for required parameters.
2154  Otherwise it always thinks there's a parameter. */
2155  if (alloced_param)
2156  free(param);
2157  param = NULL;
2158  }
2159 
2160 #ifdef DEBUG_CONFIG
2161  fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
2162 #endif
2163  res = getparameter(option, param, &usedarg, config);
2164 
2165  if (param && *param && !usedarg)
2166  /* we passed in a parameter that wasn't used! */
2168 
2169  if(res != PARAM_OK) {
2170  /* the help request isn't really an error */
2171  if(!strcmp(filename, "-")) {
2172  filename=(char *)"<stdin>";
2173  }
2174  if(PARAM_HELP_REQUESTED != res) {
2175  const char *reason = param2text(res);
2176  fprintf(stderr, "%s:%d: warning: '%s' %s\n",
2177  filename, lineno, option, reason);
2178  }
2179  }
2180 
2181  if(alloced_param)
2182  {
2183  free(param);
2184  param = NULL;
2185  }
2186 
2187  free(aline);
2188  }
2189  if(file != stdin)
2190  fclose(file);
2191  }
2192 }
2193 
2194 static void go_sleep(long ms)
2195 {
2196 #ifdef HAVE_POLL
2197  /* portable subsecond "sleep" */
2198  poll((void *)0, 0, ms);
2199 #else
2200  /* systems without poll() need other solutions */
2201 
2202 #ifdef WIN32
2203  /* Windows offers a millisecond sleep */
2204  Sleep(ms);
2205 #else
2206  /* Other systems must use select() for this */
2207  struct timeval timeout;
2208 
2209  timeout.tv_sec = 0;
2210  timeout.tv_usec = ms * 1000;
2211 
2212  select(0, NULL, NULL, NULL, &timeout);
2213 #endif
2214 
2215 #endif
2216 }
2217 
2218 struct OutStruct {
2219  char *filename;
2220  FILE *stream;
2222 };
2223 
2224 static int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
2225 {
2226  int rc;
2227  struct OutStruct *out=(struct OutStruct *)stream;
2228  struct Configurable *config = out->config;
2229  if(out && !out->stream) {
2230  /* open file for writing */
2231  out->stream=fopen(out->filename, "wb");
2232  if(!out->stream)
2233  return -1; /* failure */
2234  }
2235 
2236  if(config->recvpersecond) {
2237  /*
2238  * We know when we received data the previous time. We know how much data
2239  * we get now. Make sure that this is not faster than we are told to run.
2240  * If we're faster, sleep a while *before* doing the fwrite() here.
2241  */
2242 
2243  time_t timediff;
2244  time_t now;
2245  time_t sleep_time;
2246 
2247  now = time(NULL);
2248  timediff = now - config->lastrecvtime;
2249  if( size*nmemb > config->recvpersecond*timediff) {
2250  /* figure out how many milliseconds to rest */
2251  sleep_time = (size*nmemb)*1000/config->recvpersecond - timediff*1000;
2252 
2253  /*
2254  * Make sure we don't sleep for so long that we trigger the speed limit.
2255  * This won't limit the bandwidth quite the way we've been asked to, but
2256  * at least the transfer has a chance.
2257  */
2258  if (config->low_speed_time > 0)
2259  sleep_time = MIN(sleep_time,(config->low_speed_time * 1000) / 2);
2260 
2261  go_sleep (sleep_time);
2262  now = time(NULL);
2263  }
2264  config->lastrecvtime = now;
2265  }
2266 
2267  rc = fwrite(buffer, size, nmemb, out->stream);
2268 
2269  if(config->nobuffer)
2270  /* disable output buffering */
2271  fflush(out->stream);
2272 
2273  return rc;
2274 }
2275 
2276 struct InStruct {
2277  FILE *stream;
2279 };
2280 
2281 static int my_fread(void *buffer, size_t size, size_t nmemb, void *userp)
2282 {
2283  struct InStruct *in=(struct InStruct *)userp;
2284 
2285  struct Configurable *config = in->config;
2286 
2287  if(config->sendpersecond) {
2288  /*
2289  * We know when we sent data the previous time. We know how much data
2290  * we sent. Make sure that this was not faster than we are told to run.
2291  * If we're faster, sleep a while *before* doing the fread() here.
2292  * Also, make no larger fread() than should be sent this second!
2293  */
2294 
2295  time_t timediff;
2296  time_t now;
2297 
2298  now = time(NULL);
2299  timediff = now - config->lastsendtime;
2300  if( config->lastsendsize > config->sendpersecond*timediff) {
2301  /* figure out how many milliseconds to rest */
2302  go_sleep ( config->lastsendsize*1000/config->sendpersecond -
2303  timediff*1000 );
2304  now = time(NULL);
2305  }
2306  config->lastsendtime = now;
2307 
2308  if(size*nmemb > config->sendpersecond) {
2309  /* lower the size to actually read */
2310  nmemb = config->sendpersecond;
2311  size = 1;
2312  }
2313  config->lastsendsize = size*nmemb;
2314  }
2315 
2316 
2317  return fread(buffer, size, nmemb, in->stream);
2318 }
2319 
2321  int calls;
2322  double prev;
2323  int width;
2324  FILE *out; /* where to write everything to */
2326 };
2327 
2328 static int myprogress (void *clientp,
2329  double dltotal,
2330  double dlnow,
2331  double ultotal,
2332  double ulnow)
2333 {
2334  /* The original progress-bar source code was written for curl by Lars Aas,
2335  and this new edition inherits some of his concepts. */
2336 
2337  char line[256];
2338  char outline[256];
2339  char format[40];
2340  double frac;
2341  double percent;
2342  int barwidth;
2343  int num;
2344  int i;
2345 
2346  struct ProgressData *bar = (struct ProgressData *)clientp;
2347  double total = dltotal + ultotal + bar->initial_size;
2348  double point = dlnow + ulnow + bar->initial_size; /* we've come this far */
2349 
2350  bar->calls++; /* simply count invokes */
2351 
2352  if(total < 1) {
2353  int prevblock = (int)bar->prev / 1024;
2354  int thisblock = (int)point / 1024;
2355  while ( thisblock > prevblock ) {
2356  fprintf( bar->out, "#" );
2357  prevblock++;
2358  }
2359  }
2360  else {
2361  frac = point / total;
2362  percent = frac * 100.0f;
2363  barwidth = bar->width - 7;
2364  num = (int) (((double)barwidth) * frac);
2365  i = 0;
2366  for ( i = 0; i < num; i++ ) {
2367  line[i] = '#';
2368  }
2369  line[i] = '\0';
2370  sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
2371  sprintf( outline, format, line, percent );
2372  fprintf( bar->out, "\r%s", outline );
2373  }
2374  fflush(bar->out);
2375  bar->prev = point;
2376 
2377  return 0;
2378 }
2379 
2380 static
2381 void progressbarinit(struct ProgressData *bar,
2382  struct Configurable *config)
2383 {
2384 #ifdef __EMX__
2385  /* 20000318 mgs */
2386  int scr_size [2];
2387 #endif
2388  char *colp;
2389 
2390  memset(bar, 0, sizeof(struct ProgressData));
2391 
2392  /* pass this through to progress function so
2393  * it can display progress towards total file
2394  * not just the part that's left. (21-may-03, dbyron) */
2395  if (config->use_resume)
2396  bar->initial_size = config->resume_from;
2397 
2398 /* TODO: get terminal width through ansi escapes or something similar.
2399  try to update width when xterm is resized... - 19990617 larsa */
2400 #ifndef __EMX__
2401  /* 20000318 mgs
2402  * OS/2 users most likely won't have this env var set, and besides that
2403  * we're using our own way to determine screen width */
2404  colp = curl_getenv("COLUMNS");
2405  if (colp != NULL) {
2406  bar->width = atoi(colp);
2407  curl_free(colp);
2408  }
2409  else
2410  bar->width = 79;
2411 #else
2412  /* 20000318 mgs
2413  * We use this emx library call to get the screen width, and subtract
2414  * one from what we got in order to avoid a problem with the cursor
2415  * advancing to the next line if we print a string that is as long as
2416  * the screen is wide. */
2417 
2418  _scrsize(scr_size);
2419  bar->width = scr_size[0] - 1;
2420 #endif
2421 
2422  bar->out = config->errors;
2423 }
2424 
2425 static
2426 void dump(const char *text,
2427  FILE *stream, unsigned char *ptr, size_t size,
2428  bool nohex)
2429 {
2430  size_t i;
2431  size_t c;
2432 
2433  unsigned int width=0x10;
2434 
2435  if(nohex)
2436  /* without the hex output, we can fit more on screen */
2437  width = 0x40;
2438 
2439  fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size);
2440 
2441  for(i=0; i<size; i+= width) {
2442 
2443  fprintf(stream, "%04zx: ", i);
2444 
2445  if(!nohex) {
2446  /* hex not disabled, show it */
2447  for(c = 0; c < width; c++)
2448  if(i+c < size)
2449  fprintf(stream, "%02x ", ptr[i+c]);
2450  else
2451  fputs(" ", stream);
2452  }
2453 
2454  for(c = 0; (c < width) && (i+c < size); c++) {
2455  /* check for 0D0A; if found, skip past and start a new line of output */
2456  if (nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
2457  i+=(c+2-width);
2458  break;
2459  }
2460  fprintf(stream, "%c",
2461  (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
2462  /* check again for 0D0A, to avoid an extra \n if it's at width */
2463  if (nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
2464  i+=(c+3-width);
2465  break;
2466  }
2467  }
2468  fputc('\n', stream); /* newline */
2469  }
2470  fflush(stream);
2471 }
2472 
2473 static
2474 int my_trace(CURL *handle, curl_infotype type,
2475  unsigned char *data, size_t size,
2476  void *userp)
2477 {
2478  struct Configurable *config = (struct Configurable *)userp;
2479  FILE *output=config->errors;
2480  const char *text;
2481 
2482  (void)handle; /* prevent compiler warning */
2483 
2484  if(!config->trace_stream) {
2485  /* open for append */
2486  if(curl_strequal("-", config->trace_dump))
2487  config->trace_stream = stdout;
2488  else {
2489  config->trace_stream = fopen(config->trace_dump, "w");
2490  config->trace_fopened = TRUE;
2491  }
2492  }
2493 
2494  if(config->trace_stream)
2495  output = config->trace_stream;
2496 
2497  switch (type) {
2498  case CURLINFO_TEXT:
2499  fprintf(output, "== Info: %s", data);
2500  default: /* in case a new one is introduced to shock us */
2501  return 0;
2502 
2503  case CURLINFO_HEADER_OUT:
2504  text = "=> Send header";
2505  break;
2506  case CURLINFO_DATA_OUT:
2507  text = "=> Send data";
2508  break;
2509  case CURLINFO_HEADER_IN:
2510  text = "<= Recv header";
2511  break;
2512  case CURLINFO_DATA_IN:
2513  text = "<= Recv data";
2514  break;
2515  }
2516 
2517  dump(text, output, data, size, config->trace_ascii);
2518  return 0;
2519 }
2520 
2521 static void free_config_fields(struct Configurable *config)
2522 {
2523  if(config->random_file)
2524  free(config->random_file);
2525  if(config->egd_file)
2526  free(config->egd_file);
2527  if(config->userpwd)
2528  free(config->userpwd);
2529  if(config->postfields)
2530  free(config->postfields);
2531  if(config->proxy)
2532  free(config->proxy);
2533  if(config->proxyuserpwd)
2534  free(config->proxyuserpwd);
2535  if(config->cookie)
2536  free(config->cookie);
2537  if(config->cookiefile)
2538  free(config->cookiefile);
2539  if(config->krb4level)
2540  free(config->krb4level);
2541  if(config->headerfile)
2542  free(config->headerfile);
2543  if(config->ftpport)
2544  free(config->ftpport);
2545  if(config->range)
2546  free(config->range);
2547  if(config->customrequest)
2548  free(config->customrequest);
2549  if(config->writeout)
2550  free(config->writeout);
2551  if(config->httppost)
2552  curl_formfree(config->httppost);
2553  if(config->cacert)
2554  free(config->cacert);
2555  if(config->capath)
2556  free(config->capath);
2557  if(config->cookiejar)
2558  free(config->cookiejar);
2559 
2560  curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
2561  curl_slist_free_all(config->postquote); /* */
2562  curl_slist_free_all(config->headers); /* */
2563 }
2564 
2565 #if defined(WIN32) && !defined(__CYGWIN32__)
2566 
2567 /* Function to find CACert bundle on a Win32 platform using SearchPath.
2568  * (SearchPath is defined in windows.h, which is #included into libcurl)
2569  * (Use the ASCII version instead of the unicode one!)
2570  * The order of the directories it searches is:
2571  * 1. application's directory
2572  * 2. current working directory
2573  * 3. Windows System directory (e.g. C:\windows\system32)
2574  * 4. Windows Directory (e.g. C:\windows)
2575  * 5. all directories along %PATH%
2576  */
2577 static void FindWin32CACert(struct Configurable *config,
2578  const char *bundle_file)
2579 {
2580  /* only check for cert file if "we" support SSL */
2581  if(curlinfo->features & CURL_VERSION_SSL) {
2582  DWORD buflen;
2583  char *ptr = NULL;
2584  char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
2585  if (!retval)
2586  return;
2587  retval[0] = '\0';
2588  buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
2589  if (buflen > 0) {
2590  GetStr(&config->cacert, retval);
2591  }
2592  free(retval);
2593  }
2594 }
2595 
2596 #endif
2597 
2598 static int
2599 operate(struct Configurable *config, int argc, char *argv[])
2600 {
2601  char errorbuffer[CURL_ERROR_SIZE];
2602  char useragent[128]; /* buah, we don't want a larger default user agent */
2603  struct ProgressData progressbar;
2604  struct getout *urlnode;
2605  struct getout *nextnode;
2606 
2607  struct OutStruct outs;
2608  struct OutStruct heads;
2609  struct InStruct input;
2610 
2611  char *url = NULL;
2612 
2613  URLGlob *urls=NULL;
2614  URLGlob *inglob=NULL;
2615  int urlnum;
2616  int infilenum;
2617  char *outfiles;
2618  char *infiles; /* might a glob pattern */
2619  char *uploadfile=NULL; /* a single file, never a glob */
2620 
2621  int separator = 0;
2622 
2623  FILE *infd = stdin;
2624  bool infdfopen;
2625  FILE *headerfilep = NULL;
2626  char *urlbuffer=NULL;
2627  curl_off_t uploadfilesize; /* -1 means unknown */
2628  bool stillflags=TRUE;
2629 
2630  bool allocuseragent=FALSE;
2631 
2632  char *httpgetfields=NULL;
2633 
2634  CURL *curl;
2635  int res = 0;
2636  int i;
2637  int up; /* upload file counter within a single upload glob */
2638 
2639  char *env;
2640 #ifdef CURLDEBUG
2641  /* this sends all memory debug messages to a logfile named memdump */
2642  env = curl_getenv("CURL_MEMDEBUG");
2643  if(env) {
2644  curl_free(env);
2645  curl_memdebug("memdump");
2646  }
2647  env = curl_getenv("CURL_MEMLIMIT");
2648  if(env) {
2649  curl_memlimit(atoi(env));
2650  curl_free(env);
2651  }
2652 #endif
2653 
2654  memset(&outs,0,sizeof(outs));
2655 
2656  /* we get libcurl info right away */
2657  curlinfo = curl_version_info(CURLVERSION_NOW);
2658 
2659  errorbuffer[0]=0; /* prevent junk from being output */
2660 
2661  /* inits */
2662  if (main_init() != CURLE_OK) {
2663  helpf("error initializing curl library\n");
2664  return CURLE_FAILED_INIT;
2665  }
2666  config->showerror=TRUE;
2667  config->conf=CONF_DEFAULT;
2668  config->use_httpget=FALSE;
2669  config->create_dirs=FALSE;
2670 
2671  if(argc>1 &&
2672  (!curl_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
2673  strchr(argv[1], 'q')) {
2674  /*
2675  * The first flag, that is not a verbose name, but a shortname
2676  * and it includes the 'q' flag!
2677  */
2678  ;
2679  }
2680  else {
2681  parseconfig(NULL, config);
2682  }
2683 
2684  if ((argc < 2) && !config->url_list) {
2685  helpf(NULL);
2686  return CURLE_FAILED_INIT;
2687  }
2688 
2689  /* Parse options */
2690  for (i = 1; i < argc; i++) {
2691  if(stillflags &&
2692  ('-' == argv[i][0])) {
2693  char *nextarg;
2694  bool passarg;
2695  char *origopt=argv[i];
2696 
2697  char *flag = argv[i];
2698 
2699  if(curl_strequal("--", argv[i]))
2700  /* this indicates the end of the flags and thus enables the
2701  following (URL) argument to start with -. */
2702  stillflags=FALSE;
2703  else {
2704  nextarg= (i < argc - 1)? argv[i+1]: NULL;
2705 
2706  res = getparameter(flag, nextarg, &passarg, config);
2707  if(res) {
2708  const char *reason = param2text(res);
2709  if(res != PARAM_HELP_REQUESTED)
2710  helpf("option %s: %s\n", origopt, reason);
2711  clean_getout(config);
2712  return CURLE_FAILED_INIT;
2713  }
2714 
2715  if(passarg) /* we're supposed to skip this */
2716  i++;
2717  }
2718  }
2719  else {
2720  bool used;
2721  /* just add the URL please */
2722  res = getparameter((char *)"--url", argv[i], &used, config);
2723  if(res)
2724  return res;
2725  }
2726  }
2727 
2728  if(!config->url_list || !config->url_list->url) {
2729  clean_getout(config);
2730  helpf("no URL specified!\n");
2731  return CURLE_FAILED_INIT;
2732  }
2733  if(NULL == config->useragent) {
2734  /* set non-zero default values: */
2735  snprintf(useragent, sizeof(useragent),
2736  CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
2737  config->useragent= useragent;
2738  }
2739  else
2740  allocuseragent = TRUE;
2741 
2742  /* On WIN32 (non-cygwin), we can't set the path to curl-ca-bundle.crt
2743  * at compile time. So we look here for the file in two ways:
2744  * 1: look at the environment variable CURL_CA_BUNDLE for a path
2745  * 2: if #1 isn't found, use the windows API function SearchPath()
2746  * to find it along the app's path (includes app's dir and CWD)
2747  *
2748  * We support the environment variable thing for non-Windows platforms
2749  * too. Just for the sake of it.
2750  */
2751  if (!config->cacert &&
2752  !config->capath &&
2753  !config->insecure_ok) {
2754  env = curl_getenv("CURL_CA_BUNDLE");
2755  if(env) {
2756  GetStr(&config->cacert, env);
2757  curl_free(env);
2758  }
2759 #if defined(WIN32) && !defined(__CYGWIN32__)
2760  else
2761  FindWin32CACert(config, "curl-ca-bundle.crt");
2762 #endif
2763  }
2764 
2765  if (config->postfields) {
2766  if (config->use_httpget) {
2767  /* Use the postfields data for a http get */
2768  httpgetfields = strdup(config->postfields);
2769  free(config->postfields);
2770  config->postfields = NULL;
2771  if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
2772  &config->httpreq)) {
2773  free(httpgetfields);
2774  return PARAM_BAD_USE;
2775  }
2776  }
2777  else {
2778  if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
2779  return PARAM_BAD_USE;
2780  }
2781  }
2782 
2783  /*
2784  * Get a curl handle to use for all forthcoming curl transfers. Cleanup
2785  * when all transfers are done.
2786  */
2787  curl = curl_easy_init();
2788  if(!curl) {
2789  clean_getout(config);
2790  return CURLE_FAILED_INIT;
2791  }
2792 
2793  /* After this point, we should call curl_easy_cleanup() if we decide to bail
2794  * out from this function! */
2795 
2796  urlnode = config->url_list;
2797 
2798  if(config->headerfile) {
2799  /* open file for output: */
2800  if(strcmp(config->headerfile,"-")) {
2801  heads.filename = config->headerfile;
2802  headerfilep=NULL;
2803  }
2804  else
2805  headerfilep=stdout;
2806  heads.stream = headerfilep;
2807  heads.config = config;
2808  }
2809 
2810  /* loop through the list of given URLs */
2811  while(urlnode && !res) {
2812  char *dourl;
2813 
2814  /* get the full URL (it might be NULL) */
2815  dourl=urlnode->url;
2816 
2817  url = dourl;
2818 
2819  if(NULL == url) {
2820  /* This node had no URL, skip it and continue to the next */
2821  if(urlnode->outfile)
2822  free(urlnode->outfile);
2823 
2824  /* move on to the next URL */
2825  nextnode=urlnode->next;
2826  free(urlnode); /* free the node */
2827  urlnode = nextnode;
2828  continue; /* next please */
2829  }
2830 
2831  /* default output stream is stdout */
2832  outs.stream = stdout;
2833  outs.config = config;
2834 
2835  /* save outfile pattern before expansion */
2836  outfiles = urlnode->outfile?strdup(urlnode->outfile):NULL;
2837 
2838  infiles = urlnode->infile;
2839 
2840  if(!config->globoff && infiles) {
2841  /* Unless explicitly shut off */
2842  res = glob_url(&inglob, infiles, &infilenum,
2843  config->showerror?
2844  (config->errors?config->errors:stderr):NULL);
2845  if(res != CURLE_OK) {
2846  clean_getout(config);
2847  break;
2848  }
2849  }
2850 
2851  /* Here's the loop for uploading multiple files within the same
2852  single globbed string. If no upload, we enter the loop once anyway. */
2853  for(up = 0;
2854  (!up && !infiles) ||
2855  (uploadfile = inglob?
2856  glob_next_url(inglob):
2857  (!up?strdup(infiles):NULL));
2858  up++) {
2859  uploadfilesize=-1;
2860 
2861  if(!config->globoff) {
2862  /* Unless explicitly shut off, we expand '{...}' and '[...]'
2863  expressions and return total number of URLs in pattern set */
2864  res = glob_url(&urls, dourl, &urlnum,
2865  config->showerror?
2866  (config->errors?config->errors:stderr):NULL);
2867  if(res != CURLE_OK) {
2868  break;
2869  }
2870  }
2871  else
2872  urlnum = 1; /* without globbing, this is a single URL */
2873 
2874  /* if multiple files extracted to stdout, insert separators! */
2875  separator= ((!outfiles || curl_strequal(outfiles, "-")) && urlnum > 1);
2876 
2877  /* Here's looping around each globbed URL */
2878  for(i = 0;
2879  (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
2880  i++) {
2881  char *outfile;
2882  outfile = outfiles?strdup(outfiles):NULL;
2883 
2884  if((urlnode->flags&GETOUT_USEREMOTE) ||
2885  (outfile && !curl_strequal("-", outfile)) ) {
2886 
2887  /*
2888  * We have specified a file name to store the result in, or we have
2889  * decided we want to use the remote file name.
2890  */
2891 
2892  if(!outfile) {
2893  /* Find and get the remote file name */
2894  char * pc =strstr(url, "://");
2895  if(pc)
2896  pc+=3;
2897  else
2898  pc=url;
2899  pc = strrchr(pc, '/');
2900 
2901  if(pc) {
2902  /* duplicate the string beyond the slash */
2903  pc++;
2904  outfile = *pc ? strdup(pc): NULL;
2905  }
2906  if(!outfile || !*outfile) {
2907  helpf("Remote file name has no length!\n");
2908  res = CURLE_WRITE_ERROR;
2909  free(url);
2910  break;
2911  }
2912 #if defined(__DJGPP__)
2913  {
2914  /* This is for DOS, and then we do some major replacing of
2915  bad characters in the file name before using it */
2916  char *file1=xmalloc(PATH_MAX);
2917  strcpy(file1, msdosify(outfile));
2918  strcpy(outfile, rename_if_dos_device_name(file1));
2919  xfree(file1);
2920  }
2921 #endif /* __DJGPP__ */
2922  }
2923  else if(urls) {
2924  /* fill '#1' ... '#9' terms from URL pattern */
2925  char *storefile = outfile;
2926  outfile = glob_match_url(storefile, urls);
2927  free(storefile);
2928  if(!outfile) {
2929  /* bad globbing */
2930  fprintf(stderr, "bad output glob!\n");
2931  free(url);
2932  res = CURLE_FAILED_INIT;
2933  break;
2934  }
2935  }
2936 
2937  /* Create the directory hierarchy, if not pre-existant to a multiple
2938  file output call */
2939 
2940  if(config->create_dirs)
2941  if (-1 == create_dir_hierarchy(outfile)) {
2942  return CURLE_WRITE_ERROR;
2943  }
2944 
2945  if(config->resume_from_current) {
2946  /* We're told to continue from where we are now. Get the
2947  size of the file as it is now and open it for append instead */
2948 
2949  struct stat fileinfo;
2950 
2951  /*VMS?? -- Danger, the filesize is only valid for stream files */
2952  if(0 == stat(outfile, &fileinfo))
2953  /* set offset to current file size: */
2954  config->resume_from = fileinfo.st_size;
2955  else
2956  /* let offset be 0 */
2957  config->resume_from = 0;
2958  }
2959 
2960  outs.filename = outfile;
2961 
2962  if(config->resume_from) {
2963  /* open file for output: */
2964  outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
2965  if (!outs.stream) {
2966  helpf("Can't open '%s'!\n", outfile);
2967  return CURLE_WRITE_ERROR;
2968  }
2969  }
2970  else {
2971  outs.stream = NULL; /* open when needed */
2972  }
2973  }
2974  infdfopen=FALSE;
2975  if(uploadfile && !curl_strequal(uploadfile, "-")) {
2976  /*
2977  * We have specified a file to upload and it isn't "-".
2978  */
2979  struct stat fileinfo;
2980 
2981  /* If no file name part is given in the URL, we add this file name */
2982  char *ptr=strstr(url, "://");
2983  if(ptr)
2984  ptr+=3;
2985  else
2986  ptr=url;
2987  ptr = strrchr(ptr, '/');
2988  if(!ptr || !strlen(++ptr)) {
2989  /* The URL has no file name part, add the local file name. In order
2990  to be able to do so, we have to create a new URL in another
2991  buffer.*/
2992 
2993  /* We only want the part of the local path that is on the right
2994  side of the rightmost slash and backslash. */
2995  char *filep = strrchr(uploadfile, '/');
2996  char *file2 = strrchr(filep?filep:uploadfile, '\\');
2997 
2998  if(file2)
2999  filep = file2+1;
3000  else if(filep)
3001  filep++;
3002  else
3003  filep = uploadfile;
3004 
3005  /* URL encode the file name */
3006  filep = curl_escape(filep, 0 /* use strlen */);
3007 
3008  if(filep) {
3009 
3010  urlbuffer=(char *)malloc(strlen(url) + strlen(filep) + 3);
3011  if(!urlbuffer) {
3012  helpf("out of memory\n");
3013  return CURLE_OUT_OF_MEMORY;
3014  }
3015  if(ptr)
3016  /* there is a trailing slash on the URL */
3017  sprintf(urlbuffer, "%s%s", url, filep);
3018  else
3019  /* thers is no trailing slash on the URL */
3020  sprintf(urlbuffer, "%s/%s", url, filep);
3021 
3022  curl_free(filep);
3023 
3024  free(url);
3025  url = urlbuffer; /* use our new URL instead! */
3026  }
3027  }
3028 /*VMS??-- Reading binary from files can be a problem... */
3029 /*VMS?? Only FIXED, VAR etc WITHOUT implied CC will work */
3030 /*VMS?? Others need a \n appended to a line */
3031 /*VMS??-- Stat gives a size but this is UNRELIABLE in VMS */
3032 /*VMS?? As a f.e. a fixed file with implied CC needs to have a byte added */
3033 /*VMS?? for every record processed, this can by derived from Filesize & recordsize */
3034 /*VMS?? for VARiable record files the records need to be counted! */
3035 /*VMS?? for every record add 1 for linefeed and subtract 2 for the record header */
3036 /*VMS?? for VARIABLE header files only the bare record data needs to be considered with one appended if implied CC */
3037 
3038  infd=(FILE *) fopen(uploadfile, "rb");
3039  if (!infd || stat(uploadfile, &fileinfo)) {
3040  helpf("Can't open '%s'!\n", uploadfile);
3041  return CURLE_READ_ERROR;
3042  }
3043  infdfopen=TRUE;
3044  uploadfilesize=fileinfo.st_size;
3045 
3046  }
3047  else if(uploadfile && curl_strequal(uploadfile, "-")) {
3048  infd = stdin;
3049  }
3050 
3051  if(uploadfile && config->resume_from_current)
3052  config->resume_from = -1; /* -1 will then force get-it-yourself */
3053 
3054  if(outs.stream && isatty(fileno(outs.stream)))
3055  /* we send the output to a tty, therefore we switch off the progress
3056  meter */
3057  config->conf |= CONF_NOPROGRESS;
3058 
3059  if (urlnum > 1 && !(config->conf&CONF_MUTE)) {
3060  fprintf(stderr, "\n[%d/%d]: %s --> %s\n",
3061  i+1, urlnum, url, outfile ? outfile : "<stdout>");
3062  if (separator)
3063  printf("%s%s\n", CURLseparator, url);
3064  }
3065  if (httpgetfields) {
3066  /* Find out whether the url contains a file name */
3067  const char *pc =strstr(url, "://");
3068  char sep='?';
3069  if(pc)
3070  pc+=3;
3071  else
3072  pc=url;
3073 
3074  pc = strrchr(pc, '/'); /* check for a slash */
3075 
3076  if(pc) {
3077  /* there is a slash present in the URL */
3078 
3079  if(strchr(pc, '?'))
3080  /* Ouch, there's already a question mark in the URL string, we
3081  then append the data with an ampersand separator instead! */
3082  sep='&';
3083  }
3084  /*
3085  * Then append ? followed by the get fields to the url.
3086  */
3087  urlbuffer=(char *)malloc(strlen(url) + strlen(httpgetfields) + 2);
3088  if(!urlbuffer) {
3089  helpf("out of memory\n");
3090  return CURLE_OUT_OF_MEMORY;
3091  }
3092  if (pc)
3093  sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
3094  else
3095  /* Append / before the ? to create a well-formed url
3096  if the url contains a hostname only
3097  */
3098  sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
3099 
3100  free(url); /* free previous URL */
3101  url = urlbuffer; /* use our new URL instead! */
3102  }
3103 
3104  if(!config->errors)
3105  config->errors = stderr;
3106 
3107 #ifdef O_BINARY
3108  if(!outfile && !(config->conf & CONF_GETTEXT)) {
3109  /* We get the output to stdout and we have not got the ASCII/text flag,
3110  then set stdout to be binary */
3111  setmode( fileno(stdout), O_BINARY );
3112  }
3113 #endif
3114 
3115  curl_easy_setopt(curl, CURLOPT_SSLENGINE, config->engine);
3116  curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
3117 
3118  /* where to store */
3119  curl_easy_setopt(curl, CURLOPT_WRITEDATA, (FILE *)&outs);
3120  /* what call to write */
3121  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
3122 
3123  /* for uploads */
3124  input.stream = infd;
3125  input.config = config;
3127  /* what call to read */
3128  curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
3129 
3130  if(config->recvpersecond) {
3131  /* tell libcurl to use a smaller sized buffer as it allows us to
3132  make better sleeps! 7.9.9 stuff! */
3133  curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
3134  }
3135 
3136  /* size of uploaded file: */
3137  curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
3138  curl_easy_setopt(curl, CURLOPT_URL, url); /* what to fetch */
3139  curl_easy_setopt(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
3140  curl_easy_setopt(curl, CURLOPT_HEADER, config->conf&CONF_HEADER);
3141  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, config->conf&CONF_NOPROGRESS);
3142  curl_easy_setopt(curl, CURLOPT_NOBODY, config->conf&CONF_NOBODY);
3143  curl_easy_setopt(curl, CURLOPT_FAILONERROR,
3144  config->conf&CONF_FAILONERROR);
3145  curl_easy_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
3146  curl_easy_setopt(curl, CURLOPT_FTPLISTONLY,
3147  config->conf&CONF_FTPLISTONLY);
3148  curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
3149 
3150  if (config->conf&CONF_NETRC_OPT)
3151  curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
3152  else if (config->conf&CONF_NETRC)
3153  curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
3154  else
3155  curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
3156 
3157  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
3158  config->conf&CONF_FOLLOWLOCATION);
3159  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
3160  config->conf&CONF_UNRESTRICTED_AUTH);
3161  curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, config->conf&CONF_GETTEXT);
3162  curl_easy_setopt(curl, CURLOPT_USERPWD, config->userpwd);
3163  curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
3164  curl_easy_setopt(curl, CURLOPT_RANGE, config->range);
3165  curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
3166  curl_easy_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
3167  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config->postfields);
3168 
3169  /* new in libcurl 7.2: */
3170  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, config->postfieldsize);
3171 
3172  curl_easy_setopt(curl, CURLOPT_REFERER, config->referer);
3173  curl_easy_setopt(curl, CURLOPT_AUTOREFERER,
3174  config->conf&CONF_AUTO_REFERER);
3175  curl_easy_setopt(curl, CURLOPT_USERAGENT, config->useragent);
3176  curl_easy_setopt(curl, CURLOPT_FTPPORT, config->ftpport);
3177  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
3178  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
3179  curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
3180  config->use_resume?config->resume_from:0);
3181  curl_easy_setopt(curl, CURLOPT_COOKIE, config->cookie);
3182  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
3183  curl_easy_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
3184  curl_easy_setopt(curl, CURLOPT_SSLCERT, config->cert);
3185  curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
3186  curl_easy_setopt(curl, CURLOPT_SSLKEY, config->key);
3187  curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
3188  curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, config->key_passwd);
3189 
3190  /* default to strict verifyhost */
3191  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
3192  if(config->cacert || config->capath) {
3193  if (config->cacert)
3194  curl_easy_setopt(curl, CURLOPT_CAINFO, config->cacert);
3195 
3196  if (config->capath)
3197  curl_easy_setopt(curl, CURLOPT_CAPATH, config->capath);
3198  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
3199  }
3200  if(config->insecure_ok) {
3201  /* new stuff needed for libcurl 7.10 */
3202  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
3203  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
3204  }
3205 
3206  if((config->conf&CONF_NOBODY) ||
3207  config->remote_time) {
3208  /* no body or use remote time */
3209  curl_easy_setopt(curl, CURLOPT_FILETIME, TRUE);
3210  }
3211 
3212  if (config->maxredirs)
3213  curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
3214  else
3215  curl_easy_setopt(curl, CURLOPT_MAXREDIRS, DEFAULT_MAXREDIRS);
3216 
3217  curl_easy_setopt(curl, CURLOPT_CRLF, config->crlf);
3218  curl_easy_setopt(curl, CURLOPT_QUOTE, config->quote);
3219  curl_easy_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
3220  curl_easy_setopt(curl, CURLOPT_WRITEHEADER,
3221  config->headerfile?&heads:NULL);
3222  curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config->cookiefile);
3223  /* cookie jar was added in 7.9 */
3224  if(config->cookiejar)
3225  curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config->cookiejar);
3226  /* cookie session added in 7.9.7 */
3227  curl_easy_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
3228 
3229  curl_easy_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
3230  curl_easy_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
3231  curl_easy_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
3232  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
3233  curl_easy_setopt(curl, CURLOPT_STDERR, config->errors);
3234 
3235  /* three new ones in libcurl 7.3: */
3236  curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
3237  curl_easy_setopt(curl, CURLOPT_INTERFACE, config->iface);
3238  curl_easy_setopt(curl, CURLOPT_KRB4LEVEL, config->krb4level);
3239 
3240  progressbarinit(&progressbar, config);
3241  if((config->progressmode == CURL_PROGRESS_BAR) &&
3242  !(config->conf&(CONF_NOPROGRESS|CONF_MUTE))) {
3243  /* we want the alternative style, then we have to implement it
3244  ourselves! */
3245  curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
3246  curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
3247  }
3248 
3249  /* new in libcurl 7.6.2: */
3250  curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
3251 
3252  /* new in libcurl 7.7: */
3253  curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, config->random_file);
3254  curl_easy_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
3255  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
3256 
3257  if(config->cipher_list)
3258  curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
3259 
3260  if(config->httpversion)
3261  curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
3262 
3263  /* new in libcurl 7.9.2: */
3264  if(config->disable_epsv)
3265  /* disable it */
3266  curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
3267 
3268  /* new in libcurl 7.10.5 */
3269  if(config->disable_eprt)
3270  /* disable it */
3271  curl_easy_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
3272 
3273  /* new in libcurl 7.10.6 (default is Basic) */
3274  if(config->authtype)
3275  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
3276 
3277  /* new in curl 7.9.7 */
3278  if(config->trace_dump) {
3279  curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
3280  curl_easy_setopt(curl, CURLOPT_DEBUGDATA, config);
3281  config->conf |= CONF_VERBOSE; /* force verbose */
3282  }
3283  curl_easy_setopt(curl, CURLOPT_VERBOSE, config->conf&CONF_VERBOSE);
3284 
3285  /* new in curl 7.10 */
3286  curl_easy_setopt(curl, CURLOPT_ENCODING,
3287  (config->encoding) ? "" : NULL);
3288 
3289  /* new in curl 7.10.7 */
3290  curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
3291  config->ftp_create_dirs);
3292  if(config->proxyntlm)
3293  curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
3294 
3295  /* new in curl 7.10.8 */
3296  if(config->max_filesize)
3297  curl_easy_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
3298  config->max_filesize);
3299 
3300  /* new in curl 7.11.0 */
3301  if(config->ftp_ssl)
3302  curl_easy_setopt(curl, CURLOPT_FTP_SSL, CURLFTPSSL_TRY);
3303 
3304  /* new in curl 7.11.1 */
3305  if(config->socks5proxy) {
3306  curl_easy_setopt(curl, CURLOPT_PROXY, config->socks5proxy);
3307  curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
3308  }
3309 
3310  res = curl_easy_perform(curl);
3311 
3312  if((config->progressmode == CURL_PROGRESS_BAR) &&
3313  progressbar.calls) {
3314  /* if the custom progress bar has been displayed, we output a
3315  newline here */
3316  fputs("\n", progressbar.out);
3317  }
3318 
3319  if(config->writeout) {
3320  ourWriteOut(curl, config->writeout);
3321  }
3322 #ifdef USE_ENVIRONMENT
3323  if (config->writeenv)
3324  ourWriteEnv(curl);
3325 #endif
3326 
3327 #ifdef VMS
3328  if (!config->showerror) {
3329  vms_show = VMSSTS_HIDE;
3330  }
3331 #else
3332  if((res!=CURLE_OK) && config->showerror) {
3333  if(CURLE_SSL_CACERT == res) {
3334  fprintf(config->errors, "curl: (%d) %s\n\n", res, errorbuffer);
3335 #define CURL_CA_CERT_ERRORMSG1 \
3336 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
3337 "curl performs SSL certificate verification by default, using a \"bundle\"\n" \
3338 " of Certificate Authority (CA) public keys (CA certs). The default\n" \
3339 " bundle is named curl-ca-bundle.crt; you can specify an alternate file\n" \
3340 " using the --cacert option.\n"
3341 
3342 #define CURL_CA_CERT_ERRORMSG2 \
3343 "If this HTTPS server uses a certificate signed by a CA represented in\n" \
3344 " the bundle, the certificate verification probably failed due to a\n" \
3345 " problem with the certificate (it might be expired, or the name might\n" \
3346 " not match the domain name in the URL).\n" \
3347 "If you'd like to turn off curl's verification of the certificate, use\n" \
3348 " the -k (or --insecure) option.\n"
3349 
3350  fprintf(config->errors, "%s%s",
3353  }
3354  else
3355  fprintf(config->errors, "curl: (%d) %s\n", res, errorbuffer);
3356  }
3357 #endif
3358 
3359  if (outfile && !curl_strequal(outfile, "-") && outs.stream)
3360  fclose(outs.stream);
3361 
3362 #ifdef HAVE_UTIME
3363  /* Important that we set the time _after_ the file has been
3364  closed, as is done above here */
3365  if(config->remote_time && outs.filename) {
3366  /* as libcurl if we got a time. Pretty please */
3367  long filetime;
3368  curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
3369  if(filetime >= 0) {
3370  struct utimbuf times;
3371  times.actime = filetime;
3372  times.modtime = filetime;
3373  utime(outs.filename, &times); /* set the time we got */
3374  }
3375  }
3376 #endif
3377 #ifdef AMIGA
3378  /* Set the url as comment for the file. (up to 80 chars are allowed)
3379  */
3380  if( strlen(url) > 78 )
3381  url[79] = '\0';
3382 
3383  SetComment( outs.filename, url);
3384 #endif
3385 
3386  if(headerfilep)
3387  fclose(headerfilep);
3388 
3389  if (httpgetfields)
3390  free(httpgetfields);
3391 
3392  if(url)
3393  free(url);
3394 
3395  if(outfile)
3396  free(outfile);
3397 
3398  if(infdfopen)
3399  fclose(infd);
3400 
3401  } /* loop to the next URL */
3402 
3403  if(urls)
3404  /* cleanup memory used for URL globbing patterns */
3405  glob_cleanup(urls);
3406 
3407  if(uploadfile)
3408  free(uploadfile);
3409 
3410  } /* loop to the next globbed upload file */
3411 
3412  if(inglob)
3413  glob_cleanup(inglob);
3414 
3415  if(outfiles)
3416  free(outfiles);
3417 
3418  /* empty this urlnode struct */
3419  if(urlnode->url)
3420  free(urlnode->url);
3421  if(urlnode->outfile)
3422  free(urlnode->outfile);
3423  if(urlnode->infile)
3424  free(urlnode->infile);
3425 
3426  /* move on to the next URL */
3427  nextnode=urlnode->next;
3428  free(urlnode); /* free the node */
3429  urlnode = nextnode;
3430 
3431  } /* while-loop through all URLs */
3432 
3433  if(config->headerfile && !headerfilep && heads.stream)
3434  fclose(heads.stream);
3435 
3436  if(config->trace_fopened && config->trace_stream)
3437  fclose(config->trace_stream);
3438 
3439  if(allocuseragent)
3440  free(config->useragent);
3441 
3442  /* cleanup the curl handle! */
3443  curl_easy_cleanup(curl);
3444 
3445  if(config->errors_fopened)
3446  fclose(config->errors);
3447 
3448  main_free(); /* cleanup */
3449 
3450  return res;
3451 }
3452 
3453 int main(int argc, char *argv[])
3454 {
3455  int res;
3456  struct Configurable config;
3457  memset(&config, 0, sizeof(struct Configurable));
3458 
3459  res = operate(&config, argc, argv);
3460  free_config_fields(&config);
3461 
3462 #ifdef __NOVELL_LIBC__
3463  pressanykey();
3464 #endif
3465 #ifdef VMS
3466  if (res > CURL_LAST) res = CURL_LAST; /* If CURL_LAST exceeded then */
3467  return (vms_cond[res]|vms_show); /* curlmsg.h is out of sync. */
3468 #else
3469  return res;
3470 #endif
3471 }
3472 
3473 static char *my_get_line(FILE *fp)
3474 {
3475  char buf[4096];
3476  char *nl = NULL;
3477  char *retval = NULL;
3478 
3479  do {
3480  if (NULL == fgets(buf, sizeof(buf), fp))
3481  break;
3482  if (NULL == retval)
3483  retval = strdup(buf);
3484  else {
3485  if (NULL == (retval = realloc(retval,
3486  strlen(retval) + strlen(buf) + 1)))
3487  break;
3488  strcat(retval, buf);
3489  }
3490  }
3491  while (NULL == (nl = strchr(retval, '\n')));
3492 
3493  if (NULL != nl)
3494  *nl = '\0';
3495 
3496  return retval;
3497 }
3498 
3499 
3500 /* Create the needed directory hierarchy recursively in order to save
3501  multi-GETs in file output, ie:
3502  curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
3503  should create all the dir* automagically
3504 */
3505 static int create_dir_hierarchy(char *outfile)
3506 {
3507  char *tempdir;
3508  char *tempdir2;
3509  char *outdup;
3510  char *dirbuildup;
3511  int result=0;
3512 
3513  outdup = strdup(outfile);
3514  dirbuildup = malloc(sizeof(char) * strlen(outfile));
3515  if(!dirbuildup)
3516  return -1;
3517  dirbuildup[0] = '\0';
3518 
3519  tempdir = strtok(outdup, DIR_CHAR);
3520 
3521  while (tempdir != NULL) {
3522  tempdir2 = strtok(NULL, DIR_CHAR);
3523  /* since strtok returns a token for the last word even
3524  if not ending with DIR_CHAR, we need to prune it */
3525  if (tempdir2 != NULL) {
3526  if (strlen(dirbuildup) > 0)
3527  sprintf(dirbuildup,"%s%s%s",dirbuildup, DIR_CHAR, tempdir);
3528  else {
3529  if (0 != strncmp(outdup, DIR_CHAR, 1))
3530  sprintf(dirbuildup,"%s",tempdir);
3531  else
3532  sprintf(dirbuildup,"%s%s", DIR_CHAR, tempdir);
3533  }
3534  if (access(dirbuildup, F_OK) == -1) {
3535  result = mkdir(dirbuildup,(mode_t)0000750);
3536  if (-1 == result) {
3537  switch (errno) {
3538 #ifdef EACCES
3539  case EACCES:
3540  fprintf(stderr,"You don't have permission to create %s.\n",
3541  dirbuildup);
3542  break;
3543 #endif
3544 #ifdef ENAMETOOLONG
3545  case ENAMETOOLONG:
3546  fprintf(stderr,"The directory name %s is too long.\n",
3547  dirbuildup);
3548  break;
3549 #endif
3550 #ifdef EROFS
3551  case EROFS:
3552  fprintf(stderr,"%s resides on a read-only file system.\n",
3553  dirbuildup);
3554  break;
3555 #endif
3556 #ifdef ENOSPC
3557  case ENOSPC:
3558  fprintf(stderr,"No space left on the file system that will "
3559  "contain the directory %s.\n", dirbuildup);
3560  break;
3561 #endif
3562 #ifdef EDQUOT
3563  case EDQUOT:
3564  fprintf(stderr,"Cannot create directory %s because you "
3565  "exceeded your quota.\n", dirbuildup);
3566  break;
3567 #endif
3568  default :
3569  fprintf(stderr,"Error creating directory %s.\n", dirbuildup);
3570  break;
3571  }
3572  break; /* get out of loop */
3573  }
3574  }
3575  }
3576  tempdir = tempdir2;
3577  }
3578  free(dirbuildup);
3579  free(outdup);
3580 
3581  return result; /* 0 is fine, -1 is badness */
3582 }
3583 
3584 #ifdef __DJGPP__
3585 /* The following functions are taken with modification from the DJGPP
3586  * port of tar 1.12. They use algorithms originally from DJTAR. */
3587 
3588 char *
3589 msdosify (char *file_name)
3590 {
3591  static char dos_name[PATH_MAX];
3592  static char illegal_chars_dos[] = ".+, ;=[]|<>\\\":?*";
3593  static char *illegal_chars_w95 = &illegal_chars_dos[8];
3594  int idx, dot_idx;
3595  char *s = file_name, *d = dos_name;
3596  char *illegal_aliens = illegal_chars_dos;
3597  size_t len = sizeof (illegal_chars_dos) - 1;
3598  int lfn = 0;
3599 
3600  /* Support for Windows 9X VFAT systems, when available. */
3601  if (_use_lfn (file_name))
3602  lfn = 1;
3603  if (lfn) {
3604  illegal_aliens = illegal_chars_w95;
3605  len -= (illegal_chars_w95 - illegal_chars_dos);
3606  }
3607 
3608  /* Get past the drive letter, if any. */
3609  if (s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
3610  *d++ = *s++;
3611  *d++ = *s++;
3612  }
3613 
3614  for (idx = 0, dot_idx = -1; *s; s++, d++) {
3615  if (memchr (illegal_aliens, *s, len)) {
3616  /* Dots are special: DOS doesn't allow them as the leading character,
3617  and a file name cannot have more than a single dot. We leave the
3618  first non-leading dot alone, unless it comes too close to the
3619  beginning of the name: we want sh.lex.c to become sh_lex.c, not
3620  sh.lex-c. */
3621  if (*s == '.') {
3622  if (idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
3623  /* Copy "./" and "../" verbatim. */
3624  *d++ = *s++;
3625  if (*s == '.')
3626  *d++ = *s++;
3627  *d = *s;
3628  }
3629  else if (idx == 0)
3630  *d = '_';
3631  else if (dot_idx >= 0) {
3632  if (dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
3633  d[dot_idx - idx] = '_'; /* replace previous dot */
3634  *d = '.';
3635  }
3636  else
3637  *d = '-';
3638  }
3639  else
3640  *d = '.';
3641 
3642  if (*s == '.')
3643  dot_idx = idx;
3644  }
3645  else if (*s == '+' && s[1] == '+') {
3646  if (idx - 2 == dot_idx) { /* .c++, .h++ etc. */
3647  *d++ = 'x';
3648  *d = 'x';
3649  }
3650  else {
3651  /* libg++ etc. */
3652  memcpy (d, "plus", 4);
3653  d += 3;
3654  }
3655  s++;
3656  idx++;
3657  }
3658  else
3659  *d = '_';
3660  }
3661  else
3662  *d = *s;
3663  if (*s == '/') {
3664  idx = 0;
3665  dot_idx = -1;
3666  }
3667  else
3668  idx++;
3669  }
3670 
3671  *d = '\0';
3672  return dos_name;
3673 }
3674 
3675 char *
3676 rename_if_dos_device_name (char *file_name)
3677 {
3678  /* We could have a file whose name is a device on MS-DOS. Trying to
3679  * retrieve such a file would fail at best and wedge us at worst. We need
3680  * to rename such files. */
3681  extern char *basename (const char *);
3682  char *base;
3683  struct stat st_buf;
3684  char fname[PATH_MAX];
3685 
3686  strcpy (fname, file_name);
3687  base = basename (fname);
3688  if (((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
3689  size_t blen = strlen (base);
3690 
3691  /* Prepend a '_'. */
3692  memmove (base + 1, base, blen + 1);
3693  base[0] = '_';
3694  strcpy (file_name, fname);
3695  }
3696  return file_name;
3697 }
3698 
3699 #endif /* __DJGPP__ */
char * glob_match_url(char *filename, URLGlob *glob)
Definition: urlglob.c:428
CURLcode curl_global_init(long flags)
Globally initializes cURL given a bitwise set of the different features to initialize.
Definition: easy.c:147
CURLformoption option
Definition: curl.h:934
struct curl_forms form
Definition: main.c:634
struct getout * next
Definition: main.c:261
bool showerror
Definition: main.c:431
#define strcmp
Definition: Str.h:41
struct curl_httppost * last_post
Definition: main.c:489
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info,...)
Definition: easy.c:299
char * ftpport
Definition: main.c:425
int main(int argc, char *argv[])
Definition: main.c:3453
bool use_httpget
Definition: main.c:465
GLsizei const GLfloat * value
Definition: glext.h:3614
char * cert_type
Definition: main.c:446
long conf
Definition: main.c:436
bool trace_fopened
Definition: main.c:458
long low_speed_limit
Definition: main.c:429
char * userpwd
Definition: main.c:432
FILE * out
Definition: main.c:2324
#define OS
struct getout * url_get
Definition: main.c:441
bool crlf
Definition: main.c:453
#define CURLAUTH_BASIC
Definition: curl.h:296
#define CURL_VERSION_SSL
Definition: curl.h:1254
struct Configurable * config
Definition: main.c:2221
bool errors_fopened
Definition: main.c:475
#define CURLRC
bool proxytunnel
Definition: main.c:435
long authtype
Definition: main.c:411
GLenum GLsizei GLenum format
Definition: glext.h:2846
long postfieldsize
Definition: main.c:418
#define CURL_VERSION_LIBZ
Definition: curl.h:1255
char * curl_getenv(const char *variable)
Definition: getenv.c:68
const char * letter
Definition: main.c:396
bool cookiesession
Definition: main.c:409
#define LONG_MAX
#define CONF_FOLLOWLOCATION
Definition: main.c:170
char * capath
Definition: main.c:448
FILE * trace_stream
Definition: main.c:457
#define CONF_FAILONERROR
Definition: main.c:166
long tv_sec
Definition: timeval.h:37
#define CONF_MUTE
Definition: main.c:173
char * urls[]
Definition: multithread.c:19
DWORD
Definition: win_qgl.cpp:61
CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post,...)
Definition: formdata.c:978
bool nobuffer
Definition: main.c:463
GLfloat param
Definition: glext.h:3038
case const int
Definition: Callbacks.cpp:52
time_t curl_getdate(const char *p, const time_t *now)
Definition: getdate.c:1991
int width
Definition: main.c:2323
#define DEFAULT_MAXREDIRS
Definition: main.c:116
long vms_cond[]
Definition: curlmsg_vms.h:23
curl_off_t resume_from
Definition: main.c:416
int fileno(FILE *stream)
CURLcode curl_easy_perform(CURL *curl)
Definition: easy.c:260
CURLcode
Definition: curl.h:209
HttpReq
Definition: main.c:148
char * customrequest
Definition: main.c:454
#define CURLAUTH_GSSNEGOTIATE
Definition: curl.h:298
char * egd_file
Definition: main.c:404
GLenum GLsizei const GLvoid * string
Definition: glext.h:3472
long low_speed_time
Definition: main.c:430
#define DIR_CHAR
Definition: setup.h:235
long ssl_version
Definition: main.c:481
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
size_t lastrecvsize
Definition: main.c:504
char * infile
Definition: main.c:264
#define isseparator(x)
FILE * stream
Definition: main.c:2220
GLdouble s
Definition: glext.h:2935
GLenum GLsizei len
Definition: glext.h:3472
CURLcode curl_easy_setopt(CURL *curl, CURLoption option,...)
Definition: easy.c:217
off_t curl_off_t
Definition: curl.h:96
char * trace_dump
Definition: main.c:456
void Sleep(const int time)
int i
Definition: process.py:33
GLuint GLuint num
Definition: glext.h:5390
Boolean result
char * cert
Definition: main.c:445
char * cacert
Definition: main.c:447
int vms_show
Definition: curlmsg_vms.h:8
#define CURL_CA_CERT_ERRORMSG2
#define CONF_UNRESTRICTED_AUTH
Definition: main.c:177
struct getout * url_list
Definition: main.c:438
HttpReq httpreq
Definition: main.c:493
#define CURL_VERSION_NTLM
Definition: curl.h:1256
#define GETOUT_UPLOAD
Definition: main.c:270
char * key_passwd
Definition: main.c:451
char * strdup(char *str)
Definition: main.c:183
char * filename
Definition: main.c:2219
struct getout * url_out
Definition: main.c:442
#define CURL_VERSION
Definition: version.h:32
void ourWriteOut(CURL *curl, char *writeinfo)
Definition: writeout.c:86
#define CURL_ID
Definition: version.h:33
char * engine
Definition: main.c:452
Definition: main.c:946
void curl_memdebug(void)
Definition: memdebug.c:286
#define CURLseparator
Definition: main.c:52
GLuint GLuint GLsizei count
Definition: glext.h:2845
char * iface
Definition: main.c:426
const GLubyte * c
Definition: glext.h:4677
#define CONF_NETRC_OPT
Definition: main.c:175
bool disable_epsv
Definition: main.c:414
double prev
Definition: main.c:2322
struct multi_files * next
Definition: main.c:635
void curl_global_cleanup(void)
Globally cleanup cURL, uses the value of "init_flags" to determine what needs to be cleaned up and ...
Definition: easy.c:174
struct curl_slist * quote
Definition: main.c:477
#define CURL_VERSION_DEBUG
Definition: curl.h:1258
void hugehelp(void)
Definition: hugehelp.c:3
#define CONF_GETTEXT
Definition: main.c:171
long maxredirs
Definition: main.c:422
bool ftp_create_dirs
Definition: main.c:468
#define NULL
Definition: Lib.h:88
void ourWriteEnv(CURL *curl)
FILE * errors
Definition: main.c:474
bool resume_from_current
Definition: main.c:413
#define select(args...)
Definition: amigaos.h:39
char * cookiefile
Definition: main.c:408
char * getpass_r(const char *prompt, char *buffer, size_t buflen)
Definition: getpass.c:101
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
curl_TimeCond
Definition: curl.h:858
GLuint buffer
Definition: glext.h:3108
bool extraparam
Definition: main.c:398
#define CURL_GLOBAL_DEFAULT
Definition: curl.h:1155
int fputc(int, FILE *)
bool globoff
Definition: main.c:464
void glob_cleanup(URLGlob *glob)
Definition: urlglob.c:328
char * curl_escape(const char *string, int length)
Definition: escape.c:40
FILE * stream
Definition: main.c:2277
bool encoding
Definition: main.c:410
char * outfile
Definition: main.c:263
char * glob_next_url(URLGlob *glob)
Definition: urlglob.c:351
size_t lastsendsize
Definition: main.c:501
int() curl_strnequal(const char *s1, const char *s2, size_t n)
Definition: strequal.c:57
GLenum GLsizei width
Definition: glext.h:2846
GLenum GLenum GLenum input
Definition: glext.h:4803
struct curl_slist * prequote
Definition: main.c:479
#define CONF_DEFAULT
Definition: main.c:159
#define CURL_VERSION_IPV6
Definition: curl.h:1252
#define CONF_FTPAPPEND
Definition: main.c:168
#define MIN(X, Y)
standard MIN macro
Definition: main.c:145
#define GETOUT_OUTFILE
Definition: main.c:267
#define CURLAUTH_NTLM
Definition: curl.h:299
bool trace_ascii
Definition: main.c:459
const char ** protocols
Definition: curl.h:1245
time_t lastsendtime
Definition: main.c:500
long ip_version
Definition: main.c:482
char * key_type
Definition: main.c:450
long timeout
Definition: main.c:420
char * referer
Definition: main.c:419
#define CURL_NAME
Definition: version.h:28
Definition: curl.h:210
#define GETOUT_USEREMOTE
Definition: main.c:269
#define FORM_TYPE_SEPARATOR
Definition: main.c:748
curl_off_t initial_size
Definition: main.c:2325
bool use_resume
Definition: main.c:412
#define CURL_VERSION_GSSNEGOTIATE
Definition: curl.h:1257
void curl_formfree(struct curl_httppost *form)
Definition: formdata.c:1073
#define GETOUT_NOUPLOAD
Definition: main.c:271
int flags
Definition: main.c:265
char * cookie
Definition: main.c:406
curl_TimeCond timecond
Definition: main.c:483
struct getout * url_last
Definition: main.c:439
#define CONF_NETRC
Definition: main.c:169
int glob_url(URLGlob **glob, char *url, int *urlnum, FILE *error)
Definition: urlglob.c:285
#define CONF_HEADER
Definition: main.c:163
bool remote_time
Definition: main.c:402
size_t fread(void *, size_t, size_t, FILE *)
char * writeout
Definition: main.c:471
char * proxy
Definition: main.c:434
char * url
Definition: main.c:262
#define FORM_FILE_SEPARATOR
Definition: main.c:747
struct Configurable * config
Definition: main.c:2278
curl_version_info_data * curl_version_info(CURLversion)
Definition: version.c:213
int calls
Definition: main.c:2321
unsigned short word
Definition: Lib.h:76
char * headerfile
Definition: main.c:424
GLuint in
Definition: glext.h:5388
#define CURLVERSION_NOW
Definition: curl.h:1233
char * cipher_list
Definition: main.c:444
char * postfields
Definition: main.c:417
char * cookiejar
Definition: main.c:407
char * curl_version(void)
Definition: version.c:94
int curl_msnprintf(char *buffer, size_t maxlength, const char *format,...)
Definition: mprintf.c:1011
#define snprintf
Definition: Str.h:70
const GLcharARB * name
Definition: glext.h:3629
struct curl_slist * postquote
Definition: main.c:478
GLsizeiptr size
Definition: glext.h:3112
bool writeenv
Definition: main.c:472
const char * value
Definition: curl.h:935
struct curl_slist * curl_slist_append(struct curl_slist *, const char *)
Definition: sendf.c:82
ParameterError
Definition: main.c:945
char * homedir(void)
Definition: homedir.c:88
char * key
Definition: main.c:449
#define CONF_AUTO_REFERER
Definition: main.c:161
#define CURL_CA_CERT_ERRORMSG1
bool insecure_ok
Definition: main.c:466
struct curl_httppost * httppost
Definition: main.c:488
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
#define FALSE
Definition: mprintf.c:70
char * useragent
Definition: main.c:405
void curl_free(void *p)
Definition: escape.c:125
void CURL
Definition: types.h:25
const char * lname
Definition: main.c:397
bool create_dirs
Definition: main.c:467
void curl_slist_free_all(struct curl_slist *)
Definition: sendf.c:108
char * krb4level
Definition: main.c:455
#define CURL_ERROR_SIZE
Definition: curl.h:312
#define CURLAUTH_DIGEST
Definition: curl.h:297
#define strncmp
Definition: Str.h:42
#define strtoofft
Definition: strtoofft.h:58
time_t condtime
Definition: main.c:484
GLuint res
Definition: glext.h:5385
#define TRUE
Definition: mprintf.c:69
bool proxyntlm
Definition: main.c:469
bool disable_eprt
Definition: main.c:415
GLint j
Definition: qgl.h:264
long connecttimeout
Definition: main.c:421
#define CONF_NOBODY
Definition: main.c:165
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
struct curl_slist * telnet_options
Definition: main.c:491
#define CURL_VERSION_ASYNCHDNS
Definition: curl.h:1259
char bool
Definition: main.c:133
curl_infotype
Definition: curl.h:186
#define CURLAUTH_ANY
Definition: curl.h:300
int() curl_strequal(const char *s1, const char *s2)
Definition: strequal.c:37
char * random_file
Definition: main.c:403
bool ftp_ssl
Definition: main.c:506
#define F_OK
#define CURLOPT_READDATA
Definition: curl.h:806
size_t recvpersecond
Definition: main.c:498
void curl_easy_cleanup(CURL *curl)
Definition: easy.c:288
struct curl_slist * headers
Definition: main.c:486
#define CONF_FTPLISTONLY
Definition: main.c:167
#define CURLOPT_WRITEDATA
Definition: curl.h:805
#define CURL_VERSION_LARGEFILE
Definition: curl.h:1261
#define CURL_PROGRESS_BAR
Definition: main.c:138
time_t lastrecvtime
Definition: main.c:503
size_t fwrite(const void *, size_t, size_t, FILE *)
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
char * socks5proxy
Definition: main.c:508
long httpversion
Definition: main.c:461
#define GETOUT_URL
Definition: main.c:268
#define CONF_VERBOSE
Definition: main.c:162
bool progressmode
Definition: main.c:462
#define CURL_VERSION_KERBEROS4
Definition: curl.h:1253
CURL * curl_easy_init(void)
Definition: easy.c:195
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
Definition: ftpget.c:29
char * range
Definition: main.c:428
char * proxyuserpwd
Definition: main.c:433
curl_off_t max_filesize
Definition: main.c:423
unsigned short porttouse
Definition: main.c:427
Definition: main.c:260
#define CURL_VERSION_SPNEGO
Definition: curl.h:1260
#define CONF_NOPROGRESS
Definition: main.c:164
#define LONG_MIN
size_t sendpersecond
Definition: main.c:497