diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index ba1e78e0d..f672386a1 100644 --- a/src/tool_easysrc.c +++ b/src/tool_easysrc.c @@ -37,8 +37,13 @@ /* global variable definitions, for easy-interface source code generation */ -struct curl_slist *easysrc = NULL; -struct curl_slist *easysrc_remarks = NULL; +struct curl_slist *easysrc_decl = NULL; /* Variable declarations */ +struct curl_slist *easysrc_data = NULL; /* Build slists, forms etc. */ +struct curl_slist *easysrc_code = NULL; /* Setopt calls */ +struct curl_slist *easysrc_toohard = NULL; /* Unconvertible setopt */ +struct curl_slist *easysrc_clean = NULL; /* Clean up allocated data */ +int easysrc_form_count = 0; +int easysrc_slist_count = 0; static const char *const srchead[]={ "/********* Sample code generated by the curl command line tool **********", @@ -50,8 +55,117 @@ static const char *const srchead[]={ "int main(int argc, char *argv[])", "{", " CURLcode ret;", + " CURL *hnd;", NULL }; +/* easysrc_decl declarations come here */ +/* easysrc_data initialisations come here */ +/* easysrc_code statements come here */ +static const char *const srchard[]={ + "/* Here is a list of options the curl code used that cannot get generated", + " as source easily. You may select to either not use them or implement", + " them yourself.", + "", + NULL +}; +static const char *const srcend[]={ + "", + " return (int)ret;", + "}", + "/**** End of sample code ****/", + NULL +}; + +/* Clean up all source code if we run out of memory */ +static void easysrc_free(void) +{ + curl_slist_free_all(easysrc_decl); + easysrc_decl = NULL; + curl_slist_free_all(easysrc_data); + easysrc_data = NULL; + curl_slist_free_all(easysrc_code); + easysrc_code = NULL; + curl_slist_free_all(easysrc_toohard); + easysrc_toohard = NULL; + curl_slist_free_all(easysrc_clean); + easysrc_clean = NULL; +} + +/* Add a source line to the main code or remarks */ +CURLcode easysrc_add(struct curl_slist **plist, const char *line) +{ + CURLcode ret = CURLE_OK; + struct curl_slist *list = + curl_slist_append(*plist, line); + if(!list) { + easysrc_free(); + ret = CURLE_OUT_OF_MEMORY; + } + else + *plist = list; + return ret; +} + +CURLcode easysrc_addf(struct curl_slist **plist, const char *fmt, ...) +{ + CURLcode ret; + char *bufp; + va_list ap; + va_start(ap, fmt); + bufp = curlx_mvaprintf(fmt, ap); + va_end(ap); + if(! bufp) { + ret = CURLE_OUT_OF_MEMORY; + } + else { + ret = easysrc_add(plist, bufp); + curl_free(bufp); + } + return ret; +} + +#define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} while(0) + +CURLcode easysrc_init(void) +{ + CHKRET(easysrc_add(&easysrc_code, + "hnd = curl_easy_init();")); + return CURLE_OK; +} + +CURLcode easysrc_perform(void) +{ + /* Note any setopt calls which we could not convert */ + if(easysrc_toohard) { + int i; + struct curl_slist *ptr; + const char *c; + CHKRET(easysrc_add(&easysrc_code, "")); + /* Preamble comment */ + for(i=0; ((c = srchard[i]) != '\0'); i++) + CHKRET(easysrc_add(&easysrc_code, c)); + /* Each unconverted option */ + for(ptr=easysrc_toohard; ptr; ptr = ptr->next) + CHKRET(easysrc_add(&easysrc_code, ptr->data)); + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "*/")); + + curl_slist_free_all(easysrc_toohard); + easysrc_toohard = NULL; + } + + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);")); + return CURLE_OK; +} + +CURLcode easysrc_cleanup(void) +{ + CHKRET(easysrc_add(&easysrc_code, "")); + CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);")); + CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;")); + return CURLE_OK; +} void dumpeasysrc(struct Configurable *config) { @@ -76,40 +190,40 @@ void dumpeasysrc(struct Configurable *config) for(i=0; ((c = srchead[i]) != '\0'); i++) fprintf(out, "%s\n", c); - ptr = easysrc; - while(ptr) { + /* Declare variables used for complex setopt values */ + for(ptr=easysrc_decl; ptr; ptr = ptr->next) fprintf(out, " %s\n", ptr->data); - ptr = ptr->next; - } - ptr = easysrc_remarks; - if(ptr) { - fprintf(out, - "\n /* Here is a list of options the curl code" - " used that cannot get generated\n" - " as source easily. You may select to either" - " not use them or implement\n them yourself.\n" - "\n"); - while(ptr) { + /* Set up complex values for setopt calls */ + if(easysrc_data) { + fprintf(out, "\n"); + + for(ptr=easysrc_data; ptr; ptr = ptr->next) fprintf(out, " %s\n", ptr->data); - ptr = ptr->next; - } - fprintf(out, "\n */\n"); } - fprintf(out, - " return (int)ret;\n" - "}\n" - "/**** End of sample code ****/\n"); + fprintf(out, "\n"); + for(ptr=easysrc_code; ptr; ptr = ptr->next) { + if(ptr->data[0]) { + fprintf(out, " %s\n", ptr->data); + } + else { + fprintf(out, "\n"); + } + } + + for(ptr=easysrc_clean; ptr; ptr = ptr->next) + fprintf(out, " %s\n", ptr->data); + + for(i=0; ((c = srcend[i]) != '\0'); i++) + fprintf(out, "%s\n", c); + if(fopened) fclose(out); } } - curl_slist_free_all(easysrc_remarks); - curl_slist_free_all(easysrc); - easysrc_remarks = NULL; - easysrc = NULL; + easysrc_free(); } #endif /* CURL_DISABLE_LIBCURL_OPTION */ diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h index 8e81d5567..1d2c02765 100644 --- a/src/tool_easysrc.h +++ b/src/tool_easysrc.h @@ -26,12 +26,22 @@ /* global variable declarations, for easy-interface source code generation */ -extern struct curl_slist *easysrc; -extern struct curl_slist *easysrc_remarks; +extern struct curl_slist *easysrc_decl; /* Variable declarations */ +extern struct curl_slist *easysrc_data; /* Build slists, forms etc. */ +extern struct curl_slist *easysrc_code; /* Setopt calls etc. */ +extern struct curl_slist *easysrc_toohard; /* Unconvertible setopt */ +extern struct curl_slist *easysrc_clean; /* Clean up (reverse order) */ +extern int easysrc_form_count; /* Number of curl_httppost variables */ +extern int easysrc_slist_count; /* Number of curl_slist variables */ + +extern CURLcode easysrc_init(void); +extern CURLcode easysrc_add(struct curl_slist **plist, const char *bupf); +extern CURLcode easysrc_addf(struct curl_slist **plist, const char *fmt, ...); +extern CURLcode easysrc_perform(void); +extern CURLcode easysrc_cleanup(void); void dumpeasysrc(struct Configurable *config); -#endif /* CURL_DISABLE_LIBCIRL_CMD */ +#endif /* CURL_DISABLE_LIBCURL_OPTION */ #endif /* HEADER_CURL_TOOL_EASYSRC_H */ - diff --git a/src/tool_operate.c b/src/tool_operate.c index 3e496bfd2..d070ea64a 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -355,11 +355,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } #ifndef CURL_DISABLE_LIBCURL_OPTION - /* This is the first entry added to easysrc and it initializes the slist */ - easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();"); - if(!easysrc) { + res = easysrc_init(); + if(res) { helpf(config->errors, "out of memory\n"); - res = CURLE_OUT_OF_MEMORY; goto quit_curl; } #endif @@ -835,25 +833,25 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* new in libcurl 7.5 */ if(config->proxy) - my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver); + my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver); /* new in libcurl 7.10 */ if(config->socksproxy) { my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy); - my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver); + my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->socksver); } /* new in libcurl 7.10.6 */ if(config->proxyanyauth) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); else if(config->proxynegotiate) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); + my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); else if(config->proxyntlm) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); + my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); else if(config->proxydigest) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); + my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); else if(config->proxybasic) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); + my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); /* new in libcurl 7.19.4 */ my_setopt(curl, CURLOPT_NOPROXY, config->noproxy); @@ -896,7 +894,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) config->postfieldsize); break; case HTTPREQ_POST: - my_setopt(curl, CURLOPT_HTTPPOST, config->httppost); + my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost); break; default: break; @@ -905,18 +903,18 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) my_setopt_str(curl, CURLOPT_REFERER, config->referer); my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer); my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); - my_setopt(curl, CURLOPT_HTTPHEADER, config->headers); + my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); /* new in libcurl 7.5 */ my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); /* new in libcurl 7.9.1 */ if(config->httpversion) - my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion); + my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion); /* new in libcurl 7.10.6 (default is Basic) */ if(config->authtype) - my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype); + my_setopt_flags(curl, CURLOPT_HTTPAUTH, config->authtype); /* curl 7.19.1 (the 301 version existed in 7.18.2) */ my_setopt(curl, CURLOPT_POSTREDIR, config->post301 | @@ -1011,9 +1009,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } my_setopt(curl, CURLOPT_CRLF, config->crlf); - my_setopt(curl, CURLOPT_QUOTE, config->quote); - my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote); - my_setopt(curl, CURLOPT_PREQUOTE, config->prequote); + my_setopt_slist(curl, CURLOPT_QUOTE, config->quote); + my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote); + my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) { @@ -1034,8 +1032,8 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } #endif - my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version); - my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond); + my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version); + my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond); my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime); my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); my_setopt(curl, CURLOPT_STDERR, config->errors); @@ -1054,7 +1052,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) } /* new in libcurl 7.6.2: */ - my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); + my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); /* new in libcurl 7.7: */ my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file); @@ -1118,7 +1116,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) /* new in curl 7.16.1 */ if(config->ftp_ssl_ccc) - my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); + my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) { @@ -1191,16 +1189,16 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); if(config->mail_rcpt) - my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); + my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); /* curl 7.20.x */ if(config->ftp_pret) my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE); if(config->proto_present) - my_setopt(curl, CURLOPT_PROTOCOLS, config->proto); + my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto); if(config->proto_redir_present) - my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); + my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); if((urlnode->flags & GETOUT_USEREMOTE) && config->content_disposition) { @@ -1216,7 +1214,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) if(config->resolve) /* new in 7.21.3 */ - my_setopt(curl, CURLOPT_RESOLVE, config->resolve); + my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve); /* new in 7.21.4 */ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { @@ -1252,8 +1250,8 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) retrystart = tvnow(); #ifndef CURL_DISABLE_LIBCURL_OPTION - if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) { - res = CURLE_OUT_OF_MEMORY; + res = easysrc_perform(); + if(res) { goto show_error; } #endif @@ -1580,8 +1578,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) config->easy = curl = NULL; } #ifndef CURL_DISABLE_LIBCURL_OPTION - if(easysrc) - curl_slist_append(easysrc, "curl_easy_cleanup(hnd);"); + easysrc_cleanup(); #endif /* Close function-local opened file descriptors */ diff --git a/src/tool_setopt.c b/src/tool_setopt.c index 6fc604716..5be4c3b39 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -35,43 +35,397 @@ #include "memdebug.h" /* keep this as LAST include */ +/* Lookup tables for converting setopt values back to symbols */ +/* For enums, values may be in any order. */ +/* For bit masks, put combinations first, then single bits, */ +/* and finally any "NONE" value. */ + +#define NV(e) {#e, e} +#define NVEND {NULL, 0} /* sentinel to mark end of list */ + +const NameValue setopt_nv_CURLPROXY[] = { + NV(CURLPROXY_HTTP), + NV(CURLPROXY_HTTP_1_0), + NV(CURLPROXY_SOCKS4), + NV(CURLPROXY_SOCKS5), + NV(CURLPROXY_SOCKS4A), + NV(CURLPROXY_SOCKS5_HOSTNAME), + NVEND, +}; + +const NameValue setopt_nv_CURLAUTH[] = { + NV(CURLAUTH_ANY), /* combination */ + NV(CURLAUTH_ANYSAFE), /* combination */ + NV(CURLAUTH_BASIC), + NV(CURLAUTH_DIGEST), + NV(CURLAUTH_GSSNEGOTIATE), + NV(CURLAUTH_NTLM), + NV(CURLAUTH_DIGEST_IE), + NV(CURLAUTH_NTLM_WB), + NV(CURLAUTH_ONLY), + NV(CURLAUTH_NONE), + NVEND, +}; + +const NameValue setopt_nv_CURL_HTTP_VERSION[] = { + NV(CURL_HTTP_VERSION_NONE), + NV(CURL_HTTP_VERSION_1_0), + NV(CURL_HTTP_VERSION_1_1), + NVEND, +}; + +const NameValue setopt_nv_CURL_SSLVERSION[] = { + NV(CURL_SSLVERSION_DEFAULT), + NV(CURL_SSLVERSION_TLSv1), + NV(CURL_SSLVERSION_SSLv2), + NV(CURL_SSLVERSION_SSLv3), + NVEND, +}; + +const NameValue setopt_nv_CURL_TIMECOND[] = { + NV(CURL_TIMECOND_IFMODSINCE), + NV(CURL_TIMECOND_IFUNMODSINCE), + NV(CURL_TIMECOND_LASTMOD), + NV(CURL_TIMECOND_NONE), + NVEND, +}; + +const NameValue setopt_nv_CURLFTPSSL_CCC[] = { + NV(CURLFTPSSL_CCC_NONE), + NV(CURLFTPSSL_CCC_PASSIVE), + NV(CURLFTPSSL_CCC_ACTIVE), + NVEND, +}; + +/* These mappings essentially triplicated - see + * tool_libinfo.c and tool_paramhlp.c */ +const NameValue setopt_nv_CURLPROTO[] = { + NV(CURLPROTO_ALL), /* combination */ + NV(CURLPROTO_DICT), + NV(CURLPROTO_FILE), + NV(CURLPROTO_FTP), + NV(CURLPROTO_FTPS), + NV(CURLPROTO_GOPHER), + NV(CURLPROTO_HTTP), + NV(CURLPROTO_HTTPS), + NV(CURLPROTO_IMAP), + NV(CURLPROTO_IMAPS), + NV(CURLPROTO_LDAP), + NV(CURLPROTO_LDAPS), + NV(CURLPROTO_POP3), + NV(CURLPROTO_POP3S), + NV(CURLPROTO_RTSP), + NV(CURLPROTO_SCP), + NV(CURLPROTO_SFTP), + NV(CURLPROTO_SMTP), + NV(CURLPROTO_SMTPS), + NV(CURLPROTO_TELNET), + NV(CURLPROTO_TFTP), + NVEND, +}; + +/* Format and add code; jump to nomem on malloc error */ +#define ADD(args) do { \ + ret = easysrc_add args; \ + if(ret) \ + goto nomem; \ +} while(0) +#define ADDF(args) do { \ + ret = easysrc_addf args; \ + if(ret) \ + goto nomem; \ +} while(0) + +#define DECL0(s) ADD((&easysrc_decl, s)) +#define DECL1(f,a) ADDF((&easysrc_decl, f,a)) + +#define DATA0(s) ADD((&easysrc_data, s)) +#define DATA1(f,a) ADDF((&easysrc_data, f,a)) +#define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) +#define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) + +#define CODE0(s) ADD((&easysrc_code, s)) +#define CODE1(f,a) ADDF((&easysrc_code, f,a)) +#define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) +#define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) + +#define CLEAN0(s) ADD((&easysrc_clean, s)) +#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) + +#define REM0(s) ADD((&easysrc_toohard, s)) +#define REM1(f,a) ADDF((&easysrc_toohard, f,a)) +#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) + +/* Escape string to C string syntax. Return NULL if out of memory. + * Is this correct for those wacky EBCDIC guys? */ +static char *c_escape(const char *str) +{ + size_t len = 0; + const char *s; + unsigned char c; + char *escaped, *e; + /* Allocate space based on worst-case */ + len = strlen(str); + escaped = malloc(4 * len + 1); + if(!escaped) + return NULL; + + e = escaped; + for(s=str; (c=*s) != '\0'; s++) { + if(c=='\n') { + strcpy(e, "\\n"); + e += 2; + } + else if(c=='\r') { + strcpy(e, "\\r"); + e += 2; + } + else if(c=='\t') { + strcpy(e, "\\t"); + e += 2; + } + else if(c=='\\') { + strcpy(e, "\\\\"); + e += 2; + } + else if(c=='"') { + strcpy(e, "\\\""); + e += 2; + } + else if(! isprint(c)) { + sprintf(e, "\\%03o", c); + e += 4; + } + else + *e++ = c; + } + *e = '\0'; + return escaped; +} + +/* setopt wrapper for enum types */ +CURLcode tool_setopt_enum(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + const NameValue *nvlist, long lval) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + const NameValue *nv = NULL; + for(nv=nvlist; nv->name; nv++) { + if(nv->value == lval) break; /* found it */ + } + if(! nv->name) { + /* If no definition was found, output an explicit value. + * This could happen if new values are defined and used + * but the NameValue list is not updated. */ + CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); + } + else { + CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); + } + } + + nomem: + return ret; +} + +/* setopt wrapper for bit mask */ +CURLcode tool_setopt_flags(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + const NameValue *nvlist, long lval) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + char preamble[80]; /* should accommodate any symbol name */ + long rest = lval; /* bits not handled yet */ + const NameValue *nv = NULL; + snprintf(preamble, sizeof(preamble), + "curl_easy_setopt(hnd, %s, ", name); + for(nv=nvlist; nv->name; nv++) { + if((nv->value & ~ rest) == 0) { + /* all value flags contained in rest */ + rest &= ~ nv->value; /* remove bits handled here */ + CODE3("%s(long)%s%s", + preamble, nv->name, rest ? " |" : ");"); + if(!rest) + break; /* handled them all */ + /* replace with all spaces for continuation line */ + sprintf(preamble, "%*s", strlen(preamble), ""); + } + } + /* If any bits have no definition, output an explicit value. + * This could happen if new bits are defined and used + * but the NameValue list is not updated. */ + if(rest) + CODE2("%s%ldL);", preamble, rest); + } + + nomem: + return ret; +} + +/* setopt wrapper for CURLOPT_HTTPPOST */ +CURLcode tool_setopt_httppost(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + struct curl_httppost *post) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, post); + if(!post) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + struct curl_httppost *pp, *p; + int i; + /* May use several httppost lists, if multiple POST actions */ + i = ++ easysrc_form_count; + DECL1("struct curl_httppost *post%d;", i); + DATA1("post%d = NULL;", i); + CLEAN1("curl_formfree(post%d);", i); + CLEAN1("post%d = NULL;", i); + if(i == 1) + DECL0("struct curl_httppost *postend;"); + DATA0("postend = NULL;"); + for(p=post; p; p=p->next) { + DATA1("curl_formadd(&post%d, &postend,", i); + DATA1(" CURLFORM_COPYNAME, \"%s\",", p->name); + for(pp=p; pp; pp=pp->more) { + /* May be several files uploaded for one name; + * these are linked through the 'more' pointer */ + char *e; + e = c_escape(pp->contents); + if(!e) + goto nomem; + if(pp->flags & HTTPPOST_FILENAME) { + /* file upload as for -F @filename */ + DATA1(" CURLFORM_FILE, \"%s\",", e); + } + else if(pp->flags & HTTPPOST_READFILE) { + /* content from file as for -F showfilename) { + e = c_escape(pp->showfilename); + if(!e) + goto nomem; + DATA1(" CURLFORM_FILENAME, \"%s\",", e); + free(e); + } + if(pp->contenttype) { + e = c_escape(pp->contenttype); + if(!e) + goto nomem; + DATA1(" CURLFORM_CONTENTTYPE, \"%s\",", e); + free(e); + } + } + DATA0(" CURLFORM_END);"); + } + CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i); + } + + nomem: + return ret; +} + +/* setopt wrapper for curl_slist options */ +CURLcode tool_setopt_slist(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + struct curl_slist *list) +{ + CURLcode ret = CURLE_OK; + bool skip = FALSE; + + ret = curl_easy_setopt(curl, tag, list); + if(!list) + skip = TRUE; + + if(config->libcurl && !skip && !ret) { + struct curl_slist *s; + int i; + /* May need several slist variables, so invent name */ + i = ++ easysrc_slist_count; + DECL1("struct curl_slist *slist%d;", i); + DATA1("slist%d = NULL;", i); + CLEAN1("curl_slist_free_all(slist%d);", i); + CLEAN1("slist%d = NULL;", i); + for(s=list; s; s=s->next) { + char *e = c_escape(s->data); + if(!e) + goto nomem; + DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, e); + free(e); + } + CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); + } + + nomem: + return ret; +} + +/* generic setopt wrapper for all other options. + * Some type information is encoded in the tag value. */ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, const char *name, CURLoption tag, ...) { va_list arg; - char *bufp; - char value[256]; + char buf[256]; + const char *value; bool remark = FALSE; bool skip = FALSE; + bool escape = FALSE; CURLcode ret = CURLE_OK; va_start(arg, tag); if(tag < CURLOPTTYPE_OBJECTPOINT) { + /* Value is expected to be a long */ long lval = va_arg(arg, long); - snprintf(value, sizeof(value), "%ldL", lval); + snprintf(buf, sizeof(buf), "%ldL", lval); + value = buf; ret = curl_easy_setopt(curl, tag, lval); if(!lval) skip = TRUE; } else if(tag < CURLOPTTYPE_OFF_T) { + /* Value is some sort of object pointer */ void *pval = va_arg(arg, void *); - unsigned char *ptr = (unsigned char *)pval; /* function pointers are never printable */ if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { if(pval) { - strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */ + value = "functionpointer"; remark = TRUE; } else skip = TRUE; } - else if(pval && str) - snprintf(value, sizeof(value), "\"%s\"", (char *)ptr); + else if(pval && str) { + value = (char *)pval; + escape = TRUE; + } else if(pval) { - strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */ + value = "objectpointer"; remark = TRUE; } else @@ -81,9 +435,11 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, } else { + /* Value is expected to be curl_off_t */ curl_off_t oval = va_arg(arg, curl_off_t); - snprintf(value, sizeof(value), + snprintf(buf, sizeof(buf), "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); + value = buf; ret = curl_easy_setopt(curl, tag, oval); if(!oval) @@ -96,32 +452,21 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, /* we only use this for real if --libcurl was used */ if(remark) - bufp = curlx_maprintf("%s set to a %s", name, value); - else - bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value); - - if(!bufp) - ret = CURLE_OUT_OF_MEMORY; + REM2("%s set to a %s", name, value); else { - struct curl_slist *list = - curl_slist_append(remark?easysrc_remarks:easysrc, bufp); - - curl_free(bufp); - - if(!list) { - curl_slist_free_all(easysrc_remarks); - curl_slist_free_all(easysrc); - easysrc_remarks = NULL; - easysrc = NULL; - ret = CURLE_OUT_OF_MEMORY; + if(escape) { + char *escaped = c_escape(value); + if(!escaped) + goto nomem; + CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); + free(escaped); } - else if(remark) - easysrc_remarks = list; else - easysrc = list; + CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); } } + nomem: return ret; } diff --git a/src/tool_setopt.h b/src/tool_setopt.h index fcd60f856..4189addae 100644 --- a/src/tool_setopt.h +++ b/src/tool_setopt.h @@ -35,8 +35,45 @@ #ifndef CURL_DISABLE_LIBCURL_OPTION +/* Associate symbolic names with option values */ +typedef struct { + const char *name; + long value; +} NameValue; + +extern const NameValue setopt_nv_CURLPROXY[]; +extern const NameValue setopt_nv_CURLAUTH[]; +extern const NameValue setopt_nv_CURL_HTTP_VERSION[]; +extern const NameValue setopt_nv_CURL_SSLVERSION[]; +extern const NameValue setopt_nv_CURL_TIMECOND[]; +extern const NameValue setopt_nv_CURLFTPSSL_CCC[]; +extern const NameValue setopt_nv_CURLPROTO[]; + +/* Map options to NameValue sets */ +#define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION +#define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH +#define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION +#define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND +#define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC +#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO +#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO +#define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY +#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH + /* Intercept setopt calls for --libcurl */ +CURLcode tool_setopt_enum(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + const NameValue *nv, long lval); +CURLcode tool_setopt_flags(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + const NameValue *nv, long lval); +CURLcode tool_setopt_httppost(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + struct curl_httppost *httppost); +CURLcode tool_setopt_slist(CURL *curl, struct Configurable *config, + const char *name, CURLoption tag, + struct curl_slist *list); CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, const char *name, CURLoption tag, ...); @@ -46,11 +83,23 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, #define my_setopt_str(x,y,z) \ SETOPT_CHECK(tool_setopt(x, TRUE, config, #y, y, z)) +#define my_setopt_enum(x,y,z) \ + SETOPT_CHECK(tool_setopt_enum(x, config, #y, y, setopt_nv_ ## y, z)) + +#define my_setopt_flags(x,y,z) \ + SETOPT_CHECK(tool_setopt_flags(x, config, #y, y, setopt_nv_ ## y, z)) + +#define my_setopt_httppost(x,y,z) \ + SETOPT_CHECK(tool_setopt_httppost(x, config, #y, y, z)) + +#define my_setopt_slist(x,y,z) \ + SETOPT_CHECK(tool_setopt_slist(x, config, #y, y, z)) + #define res_setopt(x,y,z) tool_setopt(x, FALSE, config, #y, y, z) #define res_setopt_str(x,y,z) tool_setopt(x, TRUE, config, #y, y, z) -#else +#else /* CURL_DISABLE_LIBCURL_OPTION */ /* No --libcurl, so pass options directly to library */ @@ -60,6 +109,18 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, #define my_setopt_str(x,y,z) \ SETOPT_CHECK(curl_easy_setopt(x, y, z)) +#define my_setopt_enum(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z)) + +#define my_setopt_flags(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z)) + +#define my_setopt_httppost(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z)) + +#define my_setopt_slist(x,y,z) \ + SETOPT_CHECK(curl_easy_setopt(x, y, z)) + #define res_setopt(x,y,z) curl_easy_setopt(x,y,z) #define res_setopt_str(x,y,z) curl_easy_setopt(x,y,z)