1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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 https://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 #ifndef CURL_DISABLE_LIBCURL_OPTION 25 26 #define ENABLE_CURLX_PRINTF 27 /* use our own printf() functions */ 28 #include "curlx.h" 29 30 #include "tool_cfgable.h" 31 #include "tool_easysrc.h" 32 #include "tool_setopt.h" 33 #include "tool_convert.h" 34 35 #include "mime.h" 36 #include "memdebug.h" /* keep this as LAST include */ 37 38 /* Lookup tables for converting setopt values back to symbols */ 39 /* For enums, values may be in any order. */ 40 /* For bit masks, put combinations first, then single bits, */ 41 /* and finally any "NONE" value. */ 42 43 #define NV(e) {#e, e} 44 #define NV1(e, v) {#e, (v)} 45 #define NVEND {NULL, 0} /* sentinel to mark end of list */ 46 47 const NameValue setopt_nv_CURLPROXY[] = { 48 NV(CURLPROXY_HTTP), 49 NV(CURLPROXY_HTTP_1_0), 50 NV(CURLPROXY_HTTPS), 51 NV(CURLPROXY_SOCKS4), 52 NV(CURLPROXY_SOCKS5), 53 NV(CURLPROXY_SOCKS4A), 54 NV(CURLPROXY_SOCKS5_HOSTNAME), 55 NVEND, 56 }; 57 58 const NameValue setopt_nv_CURL_SOCKS_PROXY[] = { 59 NV(CURLPROXY_SOCKS4), 60 NV(CURLPROXY_SOCKS5), 61 NV(CURLPROXY_SOCKS4A), 62 NV(CURLPROXY_SOCKS5_HOSTNAME), 63 NVEND, 64 }; 65 66 const NameValueUnsigned setopt_nv_CURLAUTH[] = { 67 NV(CURLAUTH_ANY), /* combination */ 68 NV(CURLAUTH_ANYSAFE), /* combination */ 69 NV(CURLAUTH_BASIC), 70 NV(CURLAUTH_DIGEST), 71 NV(CURLAUTH_GSSNEGOTIATE), 72 NV(CURLAUTH_NTLM), 73 NV(CURLAUTH_DIGEST_IE), 74 NV(CURLAUTH_NTLM_WB), 75 NV(CURLAUTH_ONLY), 76 NV(CURLAUTH_NONE), 77 NVEND, 78 }; 79 80 const NameValue setopt_nv_CURL_HTTP_VERSION[] = { 81 NV(CURL_HTTP_VERSION_NONE), 82 NV(CURL_HTTP_VERSION_1_0), 83 NV(CURL_HTTP_VERSION_1_1), 84 NV(CURL_HTTP_VERSION_2_0), 85 NV(CURL_HTTP_VERSION_2TLS), 86 NVEND, 87 }; 88 89 const NameValue setopt_nv_CURL_SSLVERSION[] = { 90 NV(CURL_SSLVERSION_DEFAULT), 91 NV(CURL_SSLVERSION_TLSv1), 92 NV(CURL_SSLVERSION_SSLv2), 93 NV(CURL_SSLVERSION_SSLv3), 94 NV(CURL_SSLVERSION_TLSv1_0), 95 NV(CURL_SSLVERSION_TLSv1_1), 96 NV(CURL_SSLVERSION_TLSv1_2), 97 NV(CURL_SSLVERSION_TLSv1_3), 98 NVEND, 99 }; 100 101 const NameValue setopt_nv_CURL_TIMECOND[] = { 102 NV(CURL_TIMECOND_IFMODSINCE), 103 NV(CURL_TIMECOND_IFUNMODSINCE), 104 NV(CURL_TIMECOND_LASTMOD), 105 NV(CURL_TIMECOND_NONE), 106 NVEND, 107 }; 108 109 const NameValue setopt_nv_CURLFTPSSL_CCC[] = { 110 NV(CURLFTPSSL_CCC_NONE), 111 NV(CURLFTPSSL_CCC_PASSIVE), 112 NV(CURLFTPSSL_CCC_ACTIVE), 113 NVEND, 114 }; 115 116 const NameValue setopt_nv_CURLUSESSL[] = { 117 NV(CURLUSESSL_NONE), 118 NV(CURLUSESSL_TRY), 119 NV(CURLUSESSL_CONTROL), 120 NV(CURLUSESSL_ALL), 121 NVEND, 122 }; 123 124 const NameValueUnsigned setopt_nv_CURLSSLOPT[] = { 125 NV(CURLSSLOPT_ALLOW_BEAST), 126 NV(CURLSSLOPT_NO_REVOKE), 127 NVEND, 128 }; 129 130 const NameValue setopt_nv_CURL_NETRC[] = { 131 NV(CURL_NETRC_IGNORED), 132 NV(CURL_NETRC_OPTIONAL), 133 NV(CURL_NETRC_REQUIRED), 134 NVEND, 135 }; 136 137 /* These mappings essentially triplicated - see 138 * tool_libinfo.c and tool_paramhlp.c */ 139 const NameValue setopt_nv_CURLPROTO[] = { 140 NV(CURLPROTO_ALL), /* combination */ 141 NV(CURLPROTO_DICT), 142 NV(CURLPROTO_FILE), 143 NV(CURLPROTO_FTP), 144 NV(CURLPROTO_FTPS), 145 NV(CURLPROTO_GOPHER), 146 NV(CURLPROTO_HTTP), 147 NV(CURLPROTO_HTTPS), 148 NV(CURLPROTO_IMAP), 149 NV(CURLPROTO_IMAPS), 150 NV(CURLPROTO_LDAP), 151 NV(CURLPROTO_LDAPS), 152 NV(CURLPROTO_POP3), 153 NV(CURLPROTO_POP3S), 154 NV(CURLPROTO_RTSP), 155 NV(CURLPROTO_SCP), 156 NV(CURLPROTO_SFTP), 157 NV(CURLPROTO_SMB), 158 NV(CURLPROTO_SMBS), 159 NV(CURLPROTO_SMTP), 160 NV(CURLPROTO_SMTPS), 161 NV(CURLPROTO_TELNET), 162 NV(CURLPROTO_TFTP), 163 NVEND, 164 }; 165 166 /* These options have non-zero default values. */ 167 static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = { 168 NV1(CURLOPT_SSL_VERIFYPEER, 1), 169 NV1(CURLOPT_SSL_VERIFYHOST, 1), 170 NV1(CURLOPT_SSL_ENABLE_NPN, 1), 171 NV1(CURLOPT_SSL_ENABLE_ALPN, 1), 172 NV1(CURLOPT_TCP_NODELAY, 1), 173 NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), 174 NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), 175 NV1(CURLOPT_SOCKS5_AUTH, 1), 176 NVEND 177 }; 178 179 /* Format and add code; jump to nomem on malloc error */ 180 #define ADD(args) do { \ 181 ret = easysrc_add args; \ 182 if(ret) \ 183 goto nomem; \ 184 } WHILE_FALSE 185 #define ADDF(args) do { \ 186 ret = easysrc_addf args; \ 187 if(ret) \ 188 goto nomem; \ 189 } WHILE_FALSE 190 191 #define DECL0(s) ADD((&easysrc_decl, s)) 192 #define DECL1(f,a) ADDF((&easysrc_decl, f,a)) 193 194 #define DATA0(s) ADD((&easysrc_data, s)) 195 #define DATA1(f,a) ADDF((&easysrc_data, f,a)) 196 #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) 197 #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) 198 199 #define CODE0(s) ADD((&easysrc_code, s)) 200 #define CODE1(f,a) ADDF((&easysrc_code, f,a)) 201 #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) 202 #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) 203 204 #define CLEAN0(s) ADD((&easysrc_clean, s)) 205 #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) 206 207 #define REM0(s) ADD((&easysrc_toohard, s)) 208 #define REM1(f,a) ADDF((&easysrc_toohard, f,a)) 209 #define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) 210 211 /* Escape string to C string syntax. Return NULL if out of memory. 212 * Is this correct for those wacky EBCDIC guys? */ 213 static char *c_escape(const char *str, size_t len) 214 { 215 const char *s; 216 unsigned char c; 217 char *escaped, *e; 218 219 if(len == CURL_ZERO_TERMINATED) 220 len = strlen(str); 221 222 /* Check for possible overflow. */ 223 if(len > (~(size_t) 0) / 4) 224 return NULL; 225 226 /* Allocate space based on worst-case */ 227 escaped = malloc(4 * len + 1); 228 if(!escaped) 229 return NULL; 230 231 e = escaped; 232 for(s = str; (c = *s) != '\0'; s++) { 233 if(c == '\n') { 234 strcpy(e, "\\n"); 235 e += 2; 236 } 237 else if(c == '\r') { 238 strcpy(e, "\\r"); 239 e += 2; 240 } 241 else if(c == '\t') { 242 strcpy(e, "\\t"); 243 e += 2; 244 } 245 else if(c == '\\') { 246 strcpy(e, "\\\\"); 247 e += 2; 248 } 249 else if(c == '"') { 250 strcpy(e, "\\\""); 251 e += 2; 252 } 253 else if(! isprint(c)) { 254 snprintf(e, 5, "\\%03o", (unsigned)c); 255 e += 4; 256 } 257 else 258 *e++ = c; 259 } 260 *e = '\0'; 261 return escaped; 262 } 263 264 /* setopt wrapper for enum types */ 265 CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, 266 const char *name, CURLoption tag, 267 const NameValue *nvlist, long lval) 268 { 269 CURLcode ret = CURLE_OK; 270 bool skip = FALSE; 271 272 ret = curl_easy_setopt(curl, tag, lval); 273 if(!lval) 274 skip = TRUE; 275 276 if(config->libcurl && !skip && !ret) { 277 /* we only use this for real if --libcurl was used */ 278 const NameValue *nv = NULL; 279 for(nv = nvlist; nv->name; nv++) { 280 if(nv->value == lval) break; /* found it */ 281 } 282 if(! nv->name) { 283 /* If no definition was found, output an explicit value. 284 * This could happen if new values are defined and used 285 * but the NameValue list is not updated. */ 286 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); 287 } 288 else { 289 CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); 290 } 291 } 292 293 nomem: 294 return ret; 295 } 296 297 /* setopt wrapper for flags */ 298 CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, 299 const char *name, CURLoption tag, 300 const NameValue *nvlist, long lval) 301 { 302 CURLcode ret = CURLE_OK; 303 bool skip = FALSE; 304 305 ret = curl_easy_setopt(curl, tag, lval); 306 if(!lval) 307 skip = TRUE; 308 309 if(config->libcurl && !skip && !ret) { 310 /* we only use this for real if --libcurl was used */ 311 char preamble[80]; /* should accommodate any symbol name */ 312 long rest = lval; /* bits not handled yet */ 313 const NameValue *nv = NULL; 314 snprintf(preamble, sizeof(preamble), 315 "curl_easy_setopt(hnd, %s, ", name); 316 for(nv = nvlist; nv->name; nv++) { 317 if((nv->value & ~ rest) == 0) { 318 /* all value flags contained in rest */ 319 rest &= ~ nv->value; /* remove bits handled here */ 320 CODE3("%s(long)%s%s", 321 preamble, nv->name, rest ? " |" : ");"); 322 if(!rest) 323 break; /* handled them all */ 324 /* replace with all spaces for continuation line */ 325 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 326 } 327 } 328 /* If any bits have no definition, output an explicit value. 329 * This could happen if new bits are defined and used 330 * but the NameValue list is not updated. */ 331 if(rest) 332 CODE2("%s%ldL);", preamble, rest); 333 } 334 335 nomem: 336 return ret; 337 } 338 339 /* setopt wrapper for bitmasks */ 340 CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, 341 const char *name, CURLoption tag, 342 const NameValueUnsigned *nvlist, 343 long lval) 344 { 345 CURLcode ret = CURLE_OK; 346 bool skip = FALSE; 347 348 ret = curl_easy_setopt(curl, tag, lval); 349 if(!lval) 350 skip = TRUE; 351 352 if(config->libcurl && !skip && !ret) { 353 /* we only use this for real if --libcurl was used */ 354 char preamble[80]; 355 unsigned long rest = (unsigned long)lval; 356 const NameValueUnsigned *nv = NULL; 357 snprintf(preamble, sizeof(preamble), 358 "curl_easy_setopt(hnd, %s, ", name); 359 for(nv = nvlist; nv->name; nv++) { 360 if((nv->value & ~ rest) == 0) { 361 /* all value flags contained in rest */ 362 rest &= ~ nv->value; /* remove bits handled here */ 363 CODE3("%s(long)%s%s", 364 preamble, nv->name, rest ? " |" : ");"); 365 if(!rest) 366 break; /* handled them all */ 367 /* replace with all spaces for continuation line */ 368 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 369 } 370 } 371 /* If any bits have no definition, output an explicit value. 372 * This could happen if new bits are defined and used 373 * but the NameValue list is not updated. */ 374 if(rest) 375 CODE2("%s%luUL);", preamble, rest); 376 } 377 378 nomem: 379 return ret; 380 } 381 382 /* Generate code for a struct curl_slist. */ 383 static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno) 384 { 385 CURLcode ret = CURLE_OK; 386 char *escaped = NULL; 387 388 /* May need several slist variables, so invent name */ 389 *slistno = ++easysrc_slist_count; 390 391 DECL1("struct curl_slist *slist%d;", *slistno); 392 DATA1("slist%d = NULL;", *slistno); 393 CLEAN1("curl_slist_free_all(slist%d);", *slistno); 394 CLEAN1("slist%d = NULL;", *slistno); 395 for(; slist; slist = slist->next) { 396 Curl_safefree(escaped); 397 escaped = c_escape(slist->data, CURL_ZERO_TERMINATED); 398 if(!escaped) 399 return CURLE_OUT_OF_MEMORY; 400 DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", 401 *slistno, *slistno, escaped); 402 } 403 404 nomem: 405 Curl_safefree(escaped); 406 return ret; 407 } 408 409 /* Generate source code for a mime structure. */ 410 static CURLcode libcurl_generate_mime(curl_mime *mime, int *mimeno) 411 { 412 CURLcode ret = CURLE_OK; 413 int i; 414 curl_off_t size; 415 curl_mimepart *part; 416 char *filename; 417 char *escaped = NULL; 418 char *cp; 419 char *data; 420 421 /* May need several mime variables, so invent name */ 422 *mimeno = ++easysrc_mime_count; 423 424 DECL1("curl_mime *mime%d;", *mimeno); 425 DATA1("mime%d = NULL;", *mimeno); 426 CODE1("mime%d = curl_mime_init(hnd);", *mimeno); 427 CLEAN1("curl_mime_free(mime%d);", *mimeno); 428 CLEAN1("mime%d = NULL;", *mimeno); 429 if(mime->firstpart) { 430 DECL1("curl_mimepart *part%d;", *mimeno); 431 for(part = mime->firstpart; part; part = part->nextpart) { 432 CODE2("part%d = curl_mime_addpart(mime%d);", *mimeno, *mimeno); 433 filename = part->filename; 434 switch(part->kind) { 435 case MIMEKIND_FILE: 436 Curl_safefree(escaped); 437 escaped = c_escape(part->data, CURL_ZERO_TERMINATED); 438 if(!escaped) 439 return CURLE_OUT_OF_MEMORY; 440 CODE2("curl_mime_filedata(part%d, \"%s\");", *mimeno, escaped); 441 if(!filename) 442 CODE1("curl_mime_filename(part%d, NULL);", *mimeno); 443 else { 444 /* Fast check to see if remote file name is base name. */ 445 filename = part->data; 446 for(cp = filename; *cp; cp++) 447 if(*cp == '/' || *cp == '\\') 448 filename = cp + 1; 449 if(!part->filename || !strcmp(filename, part->filename)) 450 filename = NULL; 451 else 452 filename = part->filename; 453 } 454 break; 455 case MIMEKIND_CALLBACK: 456 /* Can only be reading stdin in the current context. */ 457 CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\", 458 *mimeno); 459 CODE0(" (curl_seek_callback) fseek, NULL, stdin);"); 460 break; 461 case MIMEKIND_DATA: 462 #ifdef CURL_DOES_CONVERSIONS 463 /* Data is stored in ASCII and we want in in the host character 464 code. Convert it back for output. */ 465 data = malloc(part->datasize + 1); 466 if(!data) { 467 ret = CURLE_OUT_OF_MEMORY; 468 goto nomem; 469 } 470 memcpy(data, part->data, part->datasize + 1); 471 ret = convert_from_network(data, strlen(data)); 472 if(ret) { 473 Curl_safefree(data); 474 goto nomem; 475 } 476 #else 477 data = part->data; 478 #endif 479 480 /* Are there any nul byte in data? */ 481 for(cp = data; *cp; cp++) 482 ; 483 size = (cp == data + part->datasize)? (curl_off_t) -1: part->datasize; 484 Curl_safefree(escaped); 485 escaped = c_escape(data, (size_t) part->datasize); 486 #ifdef CURL_DOES_CONVERSIONS 487 Curl_safefree(data); 488 #endif 489 if(!escaped) 490 return CURLE_OUT_OF_MEMORY; 491 if(size >= 0) 492 CODE3("curl_mime_data(part%d, \"%s\", %" CURL_FORMAT_CURL_OFF_T ");", 493 *mimeno, escaped, size); 494 else 495 CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);", 496 *mimeno, escaped); 497 break; 498 case MIMEKIND_MULTIPART: 499 ret = libcurl_generate_mime(part->arg, &i); 500 if(ret) 501 goto nomem; 502 CODE2("curl_mime_subparts(part%d, mime%d);", *mimeno, i); 503 CODE1("mime%d = NULL;", i); /* Avoid freeing in CLEAN sequence. */ 504 break; 505 default: 506 /* Other cases not possible in this context. */ 507 break; 508 } 509 510 if(part->encoder) { 511 Curl_safefree(escaped); 512 escaped = c_escape(part->encoder->name, CURL_ZERO_TERMINATED); 513 if(!escaped) 514 return CURLE_OUT_OF_MEMORY; 515 CODE2("curl_mime_encoder(part%d, \"%s\");", *mimeno, escaped); 516 } 517 518 if(filename) { 519 Curl_safefree(escaped); 520 escaped = c_escape(filename, CURL_ZERO_TERMINATED); 521 if(!escaped) 522 return CURLE_OUT_OF_MEMORY; 523 CODE2("curl_mime_filename(part%d, \"%s\");", *mimeno, escaped); 524 } 525 526 if(part->name) { 527 Curl_safefree(escaped); 528 escaped = c_escape(part->name, CURL_ZERO_TERMINATED); 529 if(!escaped) 530 return CURLE_OUT_OF_MEMORY; 531 CODE2("curl_mime_name(part%d, \"%s\");", *mimeno, escaped); 532 } 533 534 if(part->mimetype) { 535 Curl_safefree(escaped); 536 escaped = c_escape(part->mimetype, CURL_ZERO_TERMINATED); 537 if(!escaped) 538 return CURLE_OUT_OF_MEMORY; 539 CODE2("curl_mime_type(part%d, \"%s\");", *mimeno, escaped); 540 } 541 542 if(part->userheaders) { 543 int ownership = part->flags & MIME_USERHEADERS_OWNER? 1: 0; 544 545 ret = libcurl_generate_slist(part->userheaders, &i); 546 if(ret) 547 goto nomem; 548 CODE3("curl_mime_headers(part%d, slist%d, %d);", 549 *mimeno, i, ownership); 550 if(ownership) 551 CODE1("slist%d = NULL;", i); /* Prevent freeing in CLEAN sequence. */ 552 } 553 } 554 } 555 556 nomem: 557 Curl_safefree(escaped); 558 return ret; 559 } 560 561 /* setopt wrapper for CURLOPT_MIMEPOST */ 562 CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config, 563 const char *name, CURLoption tag, 564 curl_mime *mimepost) 565 { 566 CURLcode ret = CURLE_OK; 567 568 ret = curl_easy_setopt(curl, tag, mimepost); 569 570 if(config->libcurl && mimepost && !ret) { 571 int i; 572 573 ret = libcurl_generate_mime(mimepost, &i); 574 575 if(!ret) 576 CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, i); 577 } 578 579 nomem: 580 return ret; 581 } 582 583 /* setopt wrapper for curl_slist options */ 584 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, 585 const char *name, CURLoption tag, 586 struct curl_slist *list) 587 { 588 CURLcode ret = CURLE_OK; 589 590 ret = curl_easy_setopt(curl, tag, list); 591 592 if(config->libcurl && list && !ret) { 593 int i; 594 595 ret = libcurl_generate_slist(list, &i); 596 if(!ret) 597 CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); 598 } 599 600 nomem: 601 return ret; 602 } 603 604 /* generic setopt wrapper for all other options. 605 * Some type information is encoded in the tag value. */ 606 CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config, 607 const char *name, CURLoption tag, ...) 608 { 609 va_list arg; 610 char buf[256]; 611 const char *value = NULL; 612 bool remark = FALSE; 613 bool skip = FALSE; 614 bool escape = FALSE; 615 char *escaped = NULL; 616 CURLcode ret = CURLE_OK; 617 618 va_start(arg, tag); 619 620 if(tag < CURLOPTTYPE_OBJECTPOINT) { 621 /* Value is expected to be a long */ 622 long lval = va_arg(arg, long); 623 long defval = 0L; 624 const NameValue *nv = NULL; 625 for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) { 626 if(!strcmp(name, nv->name)) { 627 defval = nv->value; 628 break; /* found it */ 629 } 630 } 631 632 snprintf(buf, sizeof(buf), "%ldL", lval); 633 value = buf; 634 ret = curl_easy_setopt(curl, tag, lval); 635 if(lval == defval) 636 skip = TRUE; 637 } 638 else if(tag < CURLOPTTYPE_OFF_T) { 639 /* Value is some sort of object pointer */ 640 void *pval = va_arg(arg, void *); 641 642 /* function pointers are never printable */ 643 if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { 644 if(pval) { 645 value = "functionpointer"; 646 remark = TRUE; 647 } 648 else 649 skip = TRUE; 650 } 651 652 else if(pval && str) { 653 value = (char *)pval; 654 escape = TRUE; 655 } 656 else if(pval) { 657 value = "objectpointer"; 658 remark = TRUE; 659 } 660 else 661 skip = TRUE; 662 663 ret = curl_easy_setopt(curl, tag, pval); 664 665 } 666 else { 667 /* Value is expected to be curl_off_t */ 668 curl_off_t oval = va_arg(arg, curl_off_t); 669 snprintf(buf, sizeof(buf), 670 "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); 671 value = buf; 672 ret = curl_easy_setopt(curl, tag, oval); 673 674 if(!oval) 675 skip = TRUE; 676 } 677 678 va_end(arg); 679 680 if(config->libcurl && !skip && !ret) { 681 /* we only use this for real if --libcurl was used */ 682 683 if(remark) 684 REM2("%s set to a %s", name, value); 685 else { 686 if(escape) { 687 escaped = c_escape(value, CURL_ZERO_TERMINATED); 688 if(!escaped) { 689 ret = CURLE_OUT_OF_MEMORY; 690 goto nomem; 691 } 692 CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); 693 } 694 else 695 CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); 696 } 697 } 698 699 nomem: 700 Curl_safefree(escaped); 701 return ret; 702 } 703 704 #endif /* CURL_DISABLE_LIBCURL_OPTION */ 705