1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22#include "tool_setup.h"
23
24#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
34#include "memdebug.h" /* keep this as LAST include */
35
36/* Lookup tables for converting setopt values back to symbols */
37/* For enums, values may be in any order. */
38/* For bit masks, put combinations first, then single bits, */
39/* and finally any "NONE" value. */
40
41#define NV(e) {#e, e}
42#define NV1(e, v) {#e, (v)}
43#define NVEND {NULL, 0}         /* sentinel to mark end of list */
44
45const NameValue setopt_nv_CURLPROXY[] = {
46  NV(CURLPROXY_HTTP),
47  NV(CURLPROXY_HTTP_1_0),
48  NV(CURLPROXY_SOCKS4),
49  NV(CURLPROXY_SOCKS5),
50  NV(CURLPROXY_SOCKS4A),
51  NV(CURLPROXY_SOCKS5_HOSTNAME),
52  NVEND,
53};
54
55const NameValueUnsigned setopt_nv_CURLAUTH[] = {
56  NV(CURLAUTH_ANY),             /* combination */
57  NV(CURLAUTH_ANYSAFE),         /* combination */
58  NV(CURLAUTH_BASIC),
59  NV(CURLAUTH_DIGEST),
60  NV(CURLAUTH_GSSNEGOTIATE),
61  NV(CURLAUTH_NTLM),
62  NV(CURLAUTH_DIGEST_IE),
63  NV(CURLAUTH_NTLM_WB),
64  NV(CURLAUTH_ONLY),
65  NV(CURLAUTH_NONE),
66  NVEND,
67};
68
69const NameValue setopt_nv_CURL_HTTP_VERSION[] = {
70  NV(CURL_HTTP_VERSION_NONE),
71  NV(CURL_HTTP_VERSION_1_0),
72  NV(CURL_HTTP_VERSION_1_1),
73  NVEND,
74};
75
76const NameValue setopt_nv_CURL_SSLVERSION[] = {
77  NV(CURL_SSLVERSION_DEFAULT),
78  NV(CURL_SSLVERSION_TLSv1),
79  NV(CURL_SSLVERSION_SSLv2),
80  NV(CURL_SSLVERSION_SSLv3),
81  NVEND,
82};
83
84const NameValue setopt_nv_CURL_TIMECOND[] = {
85  NV(CURL_TIMECOND_IFMODSINCE),
86  NV(CURL_TIMECOND_IFUNMODSINCE),
87  NV(CURL_TIMECOND_LASTMOD),
88  NV(CURL_TIMECOND_NONE),
89  NVEND,
90};
91
92const NameValue setopt_nv_CURLFTPSSL_CCC[] = {
93  NV(CURLFTPSSL_CCC_NONE),
94  NV(CURLFTPSSL_CCC_PASSIVE),
95  NV(CURLFTPSSL_CCC_ACTIVE),
96  NVEND,
97};
98
99/* These mappings essentially triplicated - see
100 * tool_libinfo.c and tool_paramhlp.c */
101const NameValue setopt_nv_CURLPROTO[] = {
102  NV(CURLPROTO_ALL),            /* combination */
103  NV(CURLPROTO_DICT),
104  NV(CURLPROTO_FILE),
105  NV(CURLPROTO_FTP),
106  NV(CURLPROTO_FTPS),
107  NV(CURLPROTO_GOPHER),
108  NV(CURLPROTO_HTTP),
109  NV(CURLPROTO_HTTPS),
110  NV(CURLPROTO_IMAP),
111  NV(CURLPROTO_IMAPS),
112  NV(CURLPROTO_LDAP),
113  NV(CURLPROTO_LDAPS),
114  NV(CURLPROTO_POP3),
115  NV(CURLPROTO_POP3S),
116  NV(CURLPROTO_RTSP),
117  NV(CURLPROTO_SCP),
118  NV(CURLPROTO_SFTP),
119  NV(CURLPROTO_SMTP),
120  NV(CURLPROTO_SMTPS),
121  NV(CURLPROTO_TELNET),
122  NV(CURLPROTO_TFTP),
123  NVEND,
124};
125
126/* These options have non-zero default values. */
127static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
128  NV1(CURLOPT_SSL_VERIFYPEER, 1),
129  NV1(CURLOPT_SSL_VERIFYHOST, 1),
130  NVEND
131};
132
133/* Format and add code; jump to nomem on malloc error */
134#define ADD(args) do { \
135  ret = easysrc_add args; \
136  if(ret) \
137    goto nomem; \
138} WHILE_FALSE
139#define ADDF(args) do { \
140  ret = easysrc_addf args; \
141  if(ret) \
142    goto nomem; \
143} WHILE_FALSE
144
145#define DECL0(s) ADD((&easysrc_decl, s))
146#define DECL1(f,a) ADDF((&easysrc_decl, f,a))
147
148#define DATA0(s) ADD((&easysrc_data, s))
149#define DATA1(f,a) ADDF((&easysrc_data, f,a))
150#define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b))
151#define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c))
152
153#define CODE0(s) ADD((&easysrc_code, s))
154#define CODE1(f,a) ADDF((&easysrc_code, f,a))
155#define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b))
156#define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c))
157
158#define CLEAN0(s) ADD((&easysrc_clean, s))
159#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))
160
161#define REM0(s) ADD((&easysrc_toohard, s))
162#define REM1(f,a) ADDF((&easysrc_toohard, f,a))
163#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b))
164
165/* Escape string to C string syntax.  Return NULL if out of memory.
166 * Is this correct for those wacky EBCDIC guys? */
167static char *c_escape(const char *str)
168{
169  size_t len = 0;
170  const char *s;
171  unsigned char c;
172  char *escaped, *e;
173  /* Allocate space based on worst-case */
174  len = strlen(str);
175  escaped = malloc(4 * len + 1);
176  if(!escaped)
177    return NULL;
178
179  e = escaped;
180  for(s=str; (c=*s) != '\0'; s++) {
181    if(c=='\n') {
182      strcpy(e, "\\n");
183      e += 2;
184    }
185    else if(c=='\r') {
186      strcpy(e, "\\r");
187      e += 2;
188    }
189    else if(c=='\t') {
190      strcpy(e, "\\t");
191      e += 2;
192    }
193    else if(c=='\\') {
194      strcpy(e, "\\\\");
195      e += 2;
196    }
197    else if(c=='"') {
198      strcpy(e, "\\\"");
199      e += 2;
200    }
201    else if(! isprint(c)) {
202      snprintf(e, 4, "\\%03o", c);
203      e += 4;
204    }
205    else
206      *e++ = c;
207  }
208  *e = '\0';
209  return escaped;
210}
211
212/* setopt wrapper for enum types */
213CURLcode tool_setopt_enum(CURL *curl, struct Configurable *config,
214                          const char *name, CURLoption tag,
215                          const NameValue *nvlist, long lval)
216{
217  CURLcode ret = CURLE_OK;
218  bool skip = FALSE;
219
220  ret = curl_easy_setopt(curl, tag, lval);
221  if(!lval)
222    skip = TRUE;
223
224  if(config->libcurl && !skip && !ret) {
225    /* we only use this for real if --libcurl was used */
226    const NameValue *nv = NULL;
227    for(nv=nvlist; nv->name; nv++) {
228      if(nv->value == lval) break; /* found it */
229    }
230    if(! nv->name) {
231      /* If no definition was found, output an explicit value.
232       * This could happen if new values are defined and used
233       * but the NameValue list is not updated. */
234      CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
235    }
236    else {
237      CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name);
238    }
239  }
240
241 nomem:
242  return ret;
243}
244
245/* setopt wrapper for flags */
246CURLcode tool_setopt_flags(CURL *curl, struct Configurable *config,
247                           const char *name, CURLoption tag,
248                           const NameValue *nvlist, long lval)
249{
250  CURLcode ret = CURLE_OK;
251  bool skip = FALSE;
252
253  ret = curl_easy_setopt(curl, tag, lval);
254  if(!lval)
255    skip = TRUE;
256
257  if(config->libcurl && !skip && !ret) {
258    /* we only use this for real if --libcurl was used */
259    char preamble[80];          /* should accommodate any symbol name */
260    long rest = lval;           /* bits not handled yet */
261    const NameValue *nv = NULL;
262    snprintf(preamble, sizeof(preamble),
263             "curl_easy_setopt(hnd, %s, ", name);
264    for(nv=nvlist; nv->name; nv++) {
265      if((nv->value & ~ rest) == 0) {
266        /* all value flags contained in rest */
267        rest &= ~ nv->value;    /* remove bits handled here */
268        CODE3("%s(long)%s%s",
269              preamble, nv->name, rest ? " |" : ");");
270        if(!rest)
271          break;                /* handled them all */
272        /* replace with all spaces for continuation line */
273        snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
274      }
275    }
276    /* If any bits have no definition, output an explicit value.
277     * This could happen if new bits are defined and used
278     * but the NameValue list is not updated. */
279    if(rest)
280      CODE2("%s%ldL);", preamble, rest);
281  }
282
283 nomem:
284  return ret;
285}
286
287/* setopt wrapper for bitmasks */
288CURLcode tool_setopt_bitmask(CURL *curl, struct Configurable *config,
289                             const char *name, CURLoption tag,
290                             const NameValueUnsigned *nvlist,
291                             long lval)
292{
293  CURLcode ret = CURLE_OK;
294  bool skip = FALSE;
295
296  ret = curl_easy_setopt(curl, tag, lval);
297  if(!lval)
298    skip = TRUE;
299
300  if(config->libcurl && !skip && !ret) {
301    /* we only use this for real if --libcurl was used */
302    char preamble[80];
303    unsigned long rest = (unsigned long)lval;
304    const NameValueUnsigned *nv = NULL;
305    snprintf(preamble, sizeof(preamble),
306             "curl_easy_setopt(hnd, %s, ", name);
307    for(nv=nvlist; nv->name; nv++) {
308      if((nv->value & ~ rest) == 0) {
309        /* all value flags contained in rest */
310        rest &= ~ nv->value;    /* remove bits handled here */
311        CODE3("%s(long)%s%s",
312              preamble, nv->name, rest ? " |" : ");");
313        if(!rest)
314          break;                /* handled them all */
315        /* replace with all spaces for continuation line */
316        snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
317      }
318    }
319    /* If any bits have no definition, output an explicit value.
320     * This could happen if new bits are defined and used
321     * but the NameValue list is not updated. */
322    if(rest)
323      CODE2("%s%luUL);", preamble, rest);
324  }
325
326 nomem:
327  return ret;
328}
329
330/* setopt wrapper for CURLOPT_HTTPPOST */
331CURLcode tool_setopt_httppost(CURL *curl, struct Configurable *config,
332                              const char *name, CURLoption tag,
333                              struct curl_httppost *post)
334{
335  CURLcode ret = CURLE_OK;
336  char *escaped = NULL;
337  bool skip = FALSE;
338
339  ret = curl_easy_setopt(curl, tag, post);
340  if(!post)
341    skip = TRUE;
342
343  if(config->libcurl && !skip && !ret) {
344    struct curl_httppost *pp, *p;
345    int i;
346    /* May use several httppost lists, if multiple POST actions */
347    i = ++ easysrc_form_count;
348    DECL1("struct curl_httppost *post%d;", i);
349    DATA1("post%d = NULL;", i);
350    CLEAN1("curl_formfree(post%d);", i);
351    CLEAN1("post%d = NULL;", i);
352    if(i == 1)
353      DECL0("struct curl_httppost *postend;");
354    DATA0("postend = NULL;");
355    for(p=post; p; p=p->next) {
356      DATA1("curl_formadd(&post%d, &postend,", i);
357      DATA1("             CURLFORM_COPYNAME, \"%s\",", p->name);
358      for(pp=p; pp; pp=pp->more) {
359        /* May be several files uploaded for one name;
360         * these are linked through the 'more' pointer */
361        Curl_safefree(escaped);
362        escaped = c_escape(pp->contents);
363        if(!escaped) {
364          ret = CURLE_OUT_OF_MEMORY;
365          goto nomem;
366        }
367        if(pp->flags & HTTPPOST_FILENAME) {
368          /* file upload as for -F @filename */
369          DATA1("             CURLFORM_FILE, \"%s\",", escaped);
370        }
371        else if(pp->flags & HTTPPOST_READFILE) {
372          /* content from file as for -F <filename */
373          DATA1("             CURLFORM_FILECONTENT, \"%s\",", escaped);
374        }
375        else
376          DATA1("             CURLFORM_COPYCONTENTS, \"%s\",", escaped);
377        if(pp->showfilename) {
378          Curl_safefree(escaped);
379          escaped = c_escape(pp->showfilename);
380          if(!escaped) {
381            ret = CURLE_OUT_OF_MEMORY;
382            goto nomem;
383          }
384          DATA1("             CURLFORM_FILENAME, \"%s\",", escaped);
385        }
386        if(pp->contenttype) {
387          Curl_safefree(escaped);
388          escaped = c_escape(pp->contenttype);
389          if(!escaped) {
390            ret = CURLE_OUT_OF_MEMORY;
391            goto nomem;
392          }
393          DATA1("             CURLFORM_CONTENTTYPE, \"%s\",", escaped);
394        }
395      }
396      DATA0("             CURLFORM_END);");
397    }
398    CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i);
399  }
400
401 nomem:
402  Curl_safefree(escaped);
403  return ret;
404}
405
406/* setopt wrapper for curl_slist options */
407CURLcode tool_setopt_slist(CURL *curl, struct Configurable *config,
408                           const char *name, CURLoption tag,
409                           struct curl_slist *list)
410{
411  CURLcode ret = CURLE_OK;
412  char *escaped = NULL;
413  bool skip = FALSE;
414
415  ret = curl_easy_setopt(curl, tag, list);
416  if(!list)
417    skip = TRUE;
418
419  if(config->libcurl && !skip && !ret) {
420    struct curl_slist *s;
421    int i;
422    /* May need several slist variables, so invent name */
423    i = ++ easysrc_slist_count;
424    DECL1("struct curl_slist *slist%d;", i);
425    DATA1("slist%d = NULL;", i);
426    CLEAN1("curl_slist_free_all(slist%d);", i);
427    CLEAN1("slist%d = NULL;", i);
428    for(s=list; s; s=s->next) {
429      Curl_safefree(escaped);
430      escaped = c_escape(s->data);
431      if(!escaped) {
432        ret = CURLE_OUT_OF_MEMORY;
433        goto nomem;
434      }
435      DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped);
436    }
437    CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
438  }
439
440 nomem:
441  Curl_safefree(escaped);
442  return ret;
443}
444
445/* generic setopt wrapper for all other options.
446 * Some type information is encoded in the tag value. */
447CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
448                     const char *name, CURLoption tag, ...)
449{
450  va_list arg;
451  char buf[256];
452  const char *value = NULL;
453  bool remark = FALSE;
454  bool skip = FALSE;
455  bool escape = FALSE;
456  char *escaped = NULL;
457  CURLcode ret = CURLE_OK;
458
459  va_start(arg, tag);
460
461  if(tag < CURLOPTTYPE_OBJECTPOINT) {
462    /* Value is expected to be a long */
463    long lval = va_arg(arg, long);
464    long defval = 0L;
465    const NameValue *nv = NULL;
466    for(nv=setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
467      if(!strcmp(name, nv->name)) {
468        defval = nv->value;
469        break; /* found it */
470      }
471    }
472
473    snprintf(buf, sizeof(buf), "%ldL", lval);
474    value = buf;
475    ret = curl_easy_setopt(curl, tag, lval);
476    if(lval == defval)
477      skip = TRUE;
478  }
479  else if(tag < CURLOPTTYPE_OFF_T) {
480    /* Value is some sort of object pointer */
481    void *pval = va_arg(arg, void *);
482
483    /* function pointers are never printable */
484    if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
485      if(pval) {
486        value = "functionpointer";
487        remark = TRUE;
488      }
489      else
490        skip = TRUE;
491    }
492
493    else if(pval && str) {
494      value = (char *)pval;
495      escape = TRUE;
496    }
497    else if(pval) {
498      value = "objectpointer";
499      remark = TRUE;
500    }
501    else
502      skip = TRUE;
503
504    ret = curl_easy_setopt(curl, tag, pval);
505
506  }
507  else {
508    /* Value is expected to be curl_off_t */
509    curl_off_t oval = va_arg(arg, curl_off_t);
510    snprintf(buf, sizeof(buf),
511             "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
512    value = buf;
513    ret = curl_easy_setopt(curl, tag, oval);
514
515    if(!oval)
516      skip = TRUE;
517  }
518
519  va_end(arg);
520
521  if(config->libcurl && !skip && !ret) {
522    /* we only use this for real if --libcurl was used */
523
524    if(remark)
525      REM2("%s set to a %s", name, value);
526    else {
527      if(escape) {
528        escaped = c_escape(value);
529        if(!escaped) {
530          ret = CURLE_OUT_OF_MEMORY;
531          goto nomem;
532        }
533        CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
534      }
535      else
536        CODE2("curl_easy_setopt(hnd, %s, %s);", name, value);
537    }
538  }
539
540 nomem:
541  Curl_safefree(escaped);
542  return ret;
543}
544
545#endif /* CURL_DISABLE_LIBCURL_OPTION */
546