1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 #include "tool_setup.h"
25
26 #ifndef CURL_DISABLE_LIBCURL_OPTION
27
28 #include "curlx.h"
29
30 #include "tool_cfgable.h"
31 #include "tool_easysrc.h"
32 #include "tool_setopt.h"
33 #include "tool_msgs.h"
34 #include "dynbuf.h"
35
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 struct 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 struct 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 struct NameValueUnsigned setopt_nv_CURLHSTS[] = {
67 NV(CURLHSTS_ENABLE),
68 NVEND,
69 };
70
71 const struct NameValueUnsigned setopt_nv_CURLAUTH[] = {
72 NV(CURLAUTH_ANY), /* combination */
73 NV(CURLAUTH_ANYSAFE), /* combination */
74 NV(CURLAUTH_BASIC),
75 NV(CURLAUTH_DIGEST),
76 NV(CURLAUTH_GSSNEGOTIATE),
77 NV(CURLAUTH_NTLM),
78 NV(CURLAUTH_DIGEST_IE),
79 NV(CURLAUTH_ONLY),
80 NV(CURLAUTH_NONE),
81 NVEND,
82 };
83
84 const struct NameValue setopt_nv_CURL_HTTP_VERSION[] = {
85 NV(CURL_HTTP_VERSION_NONE),
86 NV(CURL_HTTP_VERSION_1_0),
87 NV(CURL_HTTP_VERSION_1_1),
88 NV(CURL_HTTP_VERSION_2_0),
89 NV(CURL_HTTP_VERSION_2TLS),
90 NV(CURL_HTTP_VERSION_3),
91 NV(CURL_HTTP_VERSION_3ONLY),
92 NVEND,
93 };
94
95 const struct NameValue setopt_nv_CURL_SSLVERSION[] = {
96 NV(CURL_SSLVERSION_DEFAULT),
97 NV(CURL_SSLVERSION_TLSv1),
98 NV(CURL_SSLVERSION_SSLv2),
99 NV(CURL_SSLVERSION_SSLv3),
100 NV(CURL_SSLVERSION_TLSv1_0),
101 NV(CURL_SSLVERSION_TLSv1_1),
102 NV(CURL_SSLVERSION_TLSv1_2),
103 NV(CURL_SSLVERSION_TLSv1_3),
104 NVEND,
105 };
106
107 const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[] = {
108 NV(CURL_SSLVERSION_MAX_NONE),
109 NV(CURL_SSLVERSION_MAX_DEFAULT),
110 NV(CURL_SSLVERSION_MAX_TLSv1_0),
111 NV(CURL_SSLVERSION_MAX_TLSv1_1),
112 NV(CURL_SSLVERSION_MAX_TLSv1_2),
113 NV(CURL_SSLVERSION_MAX_TLSv1_3),
114 NVEND,
115 };
116
117 const struct NameValue setopt_nv_CURL_TIMECOND[] = {
118 NV(CURL_TIMECOND_IFMODSINCE),
119 NV(CURL_TIMECOND_IFUNMODSINCE),
120 NV(CURL_TIMECOND_LASTMOD),
121 NV(CURL_TIMECOND_NONE),
122 NVEND,
123 };
124
125 const struct NameValue setopt_nv_CURLFTPSSL_CCC[] = {
126 NV(CURLFTPSSL_CCC_NONE),
127 NV(CURLFTPSSL_CCC_PASSIVE),
128 NV(CURLFTPSSL_CCC_ACTIVE),
129 NVEND,
130 };
131
132 const struct NameValue setopt_nv_CURLUSESSL[] = {
133 NV(CURLUSESSL_NONE),
134 NV(CURLUSESSL_TRY),
135 NV(CURLUSESSL_CONTROL),
136 NV(CURLUSESSL_ALL),
137 NVEND,
138 };
139
140 const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = {
141 NV(CURLSSLOPT_ALLOW_BEAST),
142 NV(CURLSSLOPT_NO_REVOKE),
143 NV(CURLSSLOPT_NO_PARTIALCHAIN),
144 NV(CURLSSLOPT_REVOKE_BEST_EFFORT),
145 NV(CURLSSLOPT_NATIVE_CA),
146 NV(CURLSSLOPT_AUTO_CLIENT_CERT),
147 NVEND,
148 };
149
150 const struct NameValue setopt_nv_CURL_NETRC[] = {
151 NV(CURL_NETRC_IGNORED),
152 NV(CURL_NETRC_OPTIONAL),
153 NV(CURL_NETRC_REQUIRED),
154 NVEND,
155 };
156
157 /* These options have non-zero default values. */
158 static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
159 NV1(CURLOPT_SSL_VERIFYPEER, 1),
160 NV1(CURLOPT_SSL_VERIFYHOST, 1),
161 NV1(CURLOPT_SSL_ENABLE_NPN, 1),
162 NV1(CURLOPT_SSL_ENABLE_ALPN, 1),
163 NV1(CURLOPT_TCP_NODELAY, 1),
164 NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
165 NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
166 NV1(CURLOPT_SOCKS5_AUTH, 1),
167 NVEND
168 };
169
170 /* Format and add code; jump to nomem on malloc error */
171 #define ADD(args) do { \
172 ret = easysrc_add args; \
173 if(ret) \
174 goto nomem; \
175 } while(0)
176 #define ADDF(args) do { \
177 ret = easysrc_addf args; \
178 if(ret) \
179 goto nomem; \
180 } while(0)
181 #define NULL_CHECK(p) do { \
182 if(!p) { \
183 ret = CURLE_OUT_OF_MEMORY; \
184 goto nomem; \
185 } \
186 } while(0)
187
188 #define DECL0(s) ADD((&easysrc_decl, s))
189 #define DECL1(f,a) ADDF((&easysrc_decl, f,a))
190
191 #define DATA0(s) ADD((&easysrc_data, s))
192 #define DATA1(f,a) ADDF((&easysrc_data, f,a))
193 #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b))
194 #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c))
195
196 #define CODE0(s) ADD((&easysrc_code, s))
197 #define CODE1(f,a) ADDF((&easysrc_code, f,a))
198 #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b))
199 #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c))
200
201 #define CLEAN0(s) ADD((&easysrc_clean, s))
202 #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))
203
204 #define REM0(s) ADD((&easysrc_toohard, s))
205 #define REM1(f,a) ADDF((&easysrc_toohard, f,a))
206 #define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c))
207
208 /* Escape string to C string syntax. Return NULL if out of memory.
209 * Is this correct for those wacky EBCDIC guys? */
210
211 #define MAX_STRING_LENGTH_OUTPUT 2000
212 #define ZERO_TERMINATED -1
213
c_escape(const char * str,curl_off_t len)214 static char *c_escape(const char *str, curl_off_t len)
215 {
216 const char *s;
217 unsigned int cutoff = 0;
218 CURLcode result;
219 struct curlx_dynbuf escaped;
220
221 curlx_dyn_init(&escaped, 4 * MAX_STRING_LENGTH_OUTPUT + 3);
222
223 if(len == ZERO_TERMINATED)
224 len = strlen(str);
225
226 if(len > MAX_STRING_LENGTH_OUTPUT) {
227 /* cap ridiculously long strings */
228 len = MAX_STRING_LENGTH_OUTPUT;
229 cutoff = 3;
230 }
231
232 result = curlx_dyn_addn(&escaped, STRCONST(""));
233 for(s = str; !result && len; s++, len--) {
234 /* escape question marks as well, to prevent generating accidental
235 trigraphs */
236 static const char from[] = "\t\r\n?\"\\";
237 static const char to[] = "\\t\\r\\n\\?\\\"\\\\";
238 const char *p = strchr(from, *s);
239
240 if(!p && ISPRINT(*s))
241 continue;
242
243 result = curlx_dyn_addn(&escaped, str, s - str);
244 str = s + 1;
245
246 if(!result) {
247 if(p && *p)
248 result = curlx_dyn_addn(&escaped, to + 2 * (p - from), 2);
249 else {
250 result = curlx_dyn_addf(&escaped,
251 /* Octal escape to avoid >2 digit hex. */
252 (len > 1 && ISXDIGIT(s[1])) ?
253 "\\%03o" : "\\x%02x",
254 (unsigned int) *(unsigned char *) s);
255 }
256 }
257 }
258
259 if(!result)
260 result = curlx_dyn_addn(&escaped, str, s - str);
261
262 if(!result)
263 (void) !curlx_dyn_addn(&escaped, "...", cutoff);
264
265 return curlx_dyn_ptr(&escaped);
266 }
267
268 /* setopt wrapper for enum types */
tool_setopt_enum(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,const struct NameValue * nvlist,long lval)269 CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config,
270 const char *name, CURLoption tag,
271 const struct NameValue *nvlist, long lval)
272 {
273 CURLcode ret = CURLE_OK;
274 bool skip = FALSE;
275
276 ret = curl_easy_setopt(curl, tag, lval);
277 if(!lval)
278 skip = TRUE;
279
280 if(config->libcurl && !skip && !ret) {
281 /* we only use this for real if --libcurl was used */
282 const struct NameValue *nv = NULL;
283 for(nv = nvlist; nv->name; nv++) {
284 if(nv->value == lval)
285 break; /* found it */
286 }
287 if(!nv->name) {
288 /* If no definition was found, output an explicit value.
289 * This could happen if new values are defined and used
290 * but the NameValue list is not updated. */
291 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
292 }
293 else {
294 CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name);
295 }
296 }
297
298 #ifdef DEBUGBUILD
299 if(ret)
300 warnf(config, "option %s returned error (%d)", name, (int)ret);
301 #endif
302 nomem:
303 return ret;
304 }
305
306 /* setopt wrapper for CURLOPT_SSLVERSION */
tool_setopt_SSLVERSION(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,long lval)307 CURLcode tool_setopt_SSLVERSION(CURL *curl, struct GlobalConfig *config,
308 const char *name, CURLoption tag,
309 long lval)
310 {
311 CURLcode ret = CURLE_OK;
312 bool skip = FALSE;
313
314 ret = curl_easy_setopt(curl, tag, lval);
315 if(!lval)
316 skip = TRUE;
317
318 if(config->libcurl && !skip && !ret) {
319 /* we only use this for real if --libcurl was used */
320 const struct NameValue *nv = NULL;
321 const struct NameValue *nv2 = NULL;
322 for(nv = setopt_nv_CURL_SSLVERSION; nv->name; nv++) {
323 if(nv->value == (lval & 0xffff))
324 break; /* found it */
325 }
326 for(nv2 = setopt_nv_CURL_SSLVERSION_MAX; nv2->name; nv2++) {
327 if(nv2->value == (lval & ~0xffff))
328 break; /* found it */
329 }
330 if(!nv->name) {
331 /* If no definition was found, output an explicit value.
332 * This could happen if new values are defined and used
333 * but the NameValue list is not updated. */
334 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
335 }
336 else {
337 CODE3("curl_easy_setopt(hnd, %s, (long)(%s | %s));",
338 name, nv->name, nv2->name);
339 }
340 }
341
342 #ifdef DEBUGBUILD
343 if(ret)
344 warnf(config, "option %s returned error (%d)", name, (int)ret);
345 #endif
346 nomem:
347 return ret;
348 }
349
350 /* setopt wrapper for bitmasks */
tool_setopt_bitmask(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,const struct NameValueUnsigned * nvlist,long lval)351 CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config,
352 const char *name, CURLoption tag,
353 const struct NameValueUnsigned *nvlist,
354 long lval)
355 {
356 CURLcode ret = CURLE_OK;
357 bool skip = FALSE;
358
359 ret = curl_easy_setopt(curl, tag, lval);
360 if(!lval)
361 skip = TRUE;
362
363 if(config->libcurl && !skip && !ret) {
364 /* we only use this for real if --libcurl was used */
365 char preamble[80];
366 unsigned long rest = (unsigned long)lval;
367 const struct NameValueUnsigned *nv = NULL;
368 msnprintf(preamble, sizeof(preamble),
369 "curl_easy_setopt(hnd, %s, ", name);
370 for(nv = nvlist; nv->name; nv++) {
371 if((nv->value & ~ rest) == 0) {
372 /* all value flags contained in rest */
373 rest &= ~ nv->value; /* remove bits handled here */
374 CODE3("%s(long)%s%s",
375 preamble, nv->name, rest ? " |" : ");");
376 if(!rest)
377 break; /* handled them all */
378 /* replace with all spaces for continuation line */
379 msnprintf(preamble, sizeof(preamble), "%*s", (int)strlen(preamble),
380 "");
381 }
382 }
383 /* If any bits have no definition, output an explicit value.
384 * This could happen if new bits are defined and used
385 * but the NameValue list is not updated. */
386 if(rest)
387 CODE2("%s%luUL);", preamble, rest);
388 }
389
390 nomem:
391 return ret;
392 }
393
394 /* Generate code for a struct curl_slist. */
libcurl_generate_slist(struct curl_slist * slist,int * slistno)395 static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
396 {
397 CURLcode ret = CURLE_OK;
398 char *escaped = NULL;
399
400 /* May need several slist variables, so invent name */
401 *slistno = ++easysrc_slist_count;
402
403 DECL1("struct curl_slist *slist%d;", *slistno);
404 DATA1("slist%d = NULL;", *slistno);
405 CLEAN1("curl_slist_free_all(slist%d);", *slistno);
406 CLEAN1("slist%d = NULL;", *slistno);
407 for(; slist; slist = slist->next) {
408 Curl_safefree(escaped);
409 escaped = c_escape(slist->data, ZERO_TERMINATED);
410 if(!escaped)
411 return CURLE_OUT_OF_MEMORY;
412 DATA3("slist%d = curl_slist_append(slist%d, \"%s\");",
413 *slistno, *slistno, escaped);
414 }
415
416 nomem:
417 Curl_safefree(escaped);
418 return ret;
419 }
420
421 static CURLcode libcurl_generate_mime(CURL *curl,
422 struct GlobalConfig *config,
423 struct tool_mime *toolmime,
424 int *mimeno); /* Forward. */
425
426 /* Wrapper to generate source code for a mime part. */
libcurl_generate_mime_part(CURL * curl,struct GlobalConfig * config,struct tool_mime * part,int mimeno)427 static CURLcode libcurl_generate_mime_part(CURL *curl,
428 struct GlobalConfig *config,
429 struct tool_mime *part,
430 int mimeno)
431 {
432 CURLcode ret = CURLE_OK;
433 int submimeno = 0;
434 char *escaped = NULL;
435 const char *data = NULL;
436 const char *filename = part->filename;
437
438 /* Parts are linked in reverse order. */
439 if(part->prev) {
440 ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno);
441 if(ret)
442 return ret;
443 }
444
445 /* Create the part. */
446 CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno);
447
448 switch(part->kind) {
449 case TOOLMIME_PARTS:
450 ret = libcurl_generate_mime(curl, config, part, &submimeno);
451 if(!ret) {
452 CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno);
453 CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */
454 }
455 break;
456
457 case TOOLMIME_DATA:
458 data = part->data;
459 if(!ret) {
460 Curl_safefree(escaped);
461 escaped = c_escape(data, ZERO_TERMINATED);
462 NULL_CHECK(escaped);
463 CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);",
464 mimeno, escaped);
465 }
466 break;
467
468 case TOOLMIME_FILE:
469 case TOOLMIME_FILEDATA:
470 escaped = c_escape(part->data, ZERO_TERMINATED);
471 NULL_CHECK(escaped);
472 CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped);
473 if(part->kind == TOOLMIME_FILEDATA && !filename) {
474 CODE1("curl_mime_filename(part%d, NULL);", mimeno);
475 }
476 break;
477
478 case TOOLMIME_STDIN:
479 if(!filename)
480 filename = "-";
481 FALLTHROUGH();
482 case TOOLMIME_STDINDATA:
483 /* Can only be reading stdin in the current context. */
484 CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\",
485 mimeno);
486 CODE0(" (curl_seek_callback) fseek, NULL, stdin);");
487 break;
488 default:
489 /* Other cases not possible in this context. */
490 break;
491 }
492
493 if(!ret && part->encoder) {
494 Curl_safefree(escaped);
495 escaped = c_escape(part->encoder, ZERO_TERMINATED);
496 NULL_CHECK(escaped);
497 CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped);
498 }
499
500 if(!ret && filename) {
501 Curl_safefree(escaped);
502 escaped = c_escape(filename, ZERO_TERMINATED);
503 NULL_CHECK(escaped);
504 CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped);
505 }
506
507 if(!ret && part->name) {
508 Curl_safefree(escaped);
509 escaped = c_escape(part->name, ZERO_TERMINATED);
510 NULL_CHECK(escaped);
511 CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped);
512 }
513
514 if(!ret && part->type) {
515 Curl_safefree(escaped);
516 escaped = c_escape(part->type, ZERO_TERMINATED);
517 NULL_CHECK(escaped);
518 CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped);
519 }
520
521 if(!ret && part->headers) {
522 int slistno;
523
524 ret = libcurl_generate_slist(part->headers, &slistno);
525 if(!ret) {
526 CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno);
527 CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */
528 }
529 }
530
531 nomem:
532 Curl_safefree(escaped);
533 return ret;
534 }
535
536 /* Wrapper to generate source code for a mime structure. */
libcurl_generate_mime(CURL * curl,struct GlobalConfig * config,struct tool_mime * toolmime,int * mimeno)537 static CURLcode libcurl_generate_mime(CURL *curl,
538 struct GlobalConfig *config,
539 struct tool_mime *toolmime,
540 int *mimeno)
541 {
542 CURLcode ret = CURLE_OK;
543
544 /* May need several mime variables, so invent name. */
545 *mimeno = ++easysrc_mime_count;
546 DECL1("curl_mime *mime%d;", *mimeno);
547 DATA1("mime%d = NULL;", *mimeno);
548 CODE1("mime%d = curl_mime_init(hnd);", *mimeno);
549 CLEAN1("curl_mime_free(mime%d);", *mimeno);
550 CLEAN1("mime%d = NULL;", *mimeno);
551
552 if(toolmime->subparts) {
553 DECL1("curl_mimepart *part%d;", *mimeno);
554 ret = libcurl_generate_mime_part(curl, config,
555 toolmime->subparts, *mimeno);
556 }
557
558 nomem:
559 return ret;
560 }
561
562 /* setopt wrapper for CURLOPT_MIMEPOST */
tool_setopt_mimepost(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,curl_mime * mimepost)563 CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
564 const char *name, CURLoption tag,
565 curl_mime *mimepost)
566 {
567 CURLcode ret = curl_easy_setopt(curl, tag, mimepost);
568 int mimeno = 0;
569
570 if(!ret && config->libcurl) {
571 ret = libcurl_generate_mime(curl, config,
572 config->current->mimeroot, &mimeno);
573
574 if(!ret)
575 CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno);
576 }
577
578 nomem:
579 return ret;
580 }
581
582 /* setopt wrapper for curl_slist options */
tool_setopt_slist(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,struct curl_slist * list)583 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
584 const char *name, CURLoption tag,
585 struct curl_slist *list)
586 {
587 CURLcode ret = CURLE_OK;
588
589 ret = curl_easy_setopt(curl, tag, list);
590
591 if(config->libcurl && list && !ret) {
592 int i;
593
594 ret = libcurl_generate_slist(list, &i);
595 if(!ret)
596 CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
597 }
598
599 nomem:
600 return ret;
601 }
602
603 /* generic setopt wrapper for all other options.
604 * Some type information is encoded in the tag value. */
tool_setopt(CURL * curl,bool str,struct GlobalConfig * global,struct OperationConfig * config,const char * name,CURLoption tag,...)605 CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
606 struct OperationConfig *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 struct 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 msnprintf(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 = "function pointer";
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 = "object pointer";
658 remark = TRUE;
659 }
660 else
661 skip = TRUE;
662
663 ret = curl_easy_setopt(curl, tag, pval);
664
665 }
666 else if(tag < CURLOPTTYPE_BLOB) {
667 /* Value is expected to be curl_off_t */
668 curl_off_t oval = va_arg(arg, curl_off_t);
669 msnprintf(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 else {
678 /* Value is a blob */
679 void *pblob = va_arg(arg, void *);
680
681 /* blobs are never printable */
682 if(pblob) {
683 value = "blob pointer";
684 remark = TRUE;
685 }
686 else
687 skip = TRUE;
688
689 ret = curl_easy_setopt(curl, tag, pblob);
690 }
691
692 va_end(arg);
693
694 if(global->libcurl && !skip && !ret) {
695 /* we only use this for real if --libcurl was used */
696
697 if(remark)
698 REM3("%s was set to a%s %s", name, (*value == 'o' ? "n" : ""), value);
699 else {
700 if(escape) {
701 curl_off_t len = ZERO_TERMINATED;
702 if(tag == CURLOPT_POSTFIELDS)
703 len = curlx_dyn_len(&config->postdata);
704 escaped = c_escape(value, len);
705 NULL_CHECK(escaped);
706 CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
707 }
708 else
709 CODE2("curl_easy_setopt(hnd, %s, %s);", name, value);
710 }
711 }
712
713 nomem:
714 Curl_safefree(escaped);
715 return ret;
716 }
717
718 #else /* CURL_DISABLE_LIBCURL_OPTION */
719
720 #endif /* CURL_DISABLE_LIBCURL_OPTION */
721