tool_operate.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "tool_setup.h"
00023 
00024 #ifdef HAVE_FCNTL_H
00025 #  include <fcntl.h>
00026 #endif
00027 
00028 #ifdef HAVE_UTIME_H
00029 #  include <utime.h>
00030 #elif defined(HAVE_SYS_UTIME_H)
00031 #  include <sys/utime.h>
00032 #endif
00033 
00034 #ifdef HAVE_LOCALE_H
00035 #  include <locale.h>
00036 #endif
00037 
00038 #ifdef HAVE_NETINET_TCP_H
00039 #  include <netinet/tcp.h>
00040 #endif
00041 
00042 #ifdef __VMS
00043 #  include <fabdef.h>
00044 #endif
00045 
00046 #include "strcase.h"
00047 
00048 #define ENABLE_CURLX_PRINTF
00049 /* use our own printf() functions */
00050 #include "curlx.h"
00051 
00052 #include "tool_binmode.h"
00053 #include "tool_cfgable.h"
00054 #include "tool_cb_dbg.h"
00055 #include "tool_cb_hdr.h"
00056 #include "tool_cb_prg.h"
00057 #include "tool_cb_rea.h"
00058 #include "tool_cb_see.h"
00059 #include "tool_cb_wrt.h"
00060 #include "tool_dirhie.h"
00061 #include "tool_doswin.h"
00062 #include "tool_easysrc.h"
00063 #include "tool_getparam.h"
00064 #include "tool_helpers.h"
00065 #include "tool_homedir.h"
00066 #include "tool_libinfo.h"
00067 #include "tool_main.h"
00068 #include "tool_metalink.h"
00069 #include "tool_msgs.h"
00070 #include "tool_operate.h"
00071 #include "tool_operhlp.h"
00072 #include "tool_paramhlp.h"
00073 #include "tool_parsecfg.h"
00074 #include "tool_setopt.h"
00075 #include "tool_sleep.h"
00076 #include "tool_urlglob.h"
00077 #include "tool_util.h"
00078 #include "tool_writeenv.h"
00079 #include "tool_writeout.h"
00080 #include "tool_xattr.h"
00081 #include "tool_vms.h"
00082 #include "tool_help.h"
00083 #include "tool_hugehelp.h"
00084 
00085 #include "memdebug.h" /* keep this as LAST include */
00086 
00087 #ifdef CURLDEBUG
00088 /* libcurl's debug builds provide an extra function */
00089 CURLcode curl_easy_perform_ev(CURL *easy);
00090 #endif
00091 
00092 #define CURLseparator  "--_curl_--"
00093 
00094 #ifndef O_BINARY
00095 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
00096    source code but yet it doesn't ruin anything */
00097 #  define O_BINARY 0
00098 #endif
00099 
00100 #define CURL_CA_CERT_ERRORMSG1                                              \
00101   "More details here: https://curl.haxx.se/docs/sslcerts.html\n\n"           \
00102   "curl performs SSL certificate verification by default, "                 \
00103   "using a \"bundle\"\n"                                                    \
00104   " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
00105   " bundle file isn't adequate, you can specify an alternate file\n"        \
00106   " using the --cacert option.\n"
00107 
00108 #define CURL_CA_CERT_ERRORMSG2                                              \
00109   "If this HTTPS server uses a certificate signed by a CA represented in\n" \
00110   " the bundle, the certificate verification probably failed due to a\n"    \
00111   " problem with the certificate (it might be expired, or the name might\n" \
00112   " not match the domain name in the URL).\n"                               \
00113   "If you'd like to turn off curl's verification of the certificate, use\n" \
00114   " the -k (or --insecure) option.\n"
00115 
00116 static bool is_fatal_error(CURLcode code)
00117 {
00118   switch(code) {
00119   /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
00120   case CURLE_FAILED_INIT:
00121   case CURLE_OUT_OF_MEMORY:
00122   case CURLE_UNKNOWN_OPTION:
00123   case CURLE_FUNCTION_NOT_FOUND:
00124   case CURLE_BAD_FUNCTION_ARGUMENT:
00125     /* critical error */
00126     return TRUE;
00127   default:
00128     break;
00129   }
00130 
00131   /* no error or not critical */
00132   return FALSE;
00133 }
00134 
00135 #ifdef __VMS
00136 /*
00137  * get_vms_file_size does what it takes to get the real size of the file
00138  *
00139  * For fixed files, find out the size of the EOF block and adjust.
00140  *
00141  * For all others, have to read the entire file in, discarding the contents.
00142  * Most posted text files will be small, and binary files like zlib archives
00143  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
00144  *
00145  */
00146 static curl_off_t vms_realfilesize(const char *name,
00147                                    const struct_stat *stat_buf)
00148 {
00149   char buffer[8192];
00150   curl_off_t count;
00151   int ret_stat;
00152   FILE * file;
00153 
00154   /* !checksrc! disable FOPENMODE 1 */
00155   file = fopen(name, "r"); /* VMS */
00156   if(file == NULL) {
00157     return 0;
00158   }
00159   count = 0;
00160   ret_stat = 1;
00161   while(ret_stat > 0) {
00162     ret_stat = fread(buffer, 1, sizeof(buffer), file);
00163     if(ret_stat != 0)
00164       count += ret_stat;
00165   }
00166   fclose(file);
00167 
00168   return count;
00169 }
00170 
00171 /*
00172  *
00173  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
00174  *  if not to call a routine to get the correct size.
00175  *
00176  */
00177 static curl_off_t VmsSpecialSize(const char *name,
00178                                  const struct_stat *stat_buf)
00179 {
00180   switch(stat_buf->st_fab_rfm) {
00181   case FAB$C_VAR:
00182   case FAB$C_VFC:
00183     return vms_realfilesize(name, stat_buf);
00184     break;
00185   default:
00186     return stat_buf->st_size;
00187   }
00188 }
00189 #endif /* __VMS */
00190 
00191 static CURLcode operate_do(struct GlobalConfig *global,
00192                            struct OperationConfig *config)
00193 {
00194   char errorbuffer[CURL_ERROR_SIZE];
00195   struct ProgressData progressbar;
00196   struct getout *urlnode;
00197 
00198   struct HdrCbData hdrcbdata;
00199   struct OutStruct heads;
00200 
00201   metalinkfile *mlfile_last = NULL;
00202 
00203   CURL *curl = config->easy;
00204   char *httpgetfields = NULL;
00205 
00206   CURLcode result = CURLE_OK;
00207   unsigned long li;
00208   bool capath_from_env;
00209 
00210   /* Save the values of noprogress and isatty to restore them later on */
00211   bool orig_noprogress = global->noprogress;
00212   bool orig_isatty = global->isatty;
00213 
00214   errorbuffer[0] = '\0';
00215 
00216   /* default headers output stream is stdout */
00217   memset(&hdrcbdata, 0, sizeof(struct HdrCbData));
00218   memset(&heads, 0, sizeof(struct OutStruct));
00219   heads.stream = stdout;
00220   heads.config = config;
00221 
00222   /*
00223   ** Beyond this point no return'ing from this function allowed.
00224   ** Jump to label 'quit_curl' in order to abandon this function
00225   ** from outside of nested loops further down below.
00226   */
00227 
00228   /* Check we have a url */
00229   if(!config->url_list || !config->url_list->url) {
00230     helpf(global->errors, "no URL specified!\n");
00231     result = CURLE_FAILED_INIT;
00232     goto quit_curl;
00233   }
00234 
00235   /* On WIN32 we can't set the path to curl-ca-bundle.crt
00236    * at compile time. So we look here for the file in two ways:
00237    * 1: look at the environment variable CURL_CA_BUNDLE for a path
00238    * 2: if #1 isn't found, use the windows API function SearchPath()
00239    *    to find it along the app's path (includes app's dir and CWD)
00240    *
00241    * We support the environment variable thing for non-Windows platforms
00242    * too. Just for the sake of it.
00243    */
00244   capath_from_env = false;
00245   if(!config->cacert &&
00246      !config->capath &&
00247      !config->insecure_ok) {
00248     char *env;
00249     env = curlx_getenv("CURL_CA_BUNDLE");
00250     if(env) {
00251       config->cacert = strdup(env);
00252       if(!config->cacert) {
00253         curl_free(env);
00254         helpf(global->errors, "out of memory\n");
00255         result = CURLE_OUT_OF_MEMORY;
00256         goto quit_curl;
00257       }
00258     }
00259     else {
00260       env = curlx_getenv("SSL_CERT_DIR");
00261       if(env) {
00262         config->capath = strdup(env);
00263         if(!config->capath) {
00264           curl_free(env);
00265           helpf(global->errors, "out of memory\n");
00266           result = CURLE_OUT_OF_MEMORY;
00267           goto quit_curl;
00268         }
00269         capath_from_env = true;
00270       }
00271       else {
00272         env = curlx_getenv("SSL_CERT_FILE");
00273         if(env) {
00274           config->cacert = strdup(env);
00275           if(!config->cacert) {
00276             curl_free(env);
00277             helpf(global->errors, "out of memory\n");
00278             result = CURLE_OUT_OF_MEMORY;
00279             goto quit_curl;
00280           }
00281         }
00282       }
00283     }
00284 
00285     if(env)
00286       curl_free(env);
00287 #ifdef WIN32
00288     else {
00289       result = FindWin32CACert(config, "curl-ca-bundle.crt");
00290       if(result)
00291         goto quit_curl;
00292     }
00293 #endif
00294   }
00295 
00296   if(config->postfields) {
00297     if(config->use_httpget) {
00298       /* Use the postfields data for a http get */
00299       httpgetfields = strdup(config->postfields);
00300       Curl_safefree(config->postfields);
00301       if(!httpgetfields) {
00302         helpf(global->errors, "out of memory\n");
00303         result = CURLE_OUT_OF_MEMORY;
00304         goto quit_curl;
00305       }
00306       if(SetHTTPrequest(config,
00307                         (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
00308                         &config->httpreq)) {
00309         result = CURLE_FAILED_INIT;
00310         goto quit_curl;
00311       }
00312     }
00313     else {
00314       if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
00315         result = CURLE_FAILED_INIT;
00316         goto quit_curl;
00317       }
00318     }
00319   }
00320 
00321   /* Single header file for all URLs */
00322   if(config->headerfile) {
00323     /* open file for output: */
00324     if(strcmp(config->headerfile, "-")) {
00325       FILE *newfile = fopen(config->headerfile, "wb");
00326       if(!newfile) {
00327         warnf(config->global, "Failed to open %s\n", config->headerfile);
00328         result = CURLE_WRITE_ERROR;
00329         goto quit_curl;
00330       }
00331       else {
00332         heads.filename = config->headerfile;
00333         heads.s_isreg = TRUE;
00334         heads.fopened = TRUE;
00335         heads.stream = newfile;
00336       }
00337     }
00338     else {
00339       /* always use binary mode for protocol header output */
00340       set_binmode(heads.stream);
00341     }
00342   }
00343 
00344   /*
00345   ** Nested loops start here.
00346   */
00347 
00348   /* loop through the list of given URLs */
00349 
00350   for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
00351 
00352     unsigned long up; /* upload file counter within a single upload glob */
00353     char *infiles; /* might be a glob pattern */
00354     char *outfiles;
00355     unsigned long infilenum;
00356     URLGlob *inglob;
00357 
00358     int metalink = 0; /* nonzero for metalink download. */
00359     metalinkfile *mlfile;
00360     metalink_resource *mlres;
00361 
00362     outfiles = NULL;
00363     infilenum = 1;
00364     inglob = NULL;
00365 
00366     if(urlnode->flags & GETOUT_METALINK) {
00367       metalink = 1;
00368       if(mlfile_last == NULL) {
00369         mlfile_last = config->metalinkfile_list;
00370       }
00371       mlfile = mlfile_last;
00372       mlfile_last = mlfile_last->next;
00373       mlres = mlfile->resource;
00374     }
00375     else {
00376       mlfile = NULL;
00377       mlres = NULL;
00378     }
00379 
00380     /* urlnode->url is the full URL (it might be NULL) */
00381 
00382     if(!urlnode->url) {
00383       /* This node has no URL. Free node data without destroying the
00384          node itself nor modifying next pointer and continue to next */
00385       Curl_safefree(urlnode->outfile);
00386       Curl_safefree(urlnode->infile);
00387       urlnode->flags = 0;
00388       continue; /* next URL please */
00389     }
00390 
00391     /* save outfile pattern before expansion */
00392     if(urlnode->outfile) {
00393       outfiles = strdup(urlnode->outfile);
00394       if(!outfiles) {
00395         helpf(global->errors, "out of memory\n");
00396         result = CURLE_OUT_OF_MEMORY;
00397         break;
00398       }
00399     }
00400 
00401     infiles = urlnode->infile;
00402 
00403     if(!config->globoff && infiles) {
00404       /* Unless explicitly shut off */
00405       result = glob_url(&inglob, infiles, &infilenum,
00406                         global->showerror?global->errors:NULL);
00407       if(result) {
00408         Curl_safefree(outfiles);
00409         break;
00410       }
00411     }
00412 
00413     /* Here's the loop for uploading multiple files within the same
00414        single globbed string. If no upload, we enter the loop once anyway. */
00415     for(up = 0 ; up < infilenum; up++) {
00416 
00417       char *uploadfile; /* a single file, never a glob */
00418       int separator;
00419       URLGlob *urls;
00420       unsigned long urlnum;
00421 
00422       uploadfile = NULL;
00423       urls = NULL;
00424       urlnum = 0;
00425 
00426       if(!up && !infiles)
00427         Curl_nop_stmt;
00428       else {
00429         if(inglob) {
00430           result = glob_next_url(&uploadfile, inglob);
00431           if(result == CURLE_OUT_OF_MEMORY)
00432             helpf(global->errors, "out of memory\n");
00433         }
00434         else if(!up) {
00435           uploadfile = strdup(infiles);
00436           if(!uploadfile) {
00437             helpf(global->errors, "out of memory\n");
00438             result = CURLE_OUT_OF_MEMORY;
00439           }
00440         }
00441         else
00442           uploadfile = NULL;
00443         if(!uploadfile)
00444           break;
00445       }
00446 
00447       if(metalink) {
00448         /* For Metalink download, we don't use glob. Instead we use
00449            the number of resources as urlnum. */
00450         urlnum = count_next_metalink_resource(mlfile);
00451       }
00452       else
00453       if(!config->globoff) {
00454         /* Unless explicitly shut off, we expand '{...}' and '[...]'
00455            expressions and return total number of URLs in pattern set */
00456         result = glob_url(&urls, urlnode->url, &urlnum,
00457                           global->showerror?global->errors:NULL);
00458         if(result) {
00459           Curl_safefree(uploadfile);
00460           break;
00461         }
00462       }
00463       else
00464         urlnum = 1; /* without globbing, this is a single URL */
00465 
00466       /* if multiple files extracted to stdout, insert separators! */
00467       separator= ((!outfiles || !strcmp(outfiles, "-")) && urlnum > 1);
00468 
00469       /* Here's looping around each globbed URL */
00470       for(li = 0 ; li < urlnum; li++) {
00471 
00472         int infd;
00473         bool infdopen;
00474         char *outfile;
00475         struct OutStruct outs;
00476         struct InStruct input;
00477         struct timeval retrystart;
00478         curl_off_t uploadfilesize;
00479         long retry_numretries;
00480         long retry_sleep_default;
00481         long retry_sleep;
00482         char *this_url = NULL;
00483         int metalink_next_res = 0;
00484 
00485         outfile = NULL;
00486         infdopen = FALSE;
00487         infd = STDIN_FILENO;
00488         uploadfilesize = -1; /* -1 means unknown */
00489 
00490         /* default output stream is stdout */
00491         memset(&outs, 0, sizeof(struct OutStruct));
00492         outs.stream = stdout;
00493         outs.config = config;
00494 
00495         if(metalink) {
00496           /* For Metalink download, use name in Metalink file as
00497              filename. */
00498           outfile = strdup(mlfile->filename);
00499           if(!outfile) {
00500             result = CURLE_OUT_OF_MEMORY;
00501             goto show_error;
00502           }
00503           this_url = strdup(mlres->url);
00504           if(!this_url) {
00505             result = CURLE_OUT_OF_MEMORY;
00506             goto show_error;
00507           }
00508         }
00509         else {
00510           if(urls) {
00511             result = glob_next_url(&this_url, urls);
00512             if(result)
00513               goto show_error;
00514           }
00515           else if(!li) {
00516             this_url = strdup(urlnode->url);
00517             if(!this_url) {
00518               result = CURLE_OUT_OF_MEMORY;
00519               goto show_error;
00520             }
00521           }
00522           else
00523             this_url = NULL;
00524           if(!this_url)
00525             break;
00526 
00527           if(outfiles) {
00528             outfile = strdup(outfiles);
00529             if(!outfile) {
00530               result = CURLE_OUT_OF_MEMORY;
00531               goto show_error;
00532             }
00533           }
00534         }
00535 
00536         if(((urlnode->flags&GETOUT_USEREMOTE) ||
00537             (outfile && strcmp("-", outfile))) &&
00538            (metalink || !config->use_metalink)) {
00539 
00540           /*
00541            * We have specified a file name to store the result in, or we have
00542            * decided we want to use the remote file name.
00543            */
00544 
00545           if(!outfile) {
00546             /* extract the file name from the URL */
00547             result = get_url_file_name(&outfile, this_url);
00548             if(result)
00549               goto show_error;
00550             if(!*outfile && !config->content_disposition) {
00551               helpf(global->errors, "Remote file name has no length!\n");
00552               result = CURLE_WRITE_ERROR;
00553               goto quit_urls;
00554             }
00555           }
00556           else if(urls) {
00557             /* fill '#1' ... '#9' terms from URL pattern */
00558             char *storefile = outfile;
00559             result = glob_match_url(&outfile, storefile, urls);
00560             Curl_safefree(storefile);
00561             if(result) {
00562               /* bad globbing */
00563               warnf(config->global, "bad output glob!\n");
00564               goto quit_urls;
00565             }
00566           }
00567 
00568           /* Create the directory hierarchy, if not pre-existent to a multiple
00569              file output call */
00570 
00571           if(config->create_dirs || metalink) {
00572             result = create_dir_hierarchy(outfile, global->errors);
00573             /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
00574             if(result == CURLE_WRITE_ERROR)
00575               goto quit_urls;
00576             if(result) {
00577               goto show_error;
00578             }
00579           }
00580 
00581           if((urlnode->flags & GETOUT_USEREMOTE)
00582              && config->content_disposition) {
00583             /* Our header callback MIGHT set the filename */
00584             DEBUGASSERT(!outs.filename);
00585           }
00586 
00587           if(config->resume_from_current) {
00588             /* We're told to continue from where we are now. Get the size
00589                of the file as it is now and open it for append instead */
00590             struct_stat fileinfo;
00591             /* VMS -- Danger, the filesize is only valid for stream files */
00592             if(0 == stat(outfile, &fileinfo))
00593               /* set offset to current file size: */
00594               config->resume_from = fileinfo.st_size;
00595             else
00596               /* let offset be 0 */
00597               config->resume_from = 0;
00598           }
00599 
00600           if(config->resume_from) {
00601 #ifdef __VMS
00602             /* open file for output, forcing VMS output format into stream
00603                mode which is needed for stat() call above to always work. */
00604             FILE *file = fopen(outfile, config->resume_from?"ab":"wb",
00605                                "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
00606 #else
00607             /* open file for output: */
00608             FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
00609 #endif
00610             if(!file) {
00611               helpf(global->errors, "Can't open '%s'!\n", outfile);
00612               result = CURLE_WRITE_ERROR;
00613               goto quit_urls;
00614             }
00615             outs.fopened = TRUE;
00616             outs.stream = file;
00617             outs.init = config->resume_from;
00618           }
00619           else {
00620             outs.stream = NULL; /* open when needed */
00621           }
00622           outs.filename = outfile;
00623           outs.s_isreg = TRUE;
00624         }
00625 
00626         if(uploadfile && !stdin_upload(uploadfile)) {
00627           /*
00628            * We have specified a file to upload and it isn't "-".
00629            */
00630           struct_stat fileinfo;
00631 
00632           this_url = add_file_name_to_url(curl, this_url, uploadfile);
00633           if(!this_url) {
00634             result = CURLE_OUT_OF_MEMORY;
00635             goto show_error;
00636           }
00637           /* VMS Note:
00638            *
00639            * Reading binary from files can be a problem...  Only FIXED, VAR
00640            * etc WITHOUT implied CC will work Others need a \n appended to a
00641            * line
00642            *
00643            * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
00644            * fixed file with implied CC needs to have a byte added for every
00645            * record processed, this can by derived from Filesize & recordsize
00646            * for VARiable record files the records need to be counted!  for
00647            * every record add 1 for linefeed and subtract 2 for the record
00648            * header for VARIABLE header files only the bare record data needs
00649            * to be considered with one appended if implied CC
00650            */
00651 #ifdef __VMS
00652           /* Calculate the real upload site for VMS */
00653           infd = -1;
00654           if(stat(uploadfile, &fileinfo) == 0) {
00655             fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
00656             switch(fileinfo.st_fab_rfm) {
00657             case FAB$C_VAR:
00658             case FAB$C_VFC:
00659             case FAB$C_STMCR:
00660               infd = open(uploadfile, O_RDONLY | O_BINARY);
00661               break;
00662             default:
00663               infd = open(uploadfile, O_RDONLY | O_BINARY,
00664                           "rfm=stmlf", "ctx=stm");
00665             }
00666           }
00667           if(infd == -1)
00668 #else
00669           infd = open(uploadfile, O_RDONLY | O_BINARY);
00670           if((infd == -1) || fstat(infd, &fileinfo))
00671 #endif
00672           {
00673             helpf(global->errors, "Can't open '%s'!\n", uploadfile);
00674             if(infd != -1) {
00675               close(infd);
00676               infd = STDIN_FILENO;
00677             }
00678             result = CURLE_READ_ERROR;
00679             goto quit_urls;
00680           }
00681           infdopen = TRUE;
00682 
00683           /* we ignore file size for char/block devices, sockets, etc. */
00684           if(S_ISREG(fileinfo.st_mode))
00685             uploadfilesize = fileinfo.st_size;
00686 
00687         }
00688         else if(uploadfile && stdin_upload(uploadfile)) {
00689           /* count to see if there are more than one auth bit set
00690              in the authtype field */
00691           int authbits = 0;
00692           int bitcheck = 0;
00693           while(bitcheck < 32) {
00694             if(config->authtype & (1UL << bitcheck++)) {
00695               authbits++;
00696               if(authbits > 1) {
00697                 /* more than one, we're done! */
00698                 break;
00699               }
00700             }
00701           }
00702 
00703           /*
00704            * If the user has also selected --anyauth or --proxy-anyauth
00705            * we should warn him/her.
00706            */
00707           if(config->proxyanyauth || (authbits>1)) {
00708             warnf(config->global,
00709                   "Using --anyauth or --proxy-anyauth with upload from stdin"
00710                   " involves a big risk of it not working. Use a temporary"
00711                   " file or a fixed auth type instead!\n");
00712           }
00713 
00714           DEBUGASSERT(infdopen == FALSE);
00715           DEBUGASSERT(infd == STDIN_FILENO);
00716 
00717           set_binmode(stdin);
00718           if(!strcmp(uploadfile, ".")) {
00719             if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
00720               warnf(config->global,
00721                     "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
00722           }
00723         }
00724 
00725         if(uploadfile && config->resume_from_current)
00726           config->resume_from = -1; /* -1 will then force get-it-yourself */
00727 
00728         if(output_expected(this_url, uploadfile) && outs.stream &&
00729            isatty(fileno(outs.stream)))
00730           /* we send the output to a tty, therefore we switch off the progress
00731              meter */
00732           global->noprogress = global->isatty = TRUE;
00733         else {
00734           /* progress meter is per download, so restore config
00735              values */
00736           global->noprogress = orig_noprogress;
00737           global->isatty = orig_isatty;
00738         }
00739 
00740         if(urlnum > 1 && !global->mute) {
00741           fprintf(global->errors, "\n[%lu/%lu]: %s --> %s\n",
00742                   li+1, urlnum, this_url, outfile ? outfile : "<stdout>");
00743           if(separator)
00744             printf("%s%s\n", CURLseparator, this_url);
00745         }
00746         if(httpgetfields) {
00747           char *urlbuffer;
00748           /* Find out whether the url contains a file name */
00749           const char *pc = strstr(this_url, "://");
00750           char sep = '?';
00751           if(pc)
00752             pc += 3;
00753           else
00754             pc = this_url;
00755 
00756           pc = strrchr(pc, '/'); /* check for a slash */
00757 
00758           if(pc) {
00759             /* there is a slash present in the URL */
00760 
00761             if(strchr(pc, '?'))
00762               /* Ouch, there's already a question mark in the URL string, we
00763                  then append the data with an ampersand separator instead! */
00764               sep='&';
00765           }
00766           /*
00767            * Then append ? followed by the get fields to the url.
00768            */
00769           if(pc)
00770             urlbuffer = aprintf("%s%c%s", this_url, sep, httpgetfields);
00771           else
00772             /* Append  / before the ? to create a well-formed url
00773                if the url contains a hostname only
00774             */
00775             urlbuffer = aprintf("%s/?%s", this_url, httpgetfields);
00776 
00777           if(!urlbuffer) {
00778             result = CURLE_OUT_OF_MEMORY;
00779             goto show_error;
00780           }
00781 
00782           Curl_safefree(this_url); /* free previous URL */
00783           this_url = urlbuffer; /* use our new URL instead! */
00784         }
00785 
00786         if(!global->errors)
00787           global->errors = stderr;
00788 
00789         if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
00790           /* We get the output to stdout and we have not got the ASCII/text
00791              flag, then set stdout to be binary */
00792           set_binmode(stdout);
00793         }
00794 
00795         if(!config->tcp_nodelay)
00796           my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
00797 
00798         if(config->tcp_fastopen)
00799           my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
00800 
00801         /* where to store */
00802         my_setopt(curl, CURLOPT_WRITEDATA, &outs);
00803         my_setopt(curl, CURLOPT_INTERLEAVEDATA, &outs);
00804         if(metalink || !config->use_metalink)
00805           /* what call to write */
00806           my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
00807 #ifdef USE_METALINK
00808         else
00809           /* Set Metalink specific write callback function to parse
00810              XML data progressively. */
00811           my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
00812 #endif /* USE_METALINK */
00813 
00814         /* for uploads */
00815         input.fd = infd;
00816         input.config = config;
00817         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
00818          * lib/telnet.c will Curl_poll() on the input file descriptor
00819          * rather then calling the READFUNCTION at regular intervals.
00820          * The circumstances in which it is preferable to enable this
00821          * behaviour, by omitting to set the READFUNCTION & READDATA options,
00822          * have not been determined.
00823          */
00824         my_setopt(curl, CURLOPT_READDATA, &input);
00825         /* what call to read */
00826         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
00827 
00828         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
00829            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
00830         my_setopt(curl, CURLOPT_SEEKDATA, &input);
00831         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
00832 
00833         if(config->recvpersecond)
00834           /* tell libcurl to use a smaller sized buffer as it allows us to
00835              make better sleeps! 7.9.9 stuff! */
00836           my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
00837 
00838         /* size of uploaded file: */
00839         if(uploadfilesize != -1)
00840           my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
00841         my_setopt_str(curl, CURLOPT_URL, this_url);     /* what to fetch */
00842         my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L);
00843         if(config->no_body) {
00844           my_setopt(curl, CURLOPT_NOBODY, 1L);
00845           my_setopt(curl, CURLOPT_HEADER, 1L);
00846         }
00847         /* If --metalink is used, we ignore --include (headers in
00848            output) option because mixing headers to the body will
00849            confuse XML parser and/or hash check will fail. */
00850         else if(!config->use_metalink)
00851           my_setopt(curl, CURLOPT_HEADER, config->include_headers?1L:0L);
00852 
00853         if(config->oauth_bearer)
00854           my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
00855 
00856 #if !defined(CURL_DISABLE_PROXY)
00857         {
00858           /* TODO: Make this a run-time check instead of compile-time one. */
00859 
00860           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
00861           /* new in libcurl 7.5 */
00862           if(config->proxy)
00863             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
00864 
00865           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
00866 
00867           /* new in libcurl 7.3 */
00868           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
00869 
00870           /* new in libcurl 7.52.0 */
00871           if(config->preproxy)
00872             my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
00873 
00874           /* new in libcurl 7.10.6 */
00875           if(config->proxyanyauth)
00876             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
00877                               (long)CURLAUTH_ANY);
00878           else if(config->proxynegotiate)
00879             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
00880                               (long)CURLAUTH_GSSNEGOTIATE);
00881           else if(config->proxyntlm)
00882             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
00883                               (long)CURLAUTH_NTLM);
00884           else if(config->proxydigest)
00885             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
00886                               (long)CURLAUTH_DIGEST);
00887           else if(config->proxybasic)
00888             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
00889                               (long)CURLAUTH_BASIC);
00890 
00891           /* new in libcurl 7.19.4 */
00892           my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
00893         }
00894 #endif
00895 
00896         my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L);
00897         my_setopt(curl, CURLOPT_UPLOAD, uploadfile?1L:0L);
00898         my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L);
00899         my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L);
00900 
00901         if(config->netrc_opt)
00902           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
00903         else if(config->netrc || config->netrc_file)
00904           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
00905         else
00906           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED);
00907 
00908         if(config->netrc_file)
00909           my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
00910 
00911         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L);
00912         if(config->login_options)
00913           my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
00914         my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
00915         my_setopt_str(curl, CURLOPT_RANGE, config->range);
00916         my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
00917         my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000));
00918 
00919         if(built_in_protos & CURLPROTO_HTTP) {
00920 
00921           long postRedir = 0;
00922 
00923           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
00924                     config->followlocation?1L:0L);
00925           my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
00926                     config->unrestricted_auth?1L:0L);
00927 
00928           switch(config->httpreq) {
00929           case HTTPREQ_SIMPLEPOST:
00930             my_setopt_str(curl, CURLOPT_POSTFIELDS,
00931                           config->postfields);
00932             my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
00933                       config->postfieldsize);
00934             break;
00935           case HTTPREQ_FORMPOST:
00936             my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
00937             break;
00938           default:
00939             break;
00940           }
00941 
00942           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
00943           my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L);
00944           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
00945           my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
00946 
00947           /* new in libcurl 7.36.0 */
00948           if(config->proxyheaders) {
00949             my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
00950             my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
00951           }
00952 
00953           /* new in libcurl 7.5 */
00954           my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
00955 
00956           if(config->httpversion)
00957             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
00958           else if(curlinfo->features & CURL_VERSION_HTTP2) {
00959             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
00960           }
00961 
00962           /* new in libcurl 7.10.6 (default is Basic) */
00963           if(config->authtype)
00964             my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);
00965 
00966           /* curl 7.19.1 (the 301 version existed in 7.18.2),
00967              303 was added in 7.26.0 */
00968           if(config->post301)
00969             postRedir |= CURL_REDIR_POST_301;
00970           if(config->post302)
00971             postRedir |= CURL_REDIR_POST_302;
00972           if(config->post303)
00973             postRedir |= CURL_REDIR_POST_303;
00974           my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
00975 
00976           /* new in libcurl 7.21.6 */
00977           if(config->encoding)
00978             my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
00979 
00980           /* new in libcurl 7.21.6 */
00981           if(config->tr_encoding)
00982             my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
00983 
00984         } /* (built_in_protos & CURLPROTO_HTTP) */
00985 
00986         my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
00987         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
00988                   config->low_speed_limit);
00989         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
00990         my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
00991                   config->sendpersecond);
00992         my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
00993                   config->recvpersecond);
00994 
00995         if(config->use_resume)
00996           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
00997         else
00998           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
00999 
01000         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
01001         my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
01002 
01003         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
01004 
01005           /* SSH and SSL private key uses same command-line option */
01006           /* new in libcurl 7.16.1 */
01007           my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
01008           /* new in libcurl 7.16.1 */
01009           my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
01010 
01011           /* new in libcurl 7.17.1: SSH host key md5 checking allows us
01012              to fail if we are not talking to who we think we should */
01013           my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
01014                         config->hostpubmd5);
01015         }
01016 
01017         if(config->cacert)
01018           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
01019         if(config->proxy_cacert)
01020           my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
01021         if(config->capath) {
01022           result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
01023           if(result == CURLE_NOT_BUILT_IN) {
01024             warnf(config->global, "ignoring %s, not supported by libcurl\n",
01025                   capath_from_env?
01026                   "SSL_CERT_DIR environment variable":"--capath");
01027           }
01028           else if(result)
01029             goto show_error;
01030         }
01031         if(config->proxy_capath)
01032           my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->proxy_capath);
01033         else if(config->capath) /* CURLOPT_PROXY_CAPATH default is capath */
01034           my_setopt_str(curl, CURLOPT_PROXY_CAPATH, config->capath);
01035 
01036         if(config->crlfile)
01037           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
01038         if(config->proxy_crlfile)
01039           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
01040         else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
01041           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
01042 
01043         if(config->pinnedpubkey)
01044           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
01045 
01046         if(curlinfo->features & CURL_VERSION_SSL) {
01047           my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
01048           my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
01049           my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
01050           my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
01051                         config->proxy_cert_type);
01052           my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
01053           my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
01054           my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
01055           my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
01056                         config->proxy_key_type);
01057 
01058           if(config->insecure_ok) {
01059             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
01060             my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
01061           }
01062           else {
01063             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
01064             /* libcurl default is strict verifyhost -> 2L   */
01065             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
01066           }
01067           if(config->proxy_insecure_ok) {
01068             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
01069             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
01070           }
01071           else {
01072             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
01073           }
01074 
01075           if(config->verifystatus)
01076             my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
01077 
01078           if(config->falsestart)
01079             my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
01080 
01081           my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
01082           my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
01083                          config->proxy_ssl_version);
01084         }
01085         if(config->path_as_is)
01086           my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
01087 
01088         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
01089           if(!config->insecure_ok) {
01090             char *home;
01091             char *file;
01092             result = CURLE_OUT_OF_MEMORY;
01093             home = homedir();
01094             if(home) {
01095               file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
01096               if(file) {
01097                 /* new in curl 7.19.6 */
01098                 result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
01099                 curl_free(file);
01100                 if(result == CURLE_UNKNOWN_OPTION)
01101                   /* libssh2 version older than 1.1.1 */
01102                   result = CURLE_OK;
01103               }
01104               Curl_safefree(home);
01105             }
01106             if(result)
01107               goto show_error;
01108           }
01109         }
01110 
01111         if(config->no_body || config->remote_time) {
01112           /* no body or use remote time */
01113           my_setopt(curl, CURLOPT_FILETIME, 1L);
01114         }
01115 
01116         my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L);
01117         my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
01118         my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
01119         my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
01120 
01121 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
01122         if(config->cookie)
01123           my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
01124 
01125         if(config->cookiefile)
01126           my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
01127 
01128         /* new in libcurl 7.9 */
01129         if(config->cookiejar)
01130           my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
01131 
01132         /* new in libcurl 7.9.7 */
01133         my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L);
01134 #else
01135         if(config->cookie || config->cookiefile || config->cookiejar) {
01136           warnf(config->global, "cookie option(s) used even though cookie "
01137                 "support is disabled!\n");
01138           return CURLE_NOT_BUILT_IN;
01139         }
01140 #endif
01141 
01142         my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
01143         my_setopt(curl, CURLOPT_TIMEVALUE, (long)config->condtime);
01144         my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
01145         customrequest_helper(config, config->httpreq, config->customrequest);
01146         my_setopt(curl, CURLOPT_STDERR, global->errors);
01147 
01148         /* three new ones in libcurl 7.3: */
01149         my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
01150         my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
01151 
01152         progressbarinit(&progressbar, config);
01153         if((global->progressmode == CURL_PROGRESS_BAR) &&
01154            !global->noprogress && !global->mute) {
01155           /* we want the alternative style, then we have to implement it
01156              ourselves! */
01157           my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
01158           my_setopt(curl, CURLOPT_XFERINFODATA, &progressbar);
01159         }
01160 
01161         /* new in libcurl 7.24.0: */
01162         if(config->dns_servers)
01163           my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
01164 
01165         /* new in libcurl 7.33.0: */
01166         if(config->dns_interface)
01167           my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
01168         if(config->dns_ipv4_addr)
01169           my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
01170         if(config->dns_ipv6_addr)
01171         my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
01172 
01173         /* new in libcurl 7.6.2: */
01174         my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
01175 
01176         /* new in libcurl 7.7: */
01177         my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
01178         my_setopt_str(curl, CURLOPT_EGDSOCKET, config->egd_file);
01179         my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS,
01180                   (long)(config->connecttimeout * 1000));
01181 
01182         if(config->cipher_list)
01183           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
01184 
01185         if(config->proxy_cipher_list)
01186           my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
01187                         config->proxy_cipher_list);
01188 
01189         /* new in libcurl 7.9.2: */
01190         if(config->disable_epsv)
01191           /* disable it */
01192           my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
01193 
01194         /* new in libcurl 7.10.5 */
01195         if(config->disable_eprt)
01196           /* disable it */
01197           my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L);
01198 
01199         if(global->tracetype != TRACE_NONE) {
01200           my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
01201           my_setopt(curl, CURLOPT_DEBUGDATA, config);
01202           my_setopt(curl, CURLOPT_VERBOSE, 1L);
01203         }
01204 
01205         /* new in curl 7.9.3 */
01206         if(config->engine) {
01207           result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
01208           if(result)
01209             goto show_error;
01210         }
01211 
01212         /* new in curl 7.10.7, extended in 7.19.4. Modified to use
01213            CREATE_DIR_RETRY in 7.49.0 */
01214         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
01215                   (long)(config->ftp_create_dirs?
01216                          CURLFTP_CREATE_DIR_RETRY:
01217                          CURLFTP_CREATE_DIR_NONE));
01218 
01219         /* new in curl 7.10.8 */
01220         if(config->max_filesize)
01221           my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
01222                     config->max_filesize);
01223 
01224         if(4 == config->ip_version)
01225           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
01226         else if(6 == config->ip_version)
01227           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
01228         else
01229           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
01230 
01231         /* new in curl 7.15.5 */
01232         if(config->ftp_ssl_reqd)
01233           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
01234 
01235         /* new in curl 7.11.0 */
01236         else if(config->ftp_ssl)
01237           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
01238 
01239         /* new in curl 7.16.0 */
01240         else if(config->ftp_ssl_control)
01241           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL);
01242 
01243         /* new in curl 7.16.1 */
01244         if(config->ftp_ssl_ccc)
01245           my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC,
01246                          (long)config->ftp_ssl_ccc_mode);
01247 
01248         /* new in curl 7.19.4 */
01249         if(config->socks5_gssapi_nec)
01250           my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
01251                         config->socks5_gssapi_nec);
01252 
01253         /* new in curl 7.43.0 */
01254         if(config->proxy_service_name)
01255           my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
01256                         config->proxy_service_name);
01257 
01258         /* new in curl 7.43.0 */
01259         if(config->service_name)
01260           my_setopt_str(curl, CURLOPT_SERVICE_NAME,
01261                         config->service_name);
01262 
01263         /* curl 7.13.0 */
01264         my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
01265 
01266         my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L);
01267 
01268         /* curl 7.14.2 */
01269         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
01270 
01271         /* curl 7.15.1 */
01272         my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod);
01273 
01274         /* curl 7.15.2 */
01275         if(config->localport) {
01276           my_setopt(curl, CURLOPT_LOCALPORT, (long)config->localport);
01277           my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
01278                         (long)config->localportrange);
01279         }
01280 
01281         /* curl 7.15.5 */
01282         my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
01283                       config->ftp_alternative_to_user);
01284 
01285         /* curl 7.16.0 */
01286         if(config->disable_sessionid)
01287           /* disable it */
01288           my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
01289 
01290         /* curl 7.16.2 */
01291         if(config->raw) {
01292           my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
01293           my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
01294         }
01295 
01296         /* curl 7.17.1 */
01297         if(!config->nokeepalive) {
01298           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
01299           if(config->alivetime != 0) {
01300             my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
01301             my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
01302           }
01303         }
01304         else
01305           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
01306 
01307         /* curl 7.20.0 */
01308         if(config->tftp_blksize)
01309           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
01310 
01311         if(config->mail_from)
01312           my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
01313 
01314         if(config->mail_rcpt)
01315           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
01316 
01317         /* curl 7.20.x */
01318         if(config->ftp_pret)
01319           my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
01320 
01321         if(config->proto_present)
01322           my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
01323         if(config->proto_redir_present)
01324           my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
01325 
01326         if(config->content_disposition
01327            && (urlnode->flags & GETOUT_USEREMOTE))
01328           hdrcbdata.honor_cd_filename = TRUE;
01329         else
01330           hdrcbdata.honor_cd_filename = FALSE;
01331 
01332         hdrcbdata.outs = &outs;
01333         hdrcbdata.heads = &heads;
01334 
01335         my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
01336         my_setopt(curl, CURLOPT_HEADERDATA, &hdrcbdata);
01337 
01338         if(config->resolve)
01339           /* new in 7.21.3 */
01340           my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
01341 
01342         if(config->connect_to)
01343           /* new in 7.49.0 */
01344           my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
01345 
01346         /* new in 7.21.4 */
01347         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
01348           if(config->tls_username)
01349             my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
01350                           config->tls_username);
01351           if(config->tls_password)
01352             my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
01353                           config->tls_password);
01354           if(config->tls_authtype)
01355             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
01356                           config->tls_authtype);
01357           if(config->proxy_tls_username)
01358             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
01359                           config->proxy_tls_username);
01360           if(config->proxy_tls_password)
01361             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
01362                           config->proxy_tls_password);
01363           if(config->proxy_tls_authtype)
01364             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
01365                           config->proxy_tls_authtype);
01366         }
01367 
01368         /* new in 7.22.0 */
01369         if(config->gssapi_delegation)
01370           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
01371                         config->gssapi_delegation);
01372 
01373         /* new in 7.25.0 and 7.44.0 */
01374         {
01375           long mask = (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
01376                       (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0);
01377           if(mask)
01378             my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
01379         }
01380 
01381         if(config->proxy_ssl_allow_beast)
01382           my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
01383                     (long)CURLSSLOPT_ALLOW_BEAST);
01384 
01385         if(config->mail_auth)
01386           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
01387 
01388         /* new in 7.31.0 */
01389         if(config->sasl_ir)
01390           my_setopt(curl, CURLOPT_SASL_IR, 1L);
01391 
01392         if(config->nonpn) {
01393           my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L);
01394         }
01395 
01396         if(config->noalpn) {
01397           my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
01398         }
01399 
01400         /* new in 7.40.0 */
01401         if(config->unix_socket_path)
01402           my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
01403                         config->unix_socket_path);
01404 
01405         /* new in 7.45.0 */
01406         if(config->proto_default)
01407           my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
01408 
01409         /* new in 7.47.0 */
01410         if(config->expect100timeout > 0)
01411           my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
01412                         (long)(config->expect100timeout*1000));
01413 
01414         /* new in 7.48.0 */
01415         if(config->tftp_no_options)
01416           my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
01417 
01418         /* initialize retry vars for loop below */
01419         retry_sleep_default = (config->retry_delay) ?
01420           config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
01421 
01422         retry_numretries = config->req_retry;
01423         retry_sleep = retry_sleep_default; /* ms */
01424         retrystart = tvnow();
01425 
01426 #ifndef CURL_DISABLE_LIBCURL_OPTION
01427         if(global->libcurl) {
01428           result = easysrc_perform();
01429           if(result)
01430             goto show_error;
01431         }
01432 #endif
01433 
01434         for(;;) {
01435 #ifdef USE_METALINK
01436           if(!metalink && config->use_metalink) {
01437             /* If outs.metalink_parser is non-NULL, delete it first. */
01438             if(outs.metalink_parser)
01439               metalink_parser_context_delete(outs.metalink_parser);
01440             outs.metalink_parser = metalink_parser_context_new();
01441             if(outs.metalink_parser == NULL) {
01442               result = CURLE_OUT_OF_MEMORY;
01443               goto show_error;
01444             }
01445             fprintf(config->global->errors,
01446                     "Metalink: parsing (%s) metalink/XML...\n", this_url);
01447           }
01448           else if(metalink)
01449             fprintf(config->global->errors,
01450                     "Metalink: fetching (%s) from (%s)...\n",
01451                     mlfile->filename, this_url);
01452 #endif /* USE_METALINK */
01453 
01454 #ifdef CURLDEBUG
01455           if(config->test_event_based)
01456             result = curl_easy_perform_ev(curl);
01457           else
01458 #endif
01459           result = curl_easy_perform(curl);
01460 
01461           if(!result && !outs.stream && !outs.bytes) {
01462             /* we have received no data despite the transfer was successful
01463                ==> force cration of an empty output file (if an output file
01464                was specified) */
01465             long cond_unmet = 0L;
01466             /* do not create (or even overwrite) the file in case we get no
01467                data because of unmet condition */
01468             curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
01469             if(!cond_unmet && !tool_create_output_file(&outs))
01470               result = CURLE_WRITE_ERROR;
01471           }
01472 
01473           if(outs.is_cd_filename && outs.stream && !global->mute &&
01474              outs.filename)
01475             printf("curl: Saved to filename '%s'\n", outs.filename);
01476 
01477           /* if retry-max-time is non-zero, make sure we haven't exceeded the
01478              time */
01479           if(retry_numretries &&
01480              (!config->retry_maxtime ||
01481               (tvdiff(tvnow(), retrystart) <
01482                config->retry_maxtime*1000L)) ) {
01483             enum {
01484               RETRY_NO,
01485               RETRY_TIMEOUT,
01486               RETRY_CONNREFUSED,
01487               RETRY_HTTP,
01488               RETRY_FTP,
01489               RETRY_LAST /* not used */
01490             } retry = RETRY_NO;
01491             long response;
01492             if((CURLE_OPERATION_TIMEDOUT == result) ||
01493                (CURLE_COULDNT_RESOLVE_HOST == result) ||
01494                (CURLE_COULDNT_RESOLVE_PROXY == result) ||
01495                (CURLE_FTP_ACCEPT_TIMEOUT == result))
01496               /* retry timeout always */
01497               retry = RETRY_TIMEOUT;
01498             else if(config->retry_connrefused &&
01499                     (CURLE_COULDNT_CONNECT == result)) {
01500               long oserrno;
01501               curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
01502               if(ECONNREFUSED == oserrno)
01503                 retry = RETRY_CONNREFUSED;
01504             }
01505             else if((CURLE_OK == result) ||
01506                     (config->failonerror &&
01507                      (CURLE_HTTP_RETURNED_ERROR == result))) {
01508               /* If it returned OK. _or_ failonerror was enabled and it
01509                  returned due to such an error, check for HTTP transient
01510                  errors to retry on. */
01511               char *effective_url = NULL;
01512               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
01513               if(effective_url &&
01514                  checkprefix("http", effective_url)) {
01515                 /* This was HTTP(S) */
01516                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
01517 
01518                 switch(response) {
01519                 case 500: /* Internal Server Error */
01520                 case 502: /* Bad Gateway */
01521                 case 503: /* Service Unavailable */
01522                 case 504: /* Gateway Timeout */
01523                   retry = RETRY_HTTP;
01524                   /*
01525                    * At this point, we have already written data to the output
01526                    * file (or terminal). If we write to a file, we must rewind
01527                    * or close/re-open the file so that the next attempt starts
01528                    * over from the beginning.
01529                    *
01530                    * TODO: similar action for the upload case. We might need
01531                    * to start over reading from a previous point if we have
01532                    * uploaded something when this was returned.
01533                    */
01534                   break;
01535                 }
01536               }
01537             } /* if CURLE_OK */
01538             else if(result) {
01539               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
01540 
01541               if(response/100 == 4)
01542                 /*
01543                  * This is typically when the FTP server only allows a certain
01544                  * amount of users and we are not one of them.  All 4xx codes
01545                  * are transient.
01546                  */
01547                 retry = RETRY_FTP;
01548             }
01549 
01550             if(retry) {
01551               static const char * const m[]={
01552                 NULL,
01553                 "timeout",
01554                 "connection refused",
01555                 "HTTP error",
01556                 "FTP error"
01557               };
01558 
01559               warnf(config->global, "Transient problem: %s "
01560                     "Will retry in %ld seconds. "
01561                     "%ld retries left.\n",
01562                     m[retry], retry_sleep/1000L, retry_numretries);
01563 
01564               tool_go_sleep(retry_sleep);
01565               retry_numretries--;
01566               if(!config->retry_delay) {
01567                 retry_sleep *= 2;
01568                 if(retry_sleep > RETRY_SLEEP_MAX)
01569                   retry_sleep = RETRY_SLEEP_MAX;
01570               }
01571               if(outs.bytes && outs.filename && outs.stream) {
01572                 /* We have written data to a output file, we truncate file
01573                  */
01574                 if(!global->mute)
01575                   fprintf(global->errors, "Throwing away %"
01576                           CURL_FORMAT_CURL_OFF_T " bytes\n",
01577                           outs.bytes);
01578                 fflush(outs.stream);
01579                 /* truncate file at the position where we started appending */
01580 #ifdef HAVE_FTRUNCATE
01581                 if(ftruncate(fileno(outs.stream), outs.init)) {
01582                   /* when truncate fails, we can't just append as then we'll
01583                      create something strange, bail out */
01584                   if(!global->mute)
01585                     fprintf(global->errors,
01586                             "failed to truncate, exiting\n");
01587                   result = CURLE_WRITE_ERROR;
01588                   goto quit_urls;
01589                 }
01590                 /* now seek to the end of the file, the position where we
01591                    just truncated the file in a large file-safe way */
01592                 fseek(outs.stream, 0, SEEK_END);
01593 #else
01594                 /* ftruncate is not available, so just reposition the file
01595                    to the location we would have truncated it. This won't
01596                    work properly with large files on 32-bit systems, but
01597                    most of those will have ftruncate. */
01598                 fseek(outs.stream, (long)outs.init, SEEK_SET);
01599 #endif
01600                 outs.bytes = 0; /* clear for next round */
01601               }
01602               continue; /* curl_easy_perform loop */
01603             }
01604           } /* if retry_numretries */
01605           else if(metalink) {
01606             /* Metalink: Decide to try the next resource or
01607                not. Basically, we want to try the next resource if
01608                download was not successful. */
01609             long response;
01610             if(CURLE_OK == result) {
01611               /* TODO We want to try next resource when download was
01612                  not successful. How to know that? */
01613               char *effective_url = NULL;
01614               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
01615               if(effective_url &&
01616                  curl_strnequal(effective_url, "http", 4)) {
01617                 /* This was HTTP(S) */
01618                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
01619                 if(response != 200 && response != 206) {
01620                   metalink_next_res = 1;
01621                   fprintf(global->errors,
01622                           "Metalink: fetching (%s) from (%s) FAILED "
01623                           "(HTTP status code %d)\n",
01624                           mlfile->filename, this_url, response);
01625                 }
01626               }
01627             }
01628             else {
01629               metalink_next_res = 1;
01630               fprintf(global->errors,
01631                       "Metalink: fetching (%s) from (%s) FAILED (%s)\n",
01632                       mlfile->filename, this_url,
01633                       (errorbuffer[0]) ?
01634                       errorbuffer : curl_easy_strerror(result));
01635             }
01636           }
01637           if(metalink && !metalink_next_res)
01638             fprintf(global->errors, "Metalink: fetching (%s) from (%s) OK\n",
01639                     mlfile->filename, this_url);
01640 
01641           /* In all ordinary cases, just break out of loop here */
01642           break; /* curl_easy_perform loop */
01643 
01644         }
01645 
01646         if((global->progressmode == CURL_PROGRESS_BAR) &&
01647            progressbar.calls)
01648           /* if the custom progress bar has been displayed, we output a
01649              newline here */
01650           fputs("\n", progressbar.out);
01651 
01652         if(config->writeout)
01653           ourWriteOut(curl, &outs, config->writeout);
01654 
01655         if(config->writeenv)
01656           ourWriteEnv(curl);
01657 
01658         /*
01659         ** Code within this loop may jump directly here to label 'show_error'
01660         ** in order to display an error message for CURLcode stored in 'res'
01661         ** variable and exit loop once that necessary writing and cleanup
01662         ** in label 'quit_urls' has been done.
01663         */
01664 
01665         show_error:
01666 
01667 #ifdef __VMS
01668         if(is_vms_shell()) {
01669           /* VMS DCL shell behavior */
01670           if(!global->showerror)
01671             vms_show = VMSSTS_HIDE;
01672         }
01673         else
01674 #endif
01675         if(result && global->showerror) {
01676           fprintf(global->errors, "curl: (%d) %s\n", result, (errorbuffer[0]) ?
01677                   errorbuffer : curl_easy_strerror(result));
01678           if(result == CURLE_SSL_CACERT)
01679             fprintf(global->errors, "%s%s",
01680                     CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
01681         }
01682 
01683         /* Fall through comment to 'quit_urls' label */
01684 
01685         /*
01686         ** Upon error condition and always that a message has already been
01687         ** displayed, code within this loop may jump directly here to label
01688         ** 'quit_urls' otherwise it should jump to 'show_error' label above.
01689         **
01690         ** When 'res' variable is _not_ CURLE_OK loop will exit once that
01691         ** all code following 'quit_urls' has been executed. Otherwise it
01692         ** will loop to the beginning from where it may exit if there are
01693         ** no more urls left.
01694         */
01695 
01696         quit_urls:
01697 
01698         /* Set file extended attributes */
01699         if(!result && config->xattr && outs.fopened && outs.stream) {
01700           int rc = fwrite_xattr(curl, fileno(outs.stream));
01701           if(rc)
01702             warnf(config->global, "Error setting extended attributes: %s\n",
01703                   strerror(errno));
01704         }
01705 
01706         /* Close the file */
01707         if(outs.fopened && outs.stream) {
01708           int rc = fclose(outs.stream);
01709           if(!result && rc) {
01710             /* something went wrong in the writing process */
01711             result = CURLE_WRITE_ERROR;
01712             fprintf(global->errors, "(%d) Failed writing body\n", result);
01713           }
01714         }
01715         else if(!outs.s_isreg && outs.stream) {
01716           /* Dump standard stream buffered data */
01717           int rc = fflush(outs.stream);
01718           if(!result && rc) {
01719             /* something went wrong in the writing process */
01720             result = CURLE_WRITE_ERROR;
01721             fprintf(global->errors, "(%d) Failed writing body\n", result);
01722           }
01723         }
01724 
01725 #ifdef __AMIGA__
01726         if(!result && outs.s_isreg && outs.filename) {
01727           /* Set the url (up to 80 chars) as comment for the file */
01728           if(strlen(url) > 78)
01729             url[79] = '\0';
01730           SetComment(outs.filename, url);
01731         }
01732 #endif
01733 
01734 #ifdef HAVE_UTIME
01735         /* File time can only be set _after_ the file has been closed */
01736         if(!result && config->remote_time && outs.s_isreg && outs.filename) {
01737           /* Ask libcurl if we got a remote file time */
01738           long filetime = -1;
01739           curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
01740           if(filetime >= 0) {
01741             struct utimbuf times;
01742             times.actime = (time_t)filetime;
01743             times.modtime = (time_t)filetime;
01744             utime(outs.filename, &times); /* set the time we got */
01745           }
01746         }
01747 #endif
01748 
01749 #ifdef USE_METALINK
01750         if(!metalink && config->use_metalink && result == CURLE_OK) {
01751           int rv = parse_metalink(config, &outs, this_url);
01752           if(rv == 0)
01753             fprintf(config->global->errors, "Metalink: parsing (%s) OK\n",
01754                     this_url);
01755           else if(rv == -1)
01756             fprintf(config->global->errors, "Metalink: parsing (%s) FAILED\n",
01757                     this_url);
01758         }
01759         else if(metalink && result == CURLE_OK && !metalink_next_res) {
01760           int rv = metalink_check_hash(global, mlfile, outs.filename);
01761           if(rv == 0) {
01762             metalink_next_res = 1;
01763           }
01764         }
01765 #endif /* USE_METALINK */
01766 
01767         /* No more business with this output struct */
01768         if(outs.alloc_filename)
01769           Curl_safefree(outs.filename);
01770 #ifdef USE_METALINK
01771         if(outs.metalink_parser)
01772           metalink_parser_context_delete(outs.metalink_parser);
01773 #endif /* USE_METALINK */
01774         memset(&outs, 0, sizeof(struct OutStruct));
01775         hdrcbdata.outs = NULL;
01776 
01777         /* Free loop-local allocated memory and close loop-local opened fd */
01778 
01779         Curl_safefree(outfile);
01780         Curl_safefree(this_url);
01781 
01782         if(infdopen)
01783           close(infd);
01784 
01785         if(metalink) {
01786           /* Should exit if error is fatal. */
01787           if(is_fatal_error(result)) {
01788             break;
01789           }
01790           if(!metalink_next_res)
01791             break;
01792           mlres = mlres->next;
01793           if(mlres == NULL)
01794             /* TODO If metalink_next_res is 1 and mlres is NULL,
01795              * set res to error code
01796              */
01797             break;
01798         }
01799         else
01800         if(urlnum > 1) {
01801           /* when url globbing, exit loop upon critical error */
01802           if(is_fatal_error(result))
01803             break;
01804         }
01805         else if(result)
01806           /* when not url globbing, exit loop upon any error */
01807           break;
01808 
01809       } /* loop to the next URL */
01810 
01811       /* Free loop-local allocated memory */
01812 
01813       Curl_safefree(uploadfile);
01814 
01815       if(urls) {
01816         /* Free list of remaining URLs */
01817         glob_cleanup(urls);
01818         urls = NULL;
01819       }
01820 
01821       if(infilenum > 1) {
01822         /* when file globbing, exit loop upon critical error */
01823         if(is_fatal_error(result))
01824           break;
01825       }
01826       else if(result)
01827         /* when not file globbing, exit loop upon any error */
01828         break;
01829 
01830     } /* loop to the next globbed upload file */
01831 
01832     /* Free loop-local allocated memory */
01833 
01834     Curl_safefree(outfiles);
01835 
01836     if(inglob) {
01837       /* Free list of globbed upload files */
01838       glob_cleanup(inglob);
01839       inglob = NULL;
01840     }
01841 
01842     /* Free this URL node data without destroying the
01843        the node itself nor modifying next pointer. */
01844     Curl_safefree(urlnode->url);
01845     Curl_safefree(urlnode->outfile);
01846     Curl_safefree(urlnode->infile);
01847     urlnode->flags = 0;
01848 
01849     /*
01850     ** Bail out upon critical errors or --fail-early
01851     */
01852     if(is_fatal_error(result) || (result && global->fail_early))
01853       goto quit_curl;
01854 
01855   } /* for-loop through all URLs */
01856 
01857   /*
01858   ** Nested loops end here.
01859   */
01860 
01861   quit_curl:
01862 
01863   /* Reset the global config variables */
01864   global->noprogress = orig_noprogress;
01865   global->isatty = orig_isatty;
01866 
01867   /* Free function-local referenced allocated memory */
01868   Curl_safefree(httpgetfields);
01869 
01870   /* Free list of given URLs */
01871   clean_getout(config);
01872 
01873   hdrcbdata.heads = NULL;
01874 
01875   /* Close function-local opened file descriptors */
01876   if(heads.fopened && heads.stream)
01877     fclose(heads.stream);
01878 
01879   if(heads.alloc_filename)
01880     Curl_safefree(heads.filename);
01881 
01882   /* Release metalink related resources here */
01883   clean_metalink(config);
01884 
01885   return result;
01886 }
01887 
01888 CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[])
01889 {
01890   CURLcode result = CURLE_OK;
01891 
01892   /* Setup proper locale from environment */
01893 #ifdef HAVE_SETLOCALE
01894   setlocale(LC_ALL, "");
01895 #endif
01896 
01897   /* Parse .curlrc if necessary */
01898   if((argc == 1) ||
01899      (!curl_strequal(argv[1], "-q") &&
01900       !curl_strequal(argv[1], "--disable"))) {
01901     parseconfig(NULL, config); /* ignore possible failure */
01902 
01903     /* If we had no arguments then make sure a url was specified in .curlrc */
01904     if((argc < 2) && (!config->first->url_list)) {
01905       helpf(config->errors, NULL);
01906       result = CURLE_FAILED_INIT;
01907     }
01908   }
01909 
01910   if(!result) {
01911     /* Parse the command line arguments */
01912     ParameterError res = parse_args(config, argc, argv);
01913     if(res) {
01914       result = CURLE_OK;
01915 
01916       /* Check if we were asked for the help */
01917       if(res == PARAM_HELP_REQUESTED)
01918         tool_help();
01919       /* Check if we were asked for the manual */
01920       else if(res == PARAM_MANUAL_REQUESTED)
01921         hugehelp();
01922       /* Check if we were asked for the version information */
01923       else if(res == PARAM_VERSION_INFO_REQUESTED)
01924         tool_version_info();
01925       /* Check if we were asked to list the SSL engines */
01926       else if(res == PARAM_ENGINES_REQUESTED)
01927         tool_list_engines(config->easy);
01928       else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
01929         result = CURLE_UNSUPPORTED_PROTOCOL;
01930       else
01931         result = CURLE_FAILED_INIT;
01932     }
01933     else {
01934 #ifndef CURL_DISABLE_LIBCURL_OPTION
01935       if(config->libcurl) {
01936         /* Initialise the libcurl source output */
01937         result = easysrc_init();
01938       }
01939 #endif
01940 
01941       /* Perform the main operations */
01942       if(!result) {
01943         size_t count = 0;
01944         struct OperationConfig *operation = config->first;
01945 
01946         /* Get the required aguments for each operation */
01947         while(!result && operation) {
01948           result = get_args(operation, count++);
01949 
01950           operation = operation->next;
01951         }
01952 
01953         /* Set the current operation pointer */
01954         config->current = config->first;
01955 
01956         /* Perform each operation */
01957         while(!result && config->current) {
01958           result = operate_do(config, config->current);
01959 
01960           config->current = config->current->next;
01961         }
01962 
01963 #ifndef CURL_DISABLE_LIBCURL_OPTION
01964         if(config->libcurl) {
01965           /* Cleanup the libcurl source output */
01966           easysrc_cleanup();
01967 
01968           /* Dump the libcurl code if previously enabled */
01969           dumpeasysrc(config);
01970         }
01971 #endif
01972       }
01973       else
01974         helpf(config->errors, "out of memory\n");
01975     }
01976   }
01977 
01978   return result;
01979 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07