2 * OAuth http functions in POSIX-C.
4 * Copyright 2007-2011 Robin Gareus <robin@gareus.org>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 # define snprintf _snprintf
41 #define OAUTH_USER_AGENT "liboauth-agent/" VERSION
43 #ifdef HAVE_CURL /* HTTP requests via libcurl */
44 #include <curl/curl.h>
46 # define GLOBAL_CURL_ENVIROMENT_OPTIONS \
47 if (getenv("CURLOPT_PROXYAUTH")){ \
48 curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); \
50 if (getenv("CURLOPT_SSL_VERIFYPEER")){ \
51 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) atol(getenv("CURLOPT_SSL_VERIFYPEER")) ); \
53 if (getenv("CURLOPT_CAINFO")){ \
54 curl_easy_setopt(curl, CURLOPT_CAINFO, getenv("CURLOPT_CAINFO") ); \
56 if (getenv("CURLOPT_FOLLOWLOCATION")){ \
57 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) atol(getenv("CURLOPT_FOLLOWLOCATION")) ); \
59 if (getenv("CURLOPT_FAILONERROR")){ \
60 curl_easy_setopt(curl, CURLOPT_FAILONERROR, (long) atol(getenv("CURLOPT_FAILONERROR")) ); \
65 size_t size; //< bytes remaining (r), bytes accumulated (w)
67 size_t start_size; //< only used with ..AndCall()
68 void (*callback)(void*,int,size_t,size_t); //< only used with ..AndCall()
69 void *callback_data; //< only used with ..AndCall()
73 WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) {
74 size_t realsize = size * nmemb;
75 struct MemoryStruct *mem = (struct MemoryStruct *)data;
77 mem->data = (char *)xrealloc(mem->data, mem->size + realsize + 1);
79 memcpy(&(mem->data[mem->size]), ptr, realsize);
80 mem->size += realsize;
81 mem->data[mem->size] = 0;
87 ReadMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) {
88 struct MemoryStruct *mem = (struct MemoryStruct *)data;
89 size_t realsize = size * nmemb;
90 if (realsize > mem->size) realsize = mem->size;
91 memcpy(ptr, mem->data, realsize);
92 mem->size -= realsize;
93 mem->data += realsize;
98 WriteMemoryCallbackAndCall(void *ptr, size_t size, size_t nmemb, void *data) {
99 struct MemoryStruct *mem = (struct MemoryStruct *)data;
100 size_t ret=WriteMemoryCallback(ptr,size,nmemb,data);
101 mem->callback(mem->callback_data,0,mem->size,mem->size);
106 ReadMemoryCallbackAndCall(void *ptr, size_t size, size_t nmemb, void *data) {
107 struct MemoryStruct *mem = (struct MemoryStruct *)data;
108 size_t ret=ReadMemoryCallback(ptr,size,nmemb,data);
109 mem->callback(mem->callback_data,1,mem->start_size-mem->size,mem->start_size);
114 * cURL http post function.
115 * the returned string (if not NULL) needs to be freed by the caller
117 * @param u url to retrieve
118 * @param p post parameters
119 * @param customheader specify custom HTTP header (or NULL for none)
120 * @return returned HTTP
122 char *oauth_curl_post (const char *u, const char *p, const char *customheader) {
125 struct curl_slist *slist=NULL;
127 struct MemoryStruct chunk;
131 curl = curl_easy_init();
132 if(!curl) return NULL;
133 curl_easy_setopt(curl, CURLOPT_URL, u);
134 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, p);
135 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
136 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
138 slist = curl_slist_append(slist, customheader);
139 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
141 curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
142 #ifdef OAUTH_CURL_TIMEOUT
143 curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
144 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
146 GLOBAL_CURL_ENVIROMENT_OPTIONS;
147 res = curl_easy_perform(curl);
148 curl_slist_free_all(slist);
153 curl_easy_cleanup(curl);
158 * cURL http get function.
159 * the returned string (if not NULL) needs to be freed by the caller
161 * @param u url to retrieve
162 * @param q optional query parameters
163 * @param customheader specify custom HTTP header (or NULL for none)
164 * @return returned HTTP
166 char *oauth_curl_get (const char *u, const char *q, const char *customheader) {
169 struct curl_slist *slist=NULL;
171 struct MemoryStruct chunk;
174 t1=(char*)xmalloc(sizeof(char)*(strlen(u)+strlen(q)+2));
175 strcpy(t1,u); strcat(t1,"?"); strcat(t1,q);
181 curl = curl_easy_init();
186 curl_easy_setopt(curl, CURLOPT_URL, q?t1:u);
187 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
188 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
190 slist = curl_slist_append(slist, customheader);
191 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
193 #if 0 // TODO - support request methods..
195 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
197 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
199 curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
200 #ifdef OAUTH_CURL_TIMEOUT
201 curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
202 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
204 GLOBAL_CURL_ENVIROMENT_OPTIONS;
205 res = curl_easy_perform(curl);
206 curl_slist_free_all(slist);
208 curl_easy_cleanup(curl);
217 * cURL http post raw data from file.
218 * the returned string needs to be freed by the caller
220 * @param u url to retrieve
221 * @param fn filename of the file to post along (max 2GB)
222 * @param len length of the file in bytes. set to '0' for autodetection
223 * @param customheader specify custom HTTP header (or NULL for default)
224 * the default header adds "Content-Type: image/jpeg;"
225 * @return returned HTTP or NULL on error
227 char *oauth_curl_post_file (const char *u, const char *fn, size_t len, const char *customheader) {
230 struct curl_slist *slist=NULL;
231 struct MemoryStruct chunk;
239 slist = curl_slist_append(slist, customheader);
241 slist = curl_slist_append(slist, "Content-Type: image/jpeg;"); // good guess :)
246 fseek(f, 0L, SEEK_END);
248 fseek(f, 0L, SEEK_SET);
250 if (!len || len > filelen) {
254 curl = curl_easy_init();
259 curl_easy_setopt(curl, CURLOPT_URL, u);
260 curl_easy_setopt(curl, CURLOPT_POST, 1);
261 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
262 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
263 curl_easy_setopt(curl, CURLOPT_READDATA, f);
264 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
265 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
266 curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
267 #ifdef OAUTH_CURL_TIMEOUT
268 curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
269 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
271 GLOBAL_CURL_ENVIROMENT_OPTIONS;
272 res = curl_easy_perform(curl);
273 curl_slist_free_all(slist);
280 curl_easy_cleanup(curl);
285 * http send raw data, with callback.
286 * the returned string needs to be freed by the caller
288 * more documentation in oauth.h
290 * @param u url to retrieve
291 * @param data data to post along
292 * @param len length of the file in bytes. set to '0' for autodetection
293 * @param customheader specify custom HTTP header (or NULL for default)
294 * the default header adds "Content-Type: image/jpeg;"
295 * @param callback specify the callback function
296 * @param callback_data specify data to pass to the callback function
297 * @return returned HTTP reply or NULL on error
299 char *oauth_curl_send_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data, const char *httpMethod) {
302 struct curl_slist *slist=NULL;
303 struct MemoryStruct chunk;
304 struct MemoryStruct rdnfo;
309 chunk.callback=callback;
310 chunk.callback_data=callback_data;
311 rdnfo.data=(char *)data;
313 rdnfo.start_size=len;
314 rdnfo.callback=callback;
315 rdnfo.callback_data=callback_data;
318 slist = curl_slist_append(slist, customheader);
320 slist = curl_slist_append(slist, "Content-Type: image/jpeg;");
322 curl = curl_easy_init();
323 if(!curl) return NULL;
324 curl_easy_setopt(curl, CURLOPT_URL, u);
325 curl_easy_setopt(curl, CURLOPT_POST, 1);
326 if (httpMethod) curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, httpMethod);
327 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
328 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
329 curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&rdnfo);
331 curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallbackAndCall);
333 curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallback);
334 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
336 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallbackAndCall);
338 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
339 curl_easy_setopt(curl, CURLOPT_USERAGENT, OAUTH_USER_AGENT);
340 #ifdef OAUTH_CURL_TIMEOUT
341 curl_easy_setopt(curl, CURLOPT_TIMEOUT, OAUTH_CURL_TIMEOUT);
342 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
344 GLOBAL_CURL_ENVIROMENT_OPTIONS;
345 res = curl_easy_perform(curl);
346 curl_slist_free_all(slist);
352 curl_easy_cleanup(curl);
357 * http post raw data.
358 * the returned string needs to be freed by the caller
360 * more documentation in oauth.h
362 * @param u url to retrieve
363 * @param data data to post along
364 * @param len length of the file in bytes. set to '0' for autodetection
365 * @param customheader specify custom HTTP header (or NULL for default)
366 * @return returned HTTP reply or NULL on error
368 char *oauth_curl_post_data(const char *u, const char *data, size_t len, const char *customheader) {
369 return oauth_curl_send_data_with_callback(u, data, len, customheader, NULL, NULL, NULL);
372 char *oauth_curl_send_data (const char *u, const char *data, size_t len, const char *customheader, const char *httpMethod) {
373 return oauth_curl_send_data_with_callback(u, data, len, customheader, NULL, NULL, httpMethod);
376 char *oauth_curl_post_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data) {
377 return oauth_curl_send_data_with_callback(u, data, len, customheader, callback, callback_data, NULL);
383 #ifdef HAVE_SHELL_CURL /* HTTP requests via command-line curl */
385 // command line presets and ENV variable name
386 #define _OAUTH_ENV_HTTPCMD "OAUTH_HTTP_CMD"
387 #define _OAUTH_ENV_HTTPGET "OAUTH_HTTP_GET_CMD"
389 #ifdef OAUTH_CURL_TIMEOUT
391 #define cpxstr(s) cpstr(s)
394 #ifndef _OAUTH_DEF_HTTPCMD
395 # define _OAUTH_DEF_HTTPCMD "curl -sA '"OAUTH_USER_AGENT"' -m "cpxstr(OAUTH_CURL_TIMEOUT)" -d '%p' '%u' "
396 //alternative: "wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "
399 #ifndef _OAUTH_DEF_HTTPGET
400 # define _OAUTH_DEF_HTTPGET "curl -sA '"OAUTH_USER_AGENT"' -m "cpxstr(OAUTH_CURL_TIMEOUT)" '%u' "
401 //alternative: "wget -q -U 'liboauth-agent/0.1' '%u' "
406 #ifndef _OAUTH_DEF_HTTPCMD
407 # define _OAUTH_DEF_HTTPCMD "curl -sA '"OAUTH_USER_AGENT"' -d '%p' '%u' "
408 //alternative: "wget -q -U 'liboauth-agent/0.1' --post-data='%p' '%u' "
411 #ifndef _OAUTH_DEF_HTTPGET
412 # define _OAUTH_DEF_HTTPGET "curl -sA '"OAUTH_USER_AGENT"' '%u' "
413 //alternative: "wget -q -U 'liboauth-agent/0.1' '%u' "
421 * escape URL for use in String Quotes (aka shell single quotes).
422 * the returned string needs to be xfree()d by the calling function
424 * WARNING: this function only escapes single-quotes (')
427 * RFC2396 defines the following
428 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
429 * besides alphanum the following are allowed as unreserved:
430 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
432 * checking `echo '-_.!~*()'` it seems we
433 * just need to escape the tick (') itself from "'" to "'\''"
435 * In C shell, the "!" character may need a backslash before it.
436 * It depends on the characters next to it. If it is surrounded by spaces,
437 * you don't need to use a backslash.
438 * (here: we'd always need to escape it for c shell)
439 * @todo: escape '!' for c-shell curl/wget commandlines
441 * @param cmd URI string or parameter to be escaped
442 * @return escaped parameter
444 char *oauth_escape_shell (const char *cmd) {
445 char *esc = xstrdup(cmd);
448 while ((tmp=strchr(tmp,'\''))) {
450 esc=(char*)xrealloc(esc,(strlen(esc)+5)*sizeof(char));
451 memmove(esc+idx+4,esc+idx+1, strlen(esc+idx));
452 esc[idx+1]='\\'; esc[idx+2]='\''; esc[idx+3]='\'';
456 // TODO escape '!' if CSHELL ?!
462 * execute command via shell and return it's output.
463 * This is used to call 'curl' or 'wget'.
464 * the command is uses <em>as is</em> and needs to be propery escaped.
466 * @param cmd the commandline to execute
467 * @return stdout string that needs to be freed or NULL if there's no output
469 char *oauth_exec_shell (const char *cmd) {
471 printf("DEBUG: executing: %s\n",cmd);
473 FILE *in = popen (cmd, "r");
478 while (in && rcv > 0 && !feof(in)) {
480 data = (char*)xrealloc(data, alloc * sizeof(char));
481 rcv = fread(data + (alloc-1024), sizeof(char), 1024, in);
486 printf("DEBUG: read %i bytes\n",len);
490 if (data) printf("DEBUG: return: %s\n",data);
491 else printf("DEBUG: NULL data\n");
497 * send POST via a command line HTTP client, wait for it to finish
498 * and return the content of the reply. requires a command-line HTTP client
500 * see \ref oauth_http_post
502 * @param u url to query
503 * @param p postargs to send along with the HTTP request.
504 * @return In case of an error NULL is returned; otherwise a pointer to the
505 * replied content from HTTP server. latter needs to be freed by caller.
507 char *oauth_exec_post (const char *u, const char *p) {
510 char *cmdtpl = getenv(_OAUTH_ENV_HTTPCMD);
511 if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPCMD);
512 else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
514 // add URL and post param - error if no '%p' or '%u' present in definition
515 t1=strstr(cmdtpl, "%p");
516 t2=strstr(cmdtpl, "%u");
518 fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPCMD);
521 // TODO: check if there are exactly two '%' in cmdtpl
522 *(++t1)= 's'; *(++t2)= 's';
524 t1=oauth_escape_shell(u);
525 t2=oauth_escape_shell(p);
527 t1=oauth_escape_shell(p);
528 t2=oauth_escape_shell(u);
530 snprintf(cmd, BUFSIZ, cmdtpl, t1, t2);
532 xfree(t1); xfree(t2);
533 return oauth_exec_shell(cmd);
537 * send GET via a command line HTTP client
538 * and return the content of the reply..
539 * requires a command-line HTTP client.
541 * Note: u and q are just concatenated with a '?' in between unless q is NULL. in which case only u will be used.
543 * see \ref oauth_http_get
545 * @param u base url to get
546 * @param q query string to send along with the HTTP request.
547 * @return In case of an error NULL is returned; otherwise a pointer to the
548 * replied content from HTTP server. latter needs to be freed by caller.
550 char *oauth_exec_get (const char *u, const char *q) {
552 char *cmdtpl, *t1, *e1;
554 if (!u) return (NULL);
556 cmdtpl = getenv(_OAUTH_ENV_HTTPGET);
557 if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPGET);
558 else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
560 // add URL and post param - error if no '%p' or '%u' present in definition
561 t1=strstr(cmdtpl, "%u");
563 fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPGET);
569 e1 = oauth_escape_shell(u);
572 e2 = oauth_escape_shell(q);
573 t1=(char*)xmalloc(sizeof(char)*(strlen(e1)+strlen(e2)+2));
574 strcpy(t1,e1); strcat(t1,"?"); strcat(t1,e2);
577 snprintf(cmd, BUFSIZ, cmdtpl, q?t1:e1);
581 return oauth_exec_shell(cmd);
583 #endif // command-line curl.
585 /* wrapper functions */
588 * do a HTTP GET request, wait for it to finish
589 * and return the content of the reply.
590 * (requires libcurl or a command-line HTTP client)
592 * more documentation in oauth.h
594 * @param u base url to get
595 * @param q query string to send along with the HTTP request or NULL.
596 * @return In case of an error NULL is returned; otherwise a pointer to the
597 * replied content from HTTP server. latter needs to be freed by caller.
599 char *oauth_http_get (const char *u, const char *q) {
601 return oauth_curl_get(u,q,NULL);
602 #elif defined(HAVE_SHELL_CURL)
603 return oauth_exec_get(u,q);
610 * do a HTTP GET request, wait for it to finish
611 * and return the content of the reply.
614 * @param u base url to get
615 * @param q query string to send along with the HTTP request or NULL.
616 * @param customheader specify custom HTTP header (or NULL for none)
617 * @return In case of an error NULL is returned; otherwise a pointer to the
618 * replied content from HTTP server. latter needs to be freed by caller.
620 char *oauth_http_get2 (const char *u, const char *q, const char *customheader) {
622 return oauth_curl_get(u,q,customheader);
629 * do a HTTP POST request, wait for it to finish
630 * and return the content of the reply.
631 * (requires libcurl or a command-line HTTP client)
633 * more documentation in oauth.h
635 * @param u url to query
636 * @param p postargs to send along with the HTTP request.
637 * @return In case of an error NULL is returned; otherwise a pointer to the
638 * replied content from HTTP server. latter needs to be freed by caller.
640 char *oauth_http_post (const char *u, const char *p) {
642 return oauth_curl_post(u,p,NULL);
643 #elif defined(HAVE_SHELL_CURL)
644 return oauth_exec_post(u,p);
652 * do a HTTP POST request, wait for it to finish
653 * and return the content of the reply.
656 * more documentation in oauth.h
658 * @param u url to query
659 * @param p postargs to send along with the HTTP request.
660 * @param customheader specify custom HTTP header (or NULL for none)
661 * @return In case of an error NULL is returned; otherwise a pointer to the
662 * replied content from HTTP server. latter needs to be freed by caller.
664 char *oauth_http_post2 (const char *u, const char *p, const char *customheader) {
666 return oauth_curl_post(u,p,customheader);
673 * http post raw data from file.
674 * the returned string needs to be freed by the caller
676 * more documentation in oauth.h
678 * @param u url to retrieve
679 * @param fn filename of the file to post along
680 * @param len length of the file in bytes. set to '0' for autodetection
681 * @param customheader specify custom HTTP header (or NULL for default)
682 * @return returned HTTP reply or NULL on error
684 char *oauth_post_file (const char *u, const char *fn, const size_t len, const char *customheader){
686 return oauth_curl_post_file (u, fn, len, customheader);
687 #elif defined(HAVE_SHELL_CURL)
688 fprintf(stderr, "\nliboauth: oauth_post_file requires libcurl. libcurl is not available.\n\n");
696 * http post raw data.
697 * the returned string needs to be freed by the caller
699 * more documentation in oauth.h
701 * @param u url to retrieve
702 * @param data data to post along
703 * @param len length of the file in bytes. set to '0' for autodetection
704 * @param customheader specify custom HTTP header (or NULL for default)
705 * @return returned HTTP reply or NULL on error
707 char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader) {
709 return oauth_curl_post_data (u, data, len, customheader);
710 #elif defined(HAVE_SHELL_CURL)
711 fprintf(stderr, "\nliboauth: oauth_post_file requires libcurl. libcurl is not available.\n\n");
718 char *oauth_send_data (const char *u, const char *data, size_t len, const char *customheader, const char *httpMethod) {
720 return oauth_curl_send_data (u, data, len, customheader, httpMethod);
721 #elif defined(HAVE_SHELL_CURL)
722 fprintf(stderr, "\nliboauth: oauth_send_file requires libcurl. libcurl is not available.\n\n");
729 char *oauth_post_data_with_callback (const char *u, const char *data, size_t len, const char *customheader, void (*callback)(void*,int,size_t,size_t), void *callback_data) {
731 return oauth_curl_post_data_with_callback(u, data, len, customheader, callback, callback_data);
732 #elif defined(HAVE_SHELL_CURL)
733 fprintf(stderr, "\nliboauth: oauth_post_data_with_callback requires libcurl.\n\n");
739 /* vi:set ts=8 sts=2 sw=2: */