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