uploaded liboauth for tizen_3.0
[platform/upstream/liboauth.git] / src / oauth_http.c
1 /*
2  * OAuth http functions in POSIX-C.
3  *
4  * Copyright 2007-2011 Robin Gareus <robin@gareus.org>
5  *
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:
12  * 
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  * 
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
22  * THE SOFTWARE.
23  *
24  */
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifdef WIN32
35 #  define snprintf _snprintf
36 #endif
37
38 #include "xmalloc.h"
39 #include "oauth.h"
40
41 #define OAUTH_USER_AGENT "liboauth-agent/" VERSION
42
43 #ifdef HAVE_CURL /* HTTP requests via libcurl */
44 #include <curl/curl.h>
45
46 # define GLOBAL_CURL_ENVIROMENT_OPTIONS \
47   if (getenv("CURLOPT_PROXYAUTH")){ \
48     curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); \
49   } \
50   if (getenv("CURLOPT_SSL_VERIFYPEER")){ \
51     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) atol(getenv("CURLOPT_SSL_VERIFYPEER")) ); \
52   } \
53   if (getenv("CURLOPT_CAINFO")){ \
54     curl_easy_setopt(curl, CURLOPT_CAINFO, getenv("CURLOPT_CAINFO") ); \
55   } \
56   if (getenv("CURLOPT_FOLLOWLOCATION")){ \
57     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) atol(getenv("CURLOPT_FOLLOWLOCATION")) ); \
58   } \
59   if (getenv("CURLOPT_FAILONERROR")){ \
60     curl_easy_setopt(curl, CURLOPT_FAILONERROR, (long) atol(getenv("CURLOPT_FAILONERROR")) ); \
61   }
62
63 struct MemoryStruct {
64   char *data;
65   size_t size; //< bytes remaining (r), bytes accumulated (w)
66
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()
70 };
71
72 static size_t
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;
76
77   mem->data = (char *)xrealloc(mem->data, mem->size + realsize + 1);
78   if (mem->data) {
79     memcpy(&(mem->data[mem->size]), ptr, realsize);
80     mem->size += realsize;
81     mem->data[mem->size] = 0;
82   }
83   return realsize;
84 }
85
86 static size_t
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;
94   return realsize;
95 }
96
97 static size_t
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);
102   return ret;
103 }
104
105 static size_t
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);
110   return ret;
111 }
112
113 /**
114  * cURL http post function.
115  * the returned string (if not NULL) needs to be freed by the caller
116  *
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
121  */
122 char *oauth_curl_post (const char *u, const char *p, const char *customheader) {
123   CURL *curl;
124   CURLcode res;
125   struct curl_slist *slist=NULL;
126
127   struct MemoryStruct chunk;
128   chunk.data=NULL;
129   chunk.size = 0;
130
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);
137   if (customheader) {
138     slist = curl_slist_append(slist, customheader);
139     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); 
140   }
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);
145 #endif
146   GLOBAL_CURL_ENVIROMENT_OPTIONS;
147   res = curl_easy_perform(curl);
148   curl_slist_free_all(slist);
149   if (res) {
150     return NULL;
151   }
152
153   curl_easy_cleanup(curl);
154   return (chunk.data);
155 }
156
157 /**
158  * cURL http get function.
159  * the returned string (if not NULL) needs to be freed by the caller
160  *
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
165  */
166 char *oauth_curl_get (const char *u, const char *q, const char *customheader) {
167   CURL *curl;
168   CURLcode res;
169   struct curl_slist *slist=NULL;
170   char *t1=NULL;
171   struct MemoryStruct chunk;
172
173   if (q) {
174     t1=(char*)xmalloc(sizeof(char)*(strlen(u)+strlen(q)+2));
175     strcpy(t1,u); strcat(t1,"?"); strcat(t1,q);
176   }
177
178   chunk.data=NULL;
179   chunk.size = 0;
180
181   curl = curl_easy_init();
182   if(!curl) {
183     xfree(t1);
184     return NULL;
185   }
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);
189   if (customheader) {
190     slist = curl_slist_append(slist, customheader);
191     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); 
192   }
193 #if 0 // TODO - support request methods..
194   if (0) 
195     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
196   else if (0) 
197     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
198 #endif
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);
203 #endif
204   GLOBAL_CURL_ENVIROMENT_OPTIONS;
205   res = curl_easy_perform(curl);
206   curl_slist_free_all(slist);
207   xfree(t1);
208   curl_easy_cleanup(curl);
209
210   if (res) {
211     return NULL;
212   }
213   return (chunk.data);
214 }
215
216 /**
217  * cURL http post raw data from file.
218  * the returned string needs to be freed by the caller
219  *
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
226  */
227 char *oauth_curl_post_file (const char *u, const char *fn, size_t len, const char *customheader) {
228   CURL *curl;
229   CURLcode res;
230   struct curl_slist *slist=NULL;
231   struct MemoryStruct chunk;
232   FILE *f;
233   long filelen;
234
235   chunk.data=NULL;
236   chunk.size=0;
237
238   if (customheader)
239     slist = curl_slist_append(slist, customheader);
240   else
241     slist = curl_slist_append(slist, "Content-Type: image/jpeg;"); // good guess :)
242
243   f = fopen(fn,"r");
244   if (!f) return NULL;
245
246   fseek(f, 0L, SEEK_END);
247   filelen = ftell(f);
248   fseek(f, 0L, SEEK_SET);
249
250   if (!len || len > filelen) {
251     len = filelen;
252   }
253
254   curl = curl_easy_init();
255   if(!curl) {
256     fclose(f);
257     return NULL;
258   }
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);
270 #endif
271   GLOBAL_CURL_ENVIROMENT_OPTIONS;
272   res = curl_easy_perform(curl);
273   curl_slist_free_all(slist);
274   fclose(f);
275   if (res) {
276     // error
277     return NULL;
278   }
279
280   curl_easy_cleanup(curl);
281   return (chunk.data);
282 }
283
284 /**
285  * http send raw data, with callback.
286  * the returned string needs to be freed by the caller
287  *
288  * more documentation in oauth.h
289  *
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
298  */
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) {
300   CURL *curl;
301   CURLcode res;
302   struct curl_slist *slist=NULL;
303   struct MemoryStruct chunk;
304   struct MemoryStruct rdnfo;
305   
306   chunk.data=NULL;
307   chunk.size=0;
308   chunk.start_size=0;
309   chunk.callback=callback;
310   chunk.callback_data=callback_data;
311   rdnfo.data=(char *)data;
312   rdnfo.size=len;
313   rdnfo.start_size=len;
314   rdnfo.callback=callback;
315   rdnfo.callback_data=callback_data;
316
317   if (customheader)
318     slist = curl_slist_append(slist, customheader);
319   else
320     slist = curl_slist_append(slist, "Content-Type: image/jpeg;");
321   
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);
330   if (callback)
331     curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallbackAndCall);
332   else
333     curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadMemoryCallback);
334   curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
335   if (callback)
336   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallbackAndCall);
337   else 
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);
343 #endif
344   GLOBAL_CURL_ENVIROMENT_OPTIONS;
345   res = curl_easy_perform(curl);
346   curl_slist_free_all(slist);
347   if (res) {
348     // error
349     return NULL;
350   }
351   
352   curl_easy_cleanup(curl);
353   return (chunk.data);
354 }
355
356 /**
357  * http post raw data.
358  * the returned string needs to be freed by the caller
359  *
360  * more documentation in oauth.h
361  *
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
367  */
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);
370 }
371
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);
374 }
375
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);
378 }
379
380 #endif // libcURL.
381
382
383 #ifdef HAVE_SHELL_CURL /* HTTP requests via command-line curl  */
384
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"
388
389 #ifdef OAUTH_CURL_TIMEOUT  
390
391 #define cpxstr(s) cpstr(s)
392 #define cpstr(s) #s
393
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' "
397 #endif
398
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' "
402 #endif
403
404 #else // no timeout
405
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' "
409 #endif
410
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' "
414 #endif
415
416 #endif
417
418 #include <stdio.h>
419
420 /**
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
423  *
424  * WARNING: this function only escapes single-quotes (')
425  *
426  *
427  * RFC2396 defines the following 
428  *  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
429  *  besides alphanum the following are allowed as unreserved:
430  *  mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
431  *
432  *  checking  `echo '-_.!~*()'` it seems we
433  *  just need to escape the tick (') itself from "'" to "'\''"
434  *
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
440  *
441  * @param cmd URI string or parameter to be escaped
442  * @return escaped parameter
443  */
444 char *oauth_escape_shell (const char *cmd) {
445   char *esc = xstrdup(cmd);
446   char *tmp = esc;
447   int idx;
448   while ((tmp=strchr(tmp,'\''))) { 
449     idx = tmp-esc;
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]='\'';
453     tmp=esc+(idx+4);
454   }
455
456 // TODO escape '!' if CSHELL ?!
457
458   return esc;
459 }
460
461 /**
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.
465  *
466  * @param cmd the commandline to execute
467  * @return stdout string that needs to be freed or NULL if there's no output
468  */
469 char *oauth_exec_shell (const char *cmd) {
470 #ifdef DEBUG_OAUTH
471   printf("DEBUG: executing: %s\n",cmd);
472 #endif
473   FILE *in = popen (cmd, "r");
474   size_t len = 0;
475   size_t alloc = 0;
476   char *data = NULL;
477   int rcv = 1;
478   while (in && rcv > 0 && !feof(in)) {
479     alloc +=1024;
480     data = (char*)xrealloc(data, alloc * sizeof(char));
481     rcv = fread(data + (alloc-1024), sizeof(char), 1024, in);
482     len += rcv;
483   }
484   pclose(in);
485 #ifdef DEBUG_OAUTH
486   printf("DEBUG: read %i bytes\n",len);
487 #endif
488   data[len]=0;
489 #ifdef DEBUG_OAUTH
490   if (data) printf("DEBUG: return: %s\n",data);
491   else printf("DEBUG: NULL data\n");
492 #endif
493   return (data);
494 }
495
496 /**
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
499  *
500  * see \ref  oauth_http_post
501  *
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.
506  */
507 char *oauth_exec_post (const char *u, const char *p) {
508   char cmd[BUFSIZ];
509   char *t1,*t2;
510   char *cmdtpl = getenv(_OAUTH_ENV_HTTPCMD);
511   if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPCMD);
512   else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
513
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");
517   if (!t1 || !t2) {
518     fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPCMD);
519     return(NULL);
520   }
521   // TODO: check if there are exactly two '%' in cmdtpl
522   *(++t1)= 's'; *(++t2)= 's';
523   if (t1>t2) {
524     t1=oauth_escape_shell(u);
525     t2=oauth_escape_shell(p);
526   } else {
527     t1=oauth_escape_shell(p);
528     t2=oauth_escape_shell(u);
529   }
530   snprintf(cmd, BUFSIZ, cmdtpl, t1, t2);
531   xfree(cmdtpl);
532   xfree(t1); xfree(t2);
533   return oauth_exec_shell(cmd);
534 }
535
536 /**
537  * send GET via a command line HTTP client
538  * and return the content of the reply..
539  * requires a command-line HTTP client.
540  * 
541  * Note: u and q are just concatenated with a '?' in between unless q is NULL. in which case only u will be used.
542  *
543  * see \ref  oauth_http_get
544  *
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.
549  */
550 char *oauth_exec_get (const char *u, const char *q) {
551   char cmd[BUFSIZ];
552   char *cmdtpl, *t1, *e1;
553
554   if (!u) return (NULL);
555
556   cmdtpl = getenv(_OAUTH_ENV_HTTPGET);
557   if (!cmdtpl) cmdtpl = xstrdup (_OAUTH_DEF_HTTPGET);
558   else cmdtpl = xstrdup (cmdtpl); // clone getenv() string.
559
560   // add URL and post param - error if no '%p' or '%u' present in definition
561   t1=strstr(cmdtpl, "%u");
562   if (!t1) {
563     fprintf(stderr, "\nliboauth: invalid HTTP command. set the '%s' environment variable.\n\n",_OAUTH_ENV_HTTPGET);
564     xfree(cmdtpl);
565     return(NULL);
566   }
567   *(++t1)= 's';
568
569   e1 = oauth_escape_shell(u);
570   if (q) {
571     char *e2;
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);
575     xfree(e2);
576   }
577   snprintf(cmd, BUFSIZ, cmdtpl, q?t1:e1);
578   xfree(cmdtpl);
579   xfree(e1);
580   if (q) xfree(t1);
581   return oauth_exec_shell(cmd);
582 }
583 #endif // command-line curl.
584
585 /* wrapper functions */
586
587 /**
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)
591  * 
592  * more documentation in oauth.h
593  *
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.
598  */
599 char *oauth_http_get (const char *u, const char *q) {
600 #ifdef HAVE_CURL
601   return oauth_curl_get(u,q,NULL);
602 #elif defined(HAVE_SHELL_CURL)
603   return oauth_exec_get(u,q);
604 #else 
605   return NULL;
606 #endif
607 }
608
609 /**
610  * do a HTTP GET request, wait for it to finish 
611  * and return the content of the reply.
612  * (requires libcurl)
613  * 
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.
619  */
620 char *oauth_http_get2 (const char *u, const char *q, const char *customheader) {
621 #ifdef HAVE_CURL
622   return oauth_curl_get(u,q,customheader);
623 #else 
624   return NULL;
625 #endif
626 }
627
628 /**
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)
632  *
633  * more documentation in oauth.h
634  *
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.
639  */
640 char *oauth_http_post (const char *u, const char *p) {
641 #ifdef HAVE_CURL
642   return oauth_curl_post(u,p,NULL);
643 #elif defined(HAVE_SHELL_CURL)
644   return oauth_exec_post(u,p);
645 #else 
646   return NULL;
647 #endif
648 }
649
650
651 /**
652  * do a HTTP POST request, wait for it to finish 
653  * and return the content of the reply.
654  * (requires libcurl)
655  *
656  * more documentation in oauth.h
657  *
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.
663  */
664 char *oauth_http_post2 (const char *u, const char *p, const char *customheader) {
665 #ifdef HAVE_CURL
666   return oauth_curl_post(u,p,customheader);
667 #else
668   return NULL;
669 #endif
670 }
671
672 /**
673  * http post raw data from file.
674  * the returned string needs to be freed by the caller
675  *
676  * more documentation in oauth.h
677  *
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
683  */
684 char *oauth_post_file (const char *u, const char *fn, const size_t len, const char *customheader){
685 #ifdef HAVE_CURL
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");
689   return NULL;
690 #else 
691   return NULL;
692 #endif
693 }
694
695 /**
696  * http post raw data.
697  * the returned string needs to be freed by the caller
698  *
699  * more documentation in oauth.h
700  *
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
706  */
707 char *oauth_post_data (const char *u, const char *data, size_t len, const char *customheader) {
708 #ifdef HAVE_CURL
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");
712   return NULL;
713 #else
714   return (NULL);
715 #endif
716 }
717
718 char *oauth_send_data (const char *u, const char *data, size_t len, const char *customheader, const char *httpMethod) {
719 #ifdef HAVE_CURL
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");
723   return NULL;
724 #else
725   return (NULL);
726 #endif
727 }
728
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) {
730 #ifdef HAVE_CURL
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");
734   return NULL;
735 #else
736   return (NULL);
737 #endif
738 }
739 /* vi:set ts=8 sts=2 sw=2: */