Reduced #ifdef HAVE_METALINK
[platform/upstream/curl.git] / src / tool_operate.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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  ***************************************************************************/
22 #include "tool_setup.h"
23
24 #ifdef HAVE_UNISTD_H
25 #  include <unistd.h>
26 #endif
27
28 #ifdef HAVE_FCNTL_H
29 #  include <fcntl.h>
30 #endif
31
32 #ifdef HAVE_UTIME_H
33 #  include <utime.h>
34 #elif defined(HAVE_SYS_UTIME_H)
35 #  include <sys/utime.h>
36 #endif
37
38 #ifdef HAVE_LOCALE_H
39 #  include <locale.h>
40 #endif
41
42 #ifdef HAVE_NETINET_TCP_H
43 #  include <netinet/tcp.h>
44 #endif
45
46 #include "rawstr.h"
47
48 #define ENABLE_CURLX_PRINTF
49 /* use our own printf() functions */
50 #include "curlx.h"
51
52 #include "tool_binmode.h"
53 #include "tool_cfgable.h"
54 #include "tool_cb_dbg.h"
55 #include "tool_cb_hdr.h"
56 #include "tool_cb_prg.h"
57 #include "tool_cb_rea.h"
58 #include "tool_cb_see.h"
59 #include "tool_cb_wrt.h"
60 #include "tool_dirhie.h"
61 #include "tool_doswin.h"
62 #include "tool_easysrc.h"
63 #include "tool_getparam.h"
64 #include "tool_helpers.h"
65 #include "tool_homedir.h"
66 #include "tool_libinfo.h"
67 #include "tool_main.h"
68 #include "tool_msgs.h"
69 #include "tool_operate.h"
70 #include "tool_operhlp.h"
71 #include "tool_parsecfg.h"
72 #include "tool_setopt.h"
73 #include "tool_sleep.h"
74 #include "tool_urlglob.h"
75 #include "tool_util.h"
76 #include "tool_writeenv.h"
77 #include "tool_writeout.h"
78 #include "tool_xattr.h"
79
80 #include "memdebug.h" /* keep this as LAST include */
81
82 #define CURLseparator  "--_curl_--"
83
84 #ifndef O_BINARY
85 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
86    source code but yet it doesn't ruin anything */
87 #  define O_BINARY 0
88 #endif
89
90 #define CURL_CA_CERT_ERRORMSG1                                              \
91   "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n"           \
92   "curl performs SSL certificate verification by default, "                 \
93   "using a \"bundle\"\n"                                                    \
94   " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
95   " bundle file isn't adequate, you can specify an alternate file\n"        \
96   " using the --cacert option.\n"
97
98 #define CURL_CA_CERT_ERRORMSG2                                              \
99   "If this HTTPS server uses a certificate signed by a CA represented in\n" \
100   " the bundle, the certificate verification probably failed due to a\n"    \
101   " problem with the certificate (it might be expired, or the name might\n" \
102   " not match the domain name in the URL).\n"                               \
103   "If you'd like to turn off curl's verification of the certificate, use\n" \
104   " the -k (or --insecure) option.\n"
105
106 static int is_fatal_error(int code)
107 {
108   switch(code) {
109   /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
110   case CURLE_FAILED_INIT:
111   case CURLE_OUT_OF_MEMORY:
112   case CURLE_UNKNOWN_OPTION:
113   case CURLE_FUNCTION_NOT_FOUND:
114   case CURLE_BAD_FUNCTION_ARGUMENT:
115     /* critical error */
116     return 1;
117   default:
118     break;
119   }
120   /* no error or not critical */
121   return 0;
122 }
123
124 int operate(struct Configurable *config, int argc, argv_item_t argv[])
125 {
126   char errorbuffer[CURL_ERROR_SIZE];
127   struct ProgressData progressbar;
128   struct getout *urlnode;
129
130   struct OutStruct heads;
131
132   metalinkfile *mlfile_last = NULL;
133
134   CURL *curl = NULL;
135   char *httpgetfields = NULL;
136
137   bool stillflags;
138   int res = 0;
139   int i;
140
141   errorbuffer[0] = '\0';
142   /* default headers output stream is stdout */
143   memset(&heads, 0, sizeof(struct OutStruct));
144   heads.stream = stdout;
145   heads.config = config;
146
147   memory_tracking_init();
148
149   /*
150   ** Initialize curl library - do not call any libcurl functions before
151   ** this point. Note that the memory_tracking_init() magic above is an
152   ** exception, but then that's not part of the official public API.
153   */
154   if(main_init() != CURLE_OK) {
155     helpf(config->errors, "error initializing curl library\n");
156     return CURLE_FAILED_INIT;
157   }
158
159   /* Get libcurl info right away */
160   if(get_libcurl_info() != CURLE_OK) {
161     helpf(config->errors, "error retrieving curl library information\n");
162     main_free();
163     return CURLE_FAILED_INIT;
164   }
165
166   /* Get a curl handle to use for all forthcoming curl transfers */
167   curl = curl_easy_init();
168   if(!curl) {
169     helpf(config->errors, "error initializing curl easy handle\n");
170     main_free();
171     return CURLE_FAILED_INIT;
172   }
173   config->easy = curl;
174
175   /*
176   ** Beyond this point no return'ing from this function allowed.
177   ** Jump to label 'quit_curl' in order to abandon this function
178   ** from outside of nested loops further down below.
179   */
180
181   /* setup proper locale from environment */
182 #ifdef HAVE_SETLOCALE
183   setlocale(LC_ALL, "");
184 #endif
185
186   /* inits */
187   config->postfieldsize = -1;
188   config->showerror = -1; /* will show errors */
189   config->use_httpget = FALSE;
190   config->create_dirs = FALSE;
191   config->maxredirs = DEFAULT_MAXREDIRS;
192   config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
193   config->proto_present = FALSE;
194   config->proto_redir =
195     CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
196   config->proto_redir_present = FALSE;
197
198   if((argc > 1) &&
199      (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
200      strchr(argv[1], 'q')) {
201     /*
202      * The first flag, that is not a verbose name, but a shortname
203      * and it includes the 'q' flag!
204      */
205     ;
206   }
207   else {
208     parseconfig(NULL, config); /* ignore possible failure */
209   }
210
211   if((argc < 2)  && !config->url_list) {
212     helpf(config->errors, NULL);
213     res = CURLE_FAILED_INIT;
214     goto quit_curl;
215   }
216
217   /* Parse options */
218   for(i = 1, stillflags = TRUE; i < argc; i++) {
219     if(stillflags &&
220        ('-' == argv[i][0])) {
221       char *nextarg;
222       bool passarg;
223       char *origopt = argv[i];
224
225       char *flag = argv[i];
226
227       if(curlx_strequal("--", argv[i]))
228         /* this indicates the end of the flags and thus enables the
229            following (URL) argument to start with -. */
230         stillflags = FALSE;
231       else {
232         nextarg = (i < (argc-1)) ? argv[i+1] : NULL;
233
234         res = getparameter(flag, nextarg, &passarg, config);
235         if(res) {
236           int retval = CURLE_OK;
237           if(res != PARAM_HELP_REQUESTED) {
238             const char *reason = param2text(res);
239             helpf(config->errors, "option %s: %s\n", origopt, reason);
240             retval = CURLE_FAILED_INIT;
241           }
242           res = retval;
243           goto quit_curl;
244         }
245
246         if(passarg) /* we're supposed to skip this */
247           i++;
248       }
249     }
250     else {
251       bool used;
252       /* just add the URL please */
253       res = getparameter((char *)"--url", argv[i], &used, config);
254       if(res)
255         goto quit_curl;
256     }
257   }
258
259   if((!config->url_list || !config->url_list->url) && !config->list_engines) {
260     helpf(config->errors, "no URL specified!\n");
261     res = CURLE_FAILED_INIT;
262     goto quit_curl;
263   }
264
265   if(!config->useragent)
266     config->useragent = my_useragent();
267   if(!config->useragent) {
268     helpf(config->errors, "out of memory\n");
269     res = CURLE_OUT_OF_MEMORY;
270     goto quit_curl;
271   }
272
273   /* On WIN32 we can't set the path to curl-ca-bundle.crt
274    * at compile time. So we look here for the file in two ways:
275    * 1: look at the environment variable CURL_CA_BUNDLE for a path
276    * 2: if #1 isn't found, use the windows API function SearchPath()
277    *    to find it along the app's path (includes app's dir and CWD)
278    *
279    * We support the environment variable thing for non-Windows platforms
280    * too. Just for the sake of it.
281    */
282   if(!config->cacert &&
283      !config->capath &&
284      !config->insecure_ok) {
285     char *env;
286     env = curlx_getenv("CURL_CA_BUNDLE");
287     if(env) {
288       config->cacert = strdup(env);
289       if(!config->cacert) {
290         curl_free(env);
291         helpf(config->errors, "out of memory\n");
292         res = CURLE_OUT_OF_MEMORY;
293         goto quit_curl;
294       }
295     }
296     else {
297       env = curlx_getenv("SSL_CERT_DIR");
298       if(env) {
299         config->capath = strdup(env);
300         if(!config->capath) {
301           curl_free(env);
302           helpf(config->errors, "out of memory\n");
303           res = CURLE_OUT_OF_MEMORY;
304           goto quit_curl;
305         }
306       }
307       else {
308         env = curlx_getenv("SSL_CERT_FILE");
309         if(env) {
310           config->cacert = strdup(env);
311           if(!config->cacert) {
312             curl_free(env);
313             helpf(config->errors, "out of memory\n");
314             res = CURLE_OUT_OF_MEMORY;
315             goto quit_curl;
316           }
317         }
318       }
319     }
320
321     if(env)
322       curl_free(env);
323 #ifdef WIN32
324     else {
325       res = FindWin32CACert(config, "curl-ca-bundle.crt");
326       if(res)
327         goto quit_curl;
328     }
329 #endif
330   }
331
332   if(config->postfields) {
333     if(config->use_httpget) {
334       /* Use the postfields data for a http get */
335       httpgetfields = strdup(config->postfields);
336       Curl_safefree(config->postfields);
337       if(!httpgetfields) {
338         helpf(config->errors, "out of memory\n");
339         res = CURLE_OUT_OF_MEMORY;
340         goto quit_curl;
341       }
342       if(SetHTTPrequest(config,
343                         (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
344                         &config->httpreq)) {
345         res = PARAM_BAD_USE;
346         goto quit_curl;
347       }
348     }
349     else {
350       if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
351         res = PARAM_BAD_USE;
352         goto quit_curl;
353       }
354     }
355   }
356
357 #ifndef CURL_DISABLE_LIBCURL_OPTION
358   res = easysrc_init();
359   if(res) {
360     helpf(config->errors, "out of memory\n");
361     goto quit_curl;
362   }
363 #endif
364
365   if(config->list_engines) {
366     struct curl_slist *engines = NULL;
367     curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
368     list_engines(engines);
369     curl_slist_free_all(engines);
370     res = CURLE_OK;
371     goto quit_curl;
372   }
373
374   /* Single header file for all URLs */
375   if(config->headerfile) {
376     /* open file for output: */
377     if(!curlx_strequal(config->headerfile, "-")) {
378       FILE *newfile = fopen(config->headerfile, "wb");
379       if(!newfile) {
380         warnf(config, "Failed to open %s\n", config->headerfile);
381         res = CURLE_WRITE_ERROR;
382         goto quit_curl;
383       }
384       else {
385         heads.filename = config->headerfile;
386         heads.s_isreg = TRUE;
387         heads.fopened = TRUE;
388         heads.stream = newfile;
389       }
390     }
391   }
392
393   /*
394   ** Nested loops start here.
395   */
396
397   /* loop through the list of given URLs */
398
399   for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
400
401     int up; /* upload file counter within a single upload glob */
402     char *infiles; /* might be a glob pattern */
403     char *outfiles;
404     int infilenum;
405     URLGlob *inglob;
406
407     int metalink = 0; /* nonzero for metalink download. */
408     metalinkfile *mlfile;
409     metalink_resource *mlres;
410
411     outfiles = NULL;
412     infilenum = 1;
413     inglob = NULL;
414
415     if(urlnode->flags & GETOUT_METALINK) {
416       metalink = 1;
417       if(mlfile_last == NULL) {
418         mlfile_last = config->metalinkfile_list;
419       }
420       mlfile = mlfile_last;
421       mlfile_last = mlfile_last->next;
422       mlres = mlfile->resource;
423     }
424     else {
425       mlfile = NULL;
426       mlres = NULL;
427     }
428
429     /* urlnode->url is the full URL (it might be NULL) */
430
431     if(!urlnode->url) {
432       /* This node has no URL. Free node data without destroying the
433          node itself nor modifying next pointer and continue to next */
434       Curl_safefree(urlnode->outfile);
435       Curl_safefree(urlnode->infile);
436       urlnode->flags = 0;
437       continue; /* next URL please */
438     }
439
440     /* save outfile pattern before expansion */
441     if(urlnode->outfile) {
442       outfiles = strdup(urlnode->outfile);
443       if(!outfiles) {
444         helpf(config->errors, "out of memory\n");
445         res = CURLE_OUT_OF_MEMORY;
446         break;
447       }
448     }
449
450     infiles = urlnode->infile;
451
452     if(!config->globoff && infiles) {
453       /* Unless explicitly shut off */
454       res = glob_url(&inglob, infiles, &infilenum,
455                      config->showerror?config->errors:NULL);
456       if(res) {
457         Curl_safefree(outfiles);
458         break;
459       }
460     }
461
462     /* Here's the loop for uploading multiple files within the same
463        single globbed string. If no upload, we enter the loop once anyway. */
464     for(up = 0 ; up < infilenum; up++) {
465
466       char *uploadfile; /* a single file, never a glob */
467       int separator;
468       URLGlob *urls;
469       int urlnum;
470
471       uploadfile = NULL;
472       separator = 0;
473       urls = NULL;
474       urlnum = 0;
475
476       if(!up && !infiles)
477         Curl_nop_stmt;
478       else {
479         if(inglob) {
480           res = glob_next_url(&uploadfile, inglob);
481           if(res == CURLE_OUT_OF_MEMORY)
482             helpf(config->errors, "out of memory\n");
483         }
484         else if(!up) {
485           uploadfile = strdup(infiles);
486           if(!uploadfile) {
487             helpf(config->errors, "out of memory\n");
488             res = CURLE_OUT_OF_MEMORY;
489           }
490         }
491         else
492           uploadfile = NULL;
493         if(!uploadfile)
494           break;
495       }
496
497       if(metalink) {
498         /* For Metalink download, we don't use glob. Instead we use
499            the number of resources as urlnum. */
500         urlnum = count_next_metalink_resource(mlfile);
501       }
502       else
503       if(!config->globoff) {
504         /* Unless explicitly shut off, we expand '{...}' and '[...]'
505            expressions and return total number of URLs in pattern set */
506         res = glob_url(&urls, urlnode->url, &urlnum,
507                        config->showerror?config->errors:NULL);
508         if(res) {
509           Curl_safefree(uploadfile);
510           break;
511         }
512       }
513       else
514         urlnum = 1; /* without globbing, this is a single URL */
515
516       /* if multiple files extracted to stdout, insert separators! */
517       separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
518
519       /* Here's looping around each globbed URL */
520       for(i = 0 ; i < urlnum; i++) {
521
522         int infd;
523         bool infdopen;
524         char *outfile;
525         struct OutStruct outs;
526         struct InStruct input;
527         struct timeval retrystart;
528         curl_off_t uploadfilesize;
529         long retry_numretries;
530         long retry_sleep_default;
531         long retry_sleep;
532         char *this_url;
533         HeaderData hdrdata;
534         int metalink_next_res = 0;
535
536         outfile = NULL;
537         infdopen = FALSE;
538         infd = STDIN_FILENO;
539         uploadfilesize = -1; /* -1 means unknown */
540
541         /* default output stream is stdout */
542         memset(&outs, 0, sizeof(struct OutStruct));
543         outs.stream = stdout;
544         outs.config = config;
545
546         if(metalink) {
547           /* For Metalink download, use name in Metalink file as
548              filename. */
549           outfile = strdup(mlfile->filename);
550           if(!outfile) {
551             res = CURLE_OUT_OF_MEMORY;
552             goto show_error;
553           }
554           this_url = strdup(mlres->url);
555           if(!this_url) {
556             res = CURLE_OUT_OF_MEMORY;
557             goto show_error;
558           }
559         }
560         else {
561           if(urls) {
562             res = glob_next_url(&this_url, urls);
563             if(res)
564               goto show_error;
565           }
566           else if(!i) {
567             this_url = strdup(urlnode->url);
568             if(!this_url) {
569               res = CURLE_OUT_OF_MEMORY;
570               goto show_error;
571             }
572           }
573           else
574             this_url = NULL;
575           if(!this_url)
576             break;
577
578           if(outfiles) {
579             outfile = strdup(outfiles);
580             if(!outfile) {
581               res = CURLE_OUT_OF_MEMORY;
582               goto show_error;
583             }
584           }
585         }
586
587         if((urlnode->flags&GETOUT_USEREMOTE) ||
588            (outfile && !curlx_strequal("-", outfile)) ) {
589
590           /*
591            * We have specified a file name to store the result in, or we have
592            * decided we want to use the remote file name.
593            */
594
595           if(!outfile) {
596             /* extract the file name from the URL */
597             res = get_url_file_name(&outfile, this_url);
598             if(res)
599               goto show_error;
600             if((!outfile || !*outfile) && !config->content_disposition) {
601               helpf(config->errors, "Remote file name has no length!\n");
602               res = CURLE_WRITE_ERROR;
603               goto quit_urls;
604             }
605 #if defined(MSDOS) || defined(WIN32)
606             /* For DOS and WIN32, we do some major replacing of
607                bad characters in the file name before using it */
608             outfile = sanitize_dos_name(outfile);
609             if(!outfile) {
610               res = CURLE_OUT_OF_MEMORY;
611               goto show_error;
612             }
613 #endif /* MSDOS || WIN32 */
614           }
615           else if(urls) {
616             /* fill '#1' ... '#9' terms from URL pattern */
617             char *storefile = outfile;
618             res = glob_match_url(&outfile, storefile, urls);
619             Curl_safefree(storefile);
620             if(res) {
621               /* bad globbing */
622               warnf(config, "bad output glob!\n");
623               goto quit_urls;
624             }
625           }
626
627           /* Create the directory hierarchy, if not pre-existent to a multiple
628              file output call */
629
630           if(config->create_dirs || metalink) {
631             res = create_dir_hierarchy(outfile, config->errors);
632             /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
633             if(res == CURLE_WRITE_ERROR)
634               goto quit_urls;
635             if(res) {
636               goto show_error;
637             }
638           }
639
640           if((urlnode->flags & GETOUT_USEREMOTE)
641              && config->content_disposition) {
642             /* Our header callback MIGHT set the filename */
643             DEBUGASSERT(!outs.filename);
644           }
645
646           if(config->resume_from_current) {
647             /* We're told to continue from where we are now. Get the size
648                of the file as it is now and open it for append instead */
649             struct_stat fileinfo;
650             /* VMS -- Danger, the filesize is only valid for stream files */
651             if(0 == stat(outfile, &fileinfo))
652               /* set offset to current file size: */
653               config->resume_from = fileinfo.st_size;
654             else
655               /* let offset be 0 */
656               config->resume_from = 0;
657           }
658
659           if(config->resume_from) {
660             /* open file for output: */
661             FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
662             if(!file) {
663               helpf(config->errors, "Can't open '%s'!\n", outfile);
664               res = CURLE_WRITE_ERROR;
665               goto quit_urls;
666             }
667             outs.fopened = TRUE;
668             outs.stream = file;
669             outs.init = config->resume_from;
670           }
671           else {
672             outs.stream = NULL; /* open when needed */
673           }
674           outs.filename = outfile;
675           outs.s_isreg = TRUE;
676         }
677
678         if(uploadfile && !stdin_upload(uploadfile)) {
679           /*
680            * We have specified a file to upload and it isn't "-".
681            */
682           struct_stat fileinfo;
683
684           this_url = add_file_name_to_url(curl, this_url, uploadfile);
685           if(!this_url) {
686             res = CURLE_OUT_OF_MEMORY;
687             goto show_error;
688           }
689           /* VMS Note:
690            *
691            * Reading binary from files can be a problem...  Only FIXED, VAR
692            * etc WITHOUT implied CC will work Others need a \n appended to a
693            * line
694            *
695            * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
696            * fixed file with implied CC needs to have a byte added for every
697            * record processed, this can by derived from Filesize & recordsize
698            * for VARiable record files the records need to be counted!  for
699            * every record add 1 for linefeed and subtract 2 for the record
700            * header for VARIABLE header files only the bare record data needs
701            * to be considered with one appended if implied CC
702            */
703
704           infd = open(uploadfile, O_RDONLY | O_BINARY);
705           if((infd == -1) || fstat(infd, &fileinfo)) {
706             helpf(config->errors, "Can't open '%s'!\n", uploadfile);
707             if(infd != -1) {
708               close(infd);
709               infd = STDIN_FILENO;
710             }
711             res = CURLE_READ_ERROR;
712             goto quit_urls;
713           }
714           infdopen = TRUE;
715
716           /* we ignore file size for char/block devices, sockets, etc. */
717           if(S_ISREG(fileinfo.st_mode))
718             uploadfilesize = fileinfo.st_size;
719
720         }
721         else if(uploadfile && stdin_upload(uploadfile)) {
722           /* count to see if there are more than one auth bit set
723              in the authtype field */
724           int authbits = 0;
725           int bitcheck = 0;
726           while(bitcheck < 32) {
727             if(config->authtype & (1UL << bitcheck++)) {
728               authbits++;
729               if(authbits > 1) {
730                 /* more than one, we're done! */
731                 break;
732               }
733             }
734           }
735
736           /*
737            * If the user has also selected --anyauth or --proxy-anyauth
738            * we should warn him/her.
739            */
740           if(config->proxyanyauth || (authbits>1)) {
741             warnf(config,
742                   "Using --anyauth or --proxy-anyauth with upload from stdin"
743                   " involves a big risk of it not working. Use a temporary"
744                   " file or a fixed auth type instead!\n");
745           }
746
747           DEBUGASSERT(infdopen == FALSE);
748           DEBUGASSERT(infd == STDIN_FILENO);
749
750           set_binmode(stdin);
751           if(curlx_strequal(uploadfile, ".")) {
752             if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
753               warnf(config,
754                     "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
755           }
756         }
757
758         if(uploadfile && config->resume_from_current)
759           config->resume_from = -1; /* -1 will then force get-it-yourself */
760
761         if(output_expected(this_url, uploadfile)
762            && outs.stream && isatty(fileno(outs.stream)))
763           /* we send the output to a tty, therefore we switch off the progress
764              meter */
765           config->noprogress = config->isatty = TRUE;
766
767         if(urlnum > 1 && !(config->mute)) {
768           fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
769                   i+1, urlnum, this_url, outfile ? outfile : "<stdout>");
770           if(separator)
771             printf("%s%s\n", CURLseparator, this_url);
772         }
773         if(httpgetfields) {
774           char *urlbuffer;
775           /* Find out whether the url contains a file name */
776           const char *pc = strstr(this_url, "://");
777           char sep = '?';
778           if(pc)
779             pc += 3;
780           else
781             pc = this_url;
782
783           pc = strrchr(pc, '/'); /* check for a slash */
784
785           if(pc) {
786             /* there is a slash present in the URL */
787
788             if(strchr(pc, '?'))
789               /* Ouch, there's already a question mark in the URL string, we
790                  then append the data with an ampersand separator instead! */
791               sep='&';
792           }
793           /*
794            * Then append ? followed by the get fields to the url.
795            */
796           urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3);
797           if(!urlbuffer) {
798             res = CURLE_OUT_OF_MEMORY;
799             goto show_error;
800           }
801           if(pc)
802             sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields);
803           else
804             /* Append  / before the ? to create a well-formed url
805                if the url contains a hostname only
806             */
807             sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields);
808
809           Curl_safefree(this_url); /* free previous URL */
810           this_url = urlbuffer; /* use our new URL instead! */
811         }
812
813         if(!config->errors)
814           config->errors = stderr;
815
816         if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
817           /* We get the output to stdout and we have not got the ASCII/text
818              flag, then set stdout to be binary */
819           set_binmode(stdout);
820         }
821
822         if(config->tcp_nodelay)
823           my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
824
825         /* where to store */
826         my_setopt(curl, CURLOPT_WRITEDATA, &outs);
827         /* what call to write */
828         my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
829
830         /* for uploads */
831         input.fd = infd;
832         input.config = config;
833         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
834          * lib/telnet.c will Curl_poll() on the input file descriptor
835          * rather then calling the READFUNCTION at regular intervals.
836          * The circumstances in which it is preferable to enable this
837          * behaviour, by omitting to set the READFUNCTION & READDATA options,
838          * have not been determined.
839          */
840         my_setopt(curl, CURLOPT_READDATA, &input);
841         /* what call to read */
842         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
843
844         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
845            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
846         my_setopt(curl, CURLOPT_SEEKDATA, &input);
847         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
848
849         if(config->recvpersecond)
850           /* tell libcurl to use a smaller sized buffer as it allows us to
851              make better sleeps! 7.9.9 stuff! */
852           my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
853
854         /* size of uploaded file: */
855         if(uploadfilesize != -1)
856           my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
857         my_setopt_str(curl, CURLOPT_URL, this_url);     /* what to fetch */
858         my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
859         if(config->no_body) {
860           my_setopt(curl, CURLOPT_NOBODY, 1);
861           my_setopt(curl, CURLOPT_HEADER, 1);
862         }
863         else
864           my_setopt(curl, CURLOPT_HEADER, config->include_headers);
865
866 #if !defined(CURL_DISABLE_PROXY)
867         {
868           /* TODO: Make this a run-time check instead of compile-time one. */
869
870           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
871           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
872
873           /* new in libcurl 7.3 */
874           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
875
876           /* new in libcurl 7.5 */
877           if(config->proxy)
878             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
879
880           /* new in libcurl 7.10 */
881           if(config->socksproxy) {
882             my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
883             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->socksver);
884           }
885
886           /* new in libcurl 7.10.6 */
887           if(config->proxyanyauth)
888             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
889                               (long) CURLAUTH_ANY);
890           else if(config->proxynegotiate)
891             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
892                               (long) CURLAUTH_GSSNEGOTIATE);
893           else if(config->proxyntlm)
894             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
895                               (long) CURLAUTH_NTLM);
896           else if(config->proxydigest)
897             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
898                               (long) CURLAUTH_DIGEST);
899           else if(config->proxybasic)
900             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
901                               (long) CURLAUTH_BASIC);
902
903           /* new in libcurl 7.19.4 */
904           my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
905         }
906 #endif
907
908         my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
909         my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
910         my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
911         my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
912
913         if(config->netrc_opt)
914           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
915         else if(config->netrc || config->netrc_file)
916           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
917         else
918           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
919
920         if(config->netrc_file)
921           my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file);
922
923         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
924         my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
925         my_setopt_str(curl, CURLOPT_RANGE, config->range);
926         my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
927         my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
928
929         if(built_in_protos & CURLPROTO_HTTP) {
930
931           long postRedir = 0;
932
933           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
934                     config->followlocation);
935           my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
936                     config->unrestricted_auth);
937
938           switch(config->httpreq) {
939           case HTTPREQ_SIMPLEPOST:
940             my_setopt_str(curl, CURLOPT_POSTFIELDS,
941                           config->postfields);
942             my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
943                       config->postfieldsize);
944             break;
945           case HTTPREQ_POST:
946             my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
947             break;
948           default:
949             break;
950           }
951
952           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
953           my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
954           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
955           my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
956
957           /* new in libcurl 7.5 */
958           my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
959
960           /* new in libcurl 7.9.1 */
961           if(config->httpversion)
962             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
963
964           /* new in libcurl 7.10.6 (default is Basic) */
965           if(config->authtype)
966             my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long) config->authtype);
967
968           /* curl 7.19.1 (the 301 version existed in 7.18.2),
969              303 was added in 7.26.0 */
970           if(config->post301)
971             postRedir |= CURL_REDIR_POST_301;
972           if(config->post302)
973             postRedir |= CURL_REDIR_POST_302;
974           if(config->post303)
975             postRedir |= CURL_REDIR_POST_303;
976           my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
977
978           /* new in libcurl 7.21.6 */
979           if(config->encoding)
980             my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
981
982           /* new in libcurl 7.21.6 */
983           if(config->tr_encoding)
984             my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1);
985
986         } /* (built_in_protos & CURLPROTO_HTTP) */
987
988         my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
989         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
990                   config->low_speed_limit);
991         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
992         my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
993                   config->sendpersecond);
994         my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
995                   config->recvpersecond);
996         my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
997                   config->use_resume?config->resume_from:0);
998
999         my_setopt(curl, CURLOPT_SSLCERT, config->cert);
1000         my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
1001         my_setopt(curl, CURLOPT_SSLKEY, config->key);
1002         my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
1003         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
1004
1005         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
1006
1007           /* SSH and SSL private key uses same command-line option */
1008           /* new in libcurl 7.16.1 */
1009           my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
1010           /* new in libcurl 7.16.1 */
1011           my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
1012
1013           /* new in libcurl 7.17.1: SSH host key md5 checking allows us
1014              to fail if we are not talking to who we think we should */
1015           my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
1016                         config->hostpubmd5);
1017         }
1018
1019         if(config->cacert)
1020           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
1021         if(config->capath)
1022           my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
1023         if(config->crlfile)
1024           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
1025
1026         if(curlinfo->features & CURL_VERSION_SSL) {
1027           if(config->insecure_ok) {
1028             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1029             my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
1030           }
1031           else {
1032             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
1033             /* libcurl default is strict verifyhost -> 2L   */
1034             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
1035           }
1036         }
1037
1038         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
1039           if(!config->insecure_ok) {
1040             char *home;
1041             char *file;
1042             res = CURLE_OUT_OF_MEMORY;
1043             home = homedir();
1044             if(home) {
1045               file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
1046               if(file) {
1047                 /* new in curl 7.19.6 */
1048                 res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
1049                 curl_free(file);
1050                 if(res == CURLE_UNKNOWN_OPTION)
1051                   /* libssh2 version older than 1.1.1 */
1052                   res = CURLE_OK;
1053               }
1054               Curl_safefree(home);
1055             }
1056             if(res)
1057               goto show_error;
1058           }
1059         }
1060
1061         if(config->no_body || config->remote_time) {
1062           /* no body or use remote time */
1063           my_setopt(curl, CURLOPT_FILETIME, TRUE);
1064         }
1065
1066         my_setopt(curl, CURLOPT_CRLF, config->crlf);
1067         my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
1068         my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
1069         my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
1070
1071 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
1072         {
1073           /* TODO: Make this a run-time check instead of compile-time one. */
1074
1075           if(config->cookie)
1076             my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
1077
1078           if(config->cookiefile)
1079             my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
1080
1081           /* new in libcurl 7.9 */
1082           if(config->cookiejar)
1083             my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
1084
1085           /* new in libcurl 7.9.7 */
1086           my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
1087         }
1088 #endif
1089
1090         my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
1091         my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond);
1092         my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
1093         my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
1094         my_setopt(curl, CURLOPT_STDERR, config->errors);
1095
1096         /* three new ones in libcurl 7.3: */
1097         my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
1098         my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
1099
1100         progressbarinit(&progressbar, config);
1101         if((config->progressmode == CURL_PROGRESS_BAR) &&
1102            !config->noprogress && !config->mute) {
1103           /* we want the alternative style, then we have to implement it
1104              ourselves! */
1105           my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb);
1106           my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
1107         }
1108
1109         /* new in libcurl 7.6.2: */
1110         my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
1111
1112         /* new in libcurl 7.7: */
1113         my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
1114         my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
1115         my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
1116
1117         if(config->cipher_list)
1118           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
1119
1120         /* new in libcurl 7.9.2: */
1121         if(config->disable_epsv)
1122           /* disable it */
1123           my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
1124
1125         /* new in libcurl 7.10.5 */
1126         if(config->disable_eprt)
1127           /* disable it */
1128           my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
1129
1130         if(config->tracetype != TRACE_NONE) {
1131           my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
1132           my_setopt(curl, CURLOPT_DEBUGDATA, config);
1133           my_setopt(curl, CURLOPT_VERBOSE, TRUE);
1134         }
1135
1136         /* new in curl 7.9.3 */
1137         if(config->engine) {
1138           res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
1139           if(res)
1140             goto show_error;
1141           my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
1142         }
1143
1144         /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
1145         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
1146                   config->ftp_create_dirs);
1147
1148         /* new in curl 7.10.8 */
1149         if(config->max_filesize)
1150           my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
1151                     config->max_filesize);
1152
1153         if(4 == config->ip_version)
1154           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1155         else if(6 == config->ip_version)
1156           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
1157         else
1158           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
1159
1160         /* new in curl 7.15.5 */
1161         if(config->ftp_ssl_reqd)
1162           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
1163
1164         /* new in curl 7.11.0 */
1165         else if(config->ftp_ssl)
1166           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
1167
1168         /* new in curl 7.16.0 */
1169         else if(config->ftp_ssl_control)
1170           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
1171
1172         /* new in curl 7.16.1 */
1173         if(config->ftp_ssl_ccc)
1174           my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
1175
1176 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1177         {
1178           /* TODO: Make this a run-time check instead of compile-time one. */
1179
1180           /* new in curl 7.19.4 */
1181           if(config->socks5_gssapi_service)
1182             my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
1183                           config->socks5_gssapi_service);
1184
1185           /* new in curl 7.19.4 */
1186           if(config->socks5_gssapi_nec)
1187             my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
1188                           config->socks5_gssapi_nec);
1189         }
1190 #endif
1191         /* curl 7.13.0 */
1192         my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
1193
1194         my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
1195
1196         /* curl 7.14.2 */
1197         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
1198
1199         /* curl 7.15.1 */
1200         my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
1201
1202         /* curl 7.15.2 */
1203         if(config->localport) {
1204           my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
1205           my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
1206                         config->localportrange);
1207         }
1208
1209         /* curl 7.15.5 */
1210         my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
1211                       config->ftp_alternative_to_user);
1212
1213         /* curl 7.16.0 */
1214         if(config->disable_sessionid)
1215           my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
1216                     !config->disable_sessionid);
1217
1218         /* curl 7.16.2 */
1219         if(config->raw) {
1220           my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
1221           my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
1222         }
1223
1224         /* curl 7.17.1 */
1225         if(!config->nokeepalive) {
1226           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1227           if(config->alivetime != 0) {
1228 #if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL)
1229             warnf(config, "Keep-alive functionality somewhat crippled due to "
1230                 "missing support in your operating system!\n");
1231 #endif
1232             my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
1233             my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
1234           }
1235         }
1236         else
1237           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
1238
1239         /* curl 7.20.0 */
1240         if(config->tftp_blksize)
1241           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
1242
1243         if(config->mail_from)
1244           my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
1245
1246         if(config->mail_rcpt)
1247           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
1248
1249         /* curl 7.20.x */
1250         if(config->ftp_pret)
1251           my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
1252
1253         if(config->proto_present)
1254           my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
1255         if(config->proto_redir_present)
1256           my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
1257
1258         hdrdata.urlnode = urlnode;
1259         hdrdata.outs = &outs;
1260         hdrdata.heads = &heads;
1261
1262         my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
1263         my_setopt(curl, CURLOPT_HEADERDATA, &hdrdata);
1264
1265         if(config->resolve)
1266           /* new in 7.21.3 */
1267           my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
1268
1269         /* new in 7.21.4 */
1270         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
1271           if(config->tls_username)
1272             my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
1273                           config->tls_username);
1274           if(config->tls_password)
1275             my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
1276                           config->tls_password);
1277           if(config->tls_authtype)
1278             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
1279                           config->tls_authtype);
1280         }
1281
1282         /* new in 7.22.0 */
1283         if(config->gssapi_delegation)
1284           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
1285                         config->gssapi_delegation);
1286
1287         /* new in 7.25.0 */
1288         if(config->ssl_allow_beast)
1289           my_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST);
1290
1291         if(config->mail_auth)
1292           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
1293
1294         /* initialize retry vars for loop below */
1295         retry_sleep_default = (config->retry_delay) ?
1296           config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
1297
1298         retry_numretries = config->req_retry;
1299         retry_sleep = retry_sleep_default; /* ms */
1300         retrystart = tvnow();
1301
1302 #ifndef CURL_DISABLE_LIBCURL_OPTION
1303         res = easysrc_perform();
1304         if(res) {
1305           goto show_error;
1306         }
1307 #endif
1308
1309         for(;;) {
1310           res = curl_easy_perform(curl);
1311
1312           if(config->content_disposition && outs.stream && !config->mute &&
1313              outs.filename)
1314             printf("curl: Saved to filename '%s'\n", outs.filename);
1315
1316           /* if retry-max-time is non-zero, make sure we haven't exceeded the
1317              time */
1318           if(retry_numretries &&
1319              (!config->retry_maxtime ||
1320               (tvdiff(tvnow(), retrystart) <
1321                config->retry_maxtime*1000L)) ) {
1322             enum {
1323               RETRY_NO,
1324               RETRY_TIMEOUT,
1325               RETRY_HTTP,
1326               RETRY_FTP,
1327               RETRY_LAST /* not used */
1328             } retry = RETRY_NO;
1329             long response;
1330             if((CURLE_OPERATION_TIMEDOUT == res) ||
1331                (CURLE_COULDNT_RESOLVE_HOST == res) ||
1332                (CURLE_COULDNT_RESOLVE_PROXY == res) ||
1333                (CURLE_FTP_ACCEPT_TIMEOUT == res))
1334               /* retry timeout always */
1335               retry = RETRY_TIMEOUT;
1336             else if((CURLE_OK == res) ||
1337                     (config->failonerror &&
1338                      (CURLE_HTTP_RETURNED_ERROR == res))) {
1339               /* If it returned OK. _or_ failonerror was enabled and it
1340                  returned due to such an error, check for HTTP transient
1341                  errors to retry on. */
1342               char *effective_url = NULL;
1343               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
1344               if(effective_url &&
1345                  checkprefix("http", effective_url)) {
1346                 /* This was HTTP(S) */
1347                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
1348
1349                 switch(response) {
1350                 case 500: /* Internal Server Error */
1351                 case 502: /* Bad Gateway */
1352                 case 503: /* Service Unavailable */
1353                 case 504: /* Gateway Timeout */
1354                   retry = RETRY_HTTP;
1355                   /*
1356                    * At this point, we have already written data to the output
1357                    * file (or terminal). If we write to a file, we must rewind
1358                    * or close/re-open the file so that the next attempt starts
1359                    * over from the beginning.
1360                    *
1361                    * TODO: similar action for the upload case. We might need
1362                    * to start over reading from a previous point if we have
1363                    * uploaded something when this was returned.
1364                    */
1365                   break;
1366                 }
1367               }
1368             } /* if CURLE_OK */
1369             else if(res) {
1370               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
1371
1372               if(response/100 == 4)
1373                 /*
1374                  * This is typically when the FTP server only allows a certain
1375                  * amount of users and we are not one of them.  All 4xx codes
1376                  * are transient.
1377                  */
1378                 retry = RETRY_FTP;
1379             }
1380
1381             if(retry) {
1382               static const char * const m[]={
1383                 NULL, "timeout", "HTTP error", "FTP error"
1384               };
1385               warnf(config, "Transient problem: %s "
1386                     "Will retry in %ld seconds. "
1387                     "%ld retries left.\n",
1388                     m[retry], retry_sleep/1000L, retry_numretries);
1389
1390               tool_go_sleep(retry_sleep);
1391               retry_numretries--;
1392               if(!config->retry_delay) {
1393                 retry_sleep *= 2;
1394                 if(retry_sleep > RETRY_SLEEP_MAX)
1395                   retry_sleep = RETRY_SLEEP_MAX;
1396               }
1397               if(outs.bytes && outs.filename) {
1398                 /* We have written data to a output file, we truncate file
1399                  */
1400                 if(!config->mute)
1401                   fprintf(config->errors, "Throwing away %"
1402                           CURL_FORMAT_CURL_OFF_T " bytes\n",
1403                           outs.bytes);
1404                 fflush(outs.stream);
1405                 /* truncate file at the position where we started appending */
1406 #ifdef HAVE_FTRUNCATE
1407                 if(ftruncate( fileno(outs.stream), outs.init)) {
1408                   /* when truncate fails, we can't just append as then we'll
1409                      create something strange, bail out */
1410                   if(!config->mute)
1411                     fprintf(config->errors,
1412                             "failed to truncate, exiting\n");
1413                   res = CURLE_WRITE_ERROR;
1414                   goto quit_urls;
1415                 }
1416                 /* now seek to the end of the file, the position where we
1417                    just truncated the file in a large file-safe way */
1418                 fseek(outs.stream, 0, SEEK_END);
1419 #else
1420                 /* ftruncate is not available, so just reposition the file
1421                    to the location we would have truncated it. This won't
1422                    work properly with large files on 32-bit systems, but
1423                    most of those will have ftruncate. */
1424                 fseek(outs.stream, (long)outs.init, SEEK_SET);
1425 #endif
1426                 outs.bytes = 0; /* clear for next round */
1427               }
1428               continue; /* curl_easy_perform loop */
1429             }
1430           } /* if retry_numretries */
1431           else if(metalink) {
1432             /* Metalink: Decide to try the next resource or
1433                not. Basically, we want to try the next resource if
1434                download was not successful. */
1435             long response;
1436             if(CURLE_OK == res) {
1437               /* TODO We want to try next resource when download was
1438                  not successful. How to know that? */
1439               char *effective_url = NULL;
1440               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
1441               if(effective_url &&
1442                  curlx_strnequal(effective_url, "http", 4)) {
1443                 /* This was HTTP(S) */
1444                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
1445                 if(response != 200 && response != 206) {
1446                   metalink_next_res = 1;
1447                 }
1448               }
1449             }
1450             else
1451               metalink_next_res = 1;
1452           }
1453
1454           /* In all ordinary cases, just break out of loop here */
1455           break; /* curl_easy_perform loop */
1456
1457         }
1458
1459         if((config->progressmode == CURL_PROGRESS_BAR) &&
1460            progressbar.calls)
1461           /* if the custom progress bar has been displayed, we output a
1462              newline here */
1463           fputs("\n", progressbar.out);
1464
1465         if(config->writeout)
1466           ourWriteOut(curl, &outs, config->writeout);
1467
1468         if(config->writeenv)
1469           ourWriteEnv(curl);
1470
1471         /*
1472         ** Code within this loop may jump directly here to label 'show_error'
1473         ** in order to display an error message for CURLcode stored in 'res'
1474         ** variable and exit loop once that necessary writing and cleanup
1475         ** in label 'quit_urls' has been done.
1476         */
1477
1478         show_error:
1479
1480 #ifdef __VMS
1481         if(is_vms_shell()) {
1482           /* VMS DCL shell behavior */
1483           if(!config->showerror)
1484             vms_show = VMSSTS_HIDE;
1485         }
1486         else
1487 #endif
1488         if(res && config->showerror) {
1489           fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ?
1490                   errorbuffer : curl_easy_strerror((CURLcode)res));
1491           if(res == CURLE_SSL_CACERT)
1492             fprintf(config->errors, "%s%s",
1493                     CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
1494         }
1495
1496         /* Fall through comment to 'quit_urls' label */
1497
1498         /*
1499         ** Upon error condition and always that a message has already been
1500         ** displayed, code within this loop may jump directly here to label
1501         ** 'quit_urls' otherwise it should jump to 'show_error' label above.
1502         **
1503         ** When 'res' variable is _not_ CURLE_OK loop will exit once that
1504         ** all code following 'quit_urls' has been executed. Otherwise it
1505         ** will loop to the beginning from where it may exit if there are
1506         ** no more urls left.
1507         */
1508
1509         quit_urls:
1510
1511         /* Set file extended attributes */
1512         if(!res && config->xattr && outs.fopened && outs.stream) {
1513           int rc = fwrite_xattr(curl, fileno(outs.stream));
1514           if(rc)
1515             warnf(config, "Error setting extended attributes: %s\n",
1516                   strerror(errno));
1517         }
1518
1519         /* Close the file */
1520         if(outs.fopened && outs.stream) {
1521           int rc = fclose(outs.stream);
1522           if(!res && rc) {
1523             /* something went wrong in the writing process */
1524             res = CURLE_WRITE_ERROR;
1525             fprintf(config->errors, "(%d) Failed writing body\n", res);
1526           }
1527         }
1528         else if(!outs.s_isreg && outs.stream) {
1529           /* Dump standard stream buffered data */
1530           int rc = fflush(outs.stream);
1531           if(!res && rc) {
1532             /* something went wrong in the writing process */
1533             res = CURLE_WRITE_ERROR;
1534             fprintf(config->errors, "(%d) Failed writing body\n", res);
1535           }
1536         }
1537
1538 #ifdef __AMIGA__
1539         if(!res && outs.s_isreg && outs.filename) {
1540           /* Set the url (up to 80 chars) as comment for the file */
1541           if(strlen(url) > 78)
1542             url[79] = '\0';
1543           SetComment(outs.filename, url);
1544         }
1545 #endif
1546
1547 #ifdef HAVE_UTIME
1548         /* File time can only be set _after_ the file has been closed */
1549         if(!res && config->remote_time && outs.s_isreg && outs.filename) {
1550           /* Ask libcurl if we got a remote file time */
1551           long filetime = -1;
1552           curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
1553           if(filetime >= 0) {
1554             struct utimbuf times;
1555             times.actime = (time_t)filetime;
1556             times.modtime = (time_t)filetime;
1557             utime(outs.filename, &times); /* set the time we got */
1558           }
1559         }
1560 #endif
1561
1562 #ifdef HAVE_LIBMETALINK
1563         if(!metalink && res == CURLE_OK && outs.filename) {
1564           /* Check the content-type header field and if it indicates
1565              Metalink file, parse it and add getout for them. */
1566           char *content_type;
1567           curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
1568           if(content_type && check_metalink_content_type(content_type)) {
1569             if(!(config->mute)) {
1570               fprintf(config->errors, "\nParsing Metalink file: %s\n",
1571                       outs.filename);
1572             }
1573             if(parse_metalink(config, outs.filename) == 0)
1574               fprintf(config->errors,
1575                       "Metalink file is parsed successfully\n");
1576             else
1577               fprintf(config->errors, "Could not parse Metalink file.\n");
1578           }
1579         }
1580 #  ifdef METALINK_HASH_CHECK
1581         else if(metalink && res == CURLE_OK && !metalink_next_res) {
1582           int rv = metalink_check_hash(config, mlfile, outs.filename);
1583           if(rv == 0) {
1584             metalink_next_res = 1;
1585           }
1586         }
1587 #  endif /* METALINK_HASH_CHECK */
1588 #endif /* HAVE_LIBMETALINK */
1589
1590         /* No more business with this output struct */
1591         if(outs.alloc_filename)
1592           Curl_safefree(outs.filename);
1593         memset(&outs, 0, sizeof(struct OutStruct));
1594
1595         /* Free loop-local allocated memory and close loop-local opened fd */
1596
1597         Curl_safefree(outfile);
1598         Curl_safefree(this_url);
1599
1600         if(infdopen) {
1601           close(infd);
1602           infdopen = FALSE;
1603           infd = STDIN_FILENO;
1604         }
1605
1606         if(metalink) {
1607           /* Should exit if error is fatal. */
1608           if(is_fatal_error(res)) {
1609             break;
1610           }
1611           if(!metalink_next_res)
1612             break;
1613           mlres = mlres->next;
1614           if(mlres == NULL)
1615             /* TODO If metalink_next_res is 1 and mlres is NULL,
1616              * set res to error code
1617              */
1618             break;
1619         }
1620         else
1621         if(urlnum > 1) {
1622           /* when url globbing, exit loop upon critical error */
1623           if(is_fatal_error(res))
1624             break;
1625         }
1626         else if(res)
1627           /* when not url globbing, exit loop upon any error */
1628           break;
1629
1630       } /* loop to the next URL */
1631
1632       /* Free loop-local allocated memory */
1633
1634       Curl_safefree(uploadfile);
1635
1636       if(urls) {
1637         /* Free list of remaining URLs */
1638         glob_cleanup(urls);
1639         urls = NULL;
1640       }
1641
1642       if(infilenum > 1) {
1643         /* when file globbing, exit loop upon critical error */
1644         if(is_fatal_error(res))
1645           break;
1646       }
1647       else if(res)
1648         /* when not file globbing, exit loop upon any error */
1649         break;
1650
1651     } /* loop to the next globbed upload file */
1652
1653     /* Free loop-local allocated memory */
1654
1655     Curl_safefree(outfiles);
1656
1657     if(inglob) {
1658       /* Free list of globbed upload files */
1659       glob_cleanup(inglob);
1660       inglob = NULL;
1661     }
1662
1663     /* Free this URL node data without destroying the
1664        the node itself nor modifying next pointer. */
1665     Curl_safefree(urlnode->url);
1666     Curl_safefree(urlnode->outfile);
1667     Curl_safefree(urlnode->infile);
1668     urlnode->flags = 0;
1669
1670     /*
1671     ** Bail out upon critical errors
1672     */
1673     if(is_fatal_error(res))
1674       goto quit_curl;
1675
1676   } /* for-loop through all URLs */
1677
1678   /*
1679   ** Nested loops end here.
1680   */
1681
1682   quit_curl:
1683
1684   /* Free function-local referenced allocated memory */
1685   Curl_safefree(httpgetfields);
1686
1687   /* Free list of given URLs */
1688   clean_getout(config);
1689
1690   /* Cleanup the curl handle now that our
1691      progressbar struct is still in scope */
1692   if(curl) {
1693     curl_easy_cleanup(curl);
1694     config->easy = curl = NULL;
1695   }
1696 #ifndef CURL_DISABLE_LIBCURL_OPTION
1697   easysrc_cleanup();
1698 #endif
1699
1700   /* Close function-local opened file descriptors */
1701
1702   if(heads.fopened && heads.stream)
1703     fclose(heads.stream);
1704   if(heads.alloc_filename)
1705     Curl_safefree(heads.filename);
1706
1707   if(config->trace_fopened && config->trace_stream)
1708     fclose(config->trace_stream);
1709
1710 #ifndef CURL_DISABLE_LIBCURL_OPTION
1711   /* Dump the libcurl code if previously enabled.
1712      NOTE: that this function relies on config->errors amongst other things
1713      so not everything can be closed and cleaned before this is called */
1714   dumpeasysrc(config);
1715 #endif
1716
1717   if(config->errors_fopened && config->errors)
1718     fclose(config->errors);
1719
1720   /* Release metalink related resources here */
1721   clean_metalink(config);
1722
1723   main_free(); /* cleanup */
1724
1725   return res;
1726 }
1727