Mon Mar 19 11:30:27 2012

Asterisk developer's documentation


func_curl.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C)  2004 - 2006, Tilghman Lesher
00005  *
00006  * Tilghman Lesher <curl-20050919@the-tilghman.com>
00007  * and Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option)
00008  *
00009  * app_curl.c is distributed with no restrictions on usage or
00010  * redistribution.
00011  *
00012  * See http://www.asterisk.org for more information about
00013  * the Asterisk project. Please do not directly contact
00014  * any of the maintainers of this project for assistance;
00015  * the project provides a web site, mailing lists and IRC
00016  * channels for your use.
00017  *
00018  */
00019 
00020 /*! \file
00021  * 
00022  * \brief Curl - Load a URL
00023  *
00024  * \author Tilghman Lesher <curl-20050919@the-tilghman.com>
00025  *
00026  * \note Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option) 
00027  *
00028  * \extref Depends on the CURL library  - http://curl.haxx.se/
00029  * 
00030  * \ingroup functions
00031  */
00032  
00033 /*** MODULEINFO
00034    <depend>curl</depend>
00035    <support_level>core</support_level>
00036  ***/
00037 
00038 #include "asterisk.h"
00039 
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 337325 $")
00041 
00042 #include <curl/curl.h>
00043 
00044 #include "asterisk/lock.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/cli.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/threadstorage.h"
00053 
00054 #define CURLVERSION_ATLEAST(a,b,c) \
00055    ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))
00056 
00057 #define CURLOPT_SPECIAL_HASHCOMPAT -500
00058 
00059 static void curlds_free(void *data);
00060 
00061 static struct ast_datastore_info curl_info = {
00062    .type = "CURL",
00063    .destroy = curlds_free,
00064 };
00065 
00066 struct curl_settings {
00067    AST_LIST_ENTRY(curl_settings) list;
00068    CURLoption key;
00069    void *value;
00070 };
00071 
00072 AST_LIST_HEAD_STATIC(global_curl_info, curl_settings);
00073 
00074 static void curlds_free(void *data)
00075 {
00076    AST_LIST_HEAD(global_curl_info, curl_settings) *list = data;
00077    struct curl_settings *setting;
00078    if (!list) {
00079       return;
00080    }
00081    while ((setting = AST_LIST_REMOVE_HEAD(list, list))) {
00082       free(setting);
00083    }
00084    AST_LIST_HEAD_DESTROY(list);
00085 }
00086 
00087 enum optiontype {
00088    OT_BOOLEAN,
00089    OT_INTEGER,
00090    OT_INTEGER_MS,
00091    OT_STRING,
00092    OT_ENUM,
00093 };
00094 
00095 static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot)
00096 {
00097    if (!strcasecmp(name, "header")) {
00098       *key = CURLOPT_HEADER;
00099       *ot = OT_BOOLEAN;
00100    } else if (!strcasecmp(name, "proxy")) {
00101       *key = CURLOPT_PROXY;
00102       *ot = OT_STRING;
00103    } else if (!strcasecmp(name, "proxyport")) {
00104       *key = CURLOPT_PROXYPORT;
00105       *ot = OT_INTEGER;
00106    } else if (!strcasecmp(name, "proxytype")) {
00107       *key = CURLOPT_PROXYTYPE;
00108       *ot = OT_ENUM;
00109    } else if (!strcasecmp(name, "dnstimeout")) {
00110       *key = CURLOPT_DNS_CACHE_TIMEOUT;
00111       *ot = OT_INTEGER;
00112    } else if (!strcasecmp(name, "userpwd")) {
00113       *key = CURLOPT_USERPWD;
00114       *ot = OT_STRING;
00115    } else if (!strcasecmp(name, "proxyuserpwd")) {
00116       *key = CURLOPT_PROXYUSERPWD;
00117       *ot = OT_STRING;
00118    } else if (!strcasecmp(name, "maxredirs")) {
00119       *key = CURLOPT_MAXREDIRS;
00120       *ot = OT_INTEGER;
00121    } else if (!strcasecmp(name, "referer")) {
00122       *key = CURLOPT_REFERER;
00123       *ot = OT_STRING;
00124    } else if (!strcasecmp(name, "useragent")) {
00125       *key = CURLOPT_USERAGENT;
00126       *ot = OT_STRING;
00127    } else if (!strcasecmp(name, "cookie")) {
00128       *key = CURLOPT_COOKIE;
00129       *ot = OT_STRING;
00130    } else if (!strcasecmp(name, "ftptimeout")) {
00131       *key = CURLOPT_FTP_RESPONSE_TIMEOUT;
00132       *ot = OT_INTEGER;
00133    } else if (!strcasecmp(name, "httptimeout")) {
00134 #if CURLVERSION_ATLEAST(7,16,2)
00135       *key = CURLOPT_TIMEOUT_MS;
00136       *ot = OT_INTEGER_MS;
00137 #else
00138       *key = CURLOPT_TIMEOUT;
00139       *ot = OT_INTEGER;
00140 #endif
00141    } else if (!strcasecmp(name, "conntimeout")) {
00142 #if CURLVERSION_ATLEAST(7,16,2)
00143       *key = CURLOPT_CONNECTTIMEOUT_MS;
00144       *ot = OT_INTEGER_MS;
00145 #else
00146       *key = CURLOPT_CONNECTTIMEOUT;
00147       *ot = OT_INTEGER;
00148 #endif
00149    } else if (!strcasecmp(name, "ftptext")) {
00150       *key = CURLOPT_TRANSFERTEXT;
00151       *ot = OT_BOOLEAN;
00152    } else if (!strcasecmp(name, "ssl_verifypeer")) {
00153       *key = CURLOPT_SSL_VERIFYPEER;
00154       *ot = OT_BOOLEAN;
00155    } else if (!strcasecmp(name, "hashcompat")) {
00156       *key = CURLOPT_SPECIAL_HASHCOMPAT;
00157       *ot = OT_BOOLEAN;
00158    } else {
00159       return -1;
00160    }
00161    return 0;
00162 }
00163 
00164 static int acf_curlopt_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
00165 {
00166    struct ast_datastore *store;
00167    struct global_curl_info *list;
00168    struct curl_settings *cur, *new = NULL;
00169    CURLoption key;
00170    enum optiontype ot;
00171 
00172    if (chan) {
00173       if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
00174          /* Create a new datastore */
00175          if (!(store = ast_datastore_alloc(&curl_info, NULL))) {
00176             ast_log(LOG_ERROR, "Unable to allocate new datastore.  Cannot set any CURL options\n");
00177             return -1;
00178          }
00179 
00180          if (!(list = ast_calloc(1, sizeof(*list)))) {
00181             ast_log(LOG_ERROR, "Unable to allocate list head.  Cannot set any CURL options\n");
00182             ast_datastore_free(store);
00183          }
00184 
00185          store->data = list;
00186          AST_LIST_HEAD_INIT(list);
00187          ast_channel_datastore_add(chan, store);
00188       } else {
00189          list = store->data;
00190       }
00191    } else {
00192       /* Populate the global structure */
00193       list = &global_curl_info;
00194    }
00195 
00196    if (!parse_curlopt_key(name, &key, &ot)) {
00197       if (ot == OT_BOOLEAN) {
00198          if ((new = ast_calloc(1, sizeof(*new)))) {
00199             new->value = (void *)((long) ast_true(value));
00200          }
00201       } else if (ot == OT_INTEGER) {
00202          long tmp = atol(value);
00203          if ((new = ast_calloc(1, sizeof(*new)))) {
00204             new->value = (void *)tmp;
00205          }
00206       } else if (ot == OT_INTEGER_MS) {
00207          long tmp = atof(value) * 1000.0;
00208          if ((new = ast_calloc(1, sizeof(*new)))) {
00209             new->value = (void *)tmp;
00210          }
00211       } else if (ot == OT_STRING) {
00212          if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) {
00213             new->value = (char *)new + sizeof(*new);
00214             strcpy(new->value, value);
00215          }
00216       } else if (ot == OT_ENUM) {
00217          if (key == CURLOPT_PROXYTYPE) {
00218             long ptype =
00219 #if CURLVERSION_ATLEAST(7,10,0)
00220                CURLPROXY_HTTP;
00221 #else
00222                CURLPROXY_SOCKS5;
00223 #endif
00224             if (0) {
00225 #if CURLVERSION_ATLEAST(7,15,2)
00226             } else if (!strcasecmp(value, "socks4")) {
00227                ptype = CURLPROXY_SOCKS4;
00228 #endif
00229 #if CURLVERSION_ATLEAST(7,18,0)
00230             } else if (!strcasecmp(value, "socks4a")) {
00231                ptype = CURLPROXY_SOCKS4A;
00232 #endif
00233 #if CURLVERSION_ATLEAST(7,18,0)
00234             } else if (!strcasecmp(value, "socks5")) {
00235                ptype = CURLPROXY_SOCKS5;
00236 #endif
00237 #if CURLVERSION_ATLEAST(7,18,0)
00238             } else if (!strncasecmp(value, "socks5", 6)) {
00239                ptype = CURLPROXY_SOCKS5_HOSTNAME;
00240 #endif
00241             }
00242 
00243             if ((new = ast_calloc(1, sizeof(*new)))) {
00244                new->value = (void *)ptype;
00245             }
00246          } else {
00247             /* Highly unlikely */
00248             goto yuck;
00249          }
00250       }
00251 
00252       /* Memory allocation error */
00253       if (!new) {
00254          return -1;
00255       }
00256 
00257       new->key = key;
00258    } else {
00259 yuck:
00260       ast_log(LOG_ERROR, "Unrecognized option: %s\n", name);
00261       return -1;
00262    }
00263 
00264    /* Remove any existing entry */
00265    AST_LIST_LOCK(list);
00266    AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) {
00267       if (cur->key == new->key) {
00268          AST_LIST_REMOVE_CURRENT(list);
00269          free(cur);
00270          break;
00271       }
00272    }
00273    AST_LIST_TRAVERSE_SAFE_END
00274 
00275    /* Insert new entry */
00276    ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value);
00277    AST_LIST_INSERT_TAIL(list, new, list);
00278    AST_LIST_UNLOCK(list);
00279 
00280    return 0;
00281 }
00282 
00283 static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
00284 {
00285    struct ast_datastore *store;
00286    struct global_curl_info *list[2] = { &global_curl_info, NULL };
00287    struct curl_settings *cur = NULL;
00288    CURLoption key;
00289    enum optiontype ot;
00290    int i;
00291 
00292    if (parse_curlopt_key(data, &key, &ot)) {
00293       ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data);
00294       return -1;
00295    }
00296 
00297    if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
00298       list[0] = store->data;
00299       list[1] = &global_curl_info;
00300    }
00301 
00302    for (i = 0; i < 2; i++) {
00303       if (!list[i]) {
00304          break;
00305       }
00306       AST_LIST_LOCK(list[i]);
00307       AST_LIST_TRAVERSE(list[i], cur, list) {
00308          if (cur->key == key) {
00309             if (ot == OT_BOOLEAN || ot == OT_INTEGER) {
00310                if (buf) {
00311                   snprintf(buf, len, "%ld", (long) cur->value);
00312                } else {
00313                   ast_str_set(bufstr, len, "%ld", (long) cur->value);
00314                }
00315             } else if (ot == OT_INTEGER_MS) {
00316                if ((long) cur->value % 1000 == 0) {
00317                   if (buf) {
00318                      snprintf(buf, len, "%ld", (long)cur->value / 1000);
00319                   } else {
00320                      ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000);
00321                   }
00322                } else {
00323                   if (buf) {
00324                      snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0);
00325                   } else {
00326                      ast_str_set(bufstr, len, "%.3f", (double) ((long) cur->value) / 1000.0);
00327                   }
00328                }
00329             } else if (ot == OT_STRING) {
00330                ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value);
00331                if (buf) {
00332                   ast_copy_string(buf, cur->value, len);
00333                } else {
00334                   ast_str_set(bufstr, 0, "%s", (char *) cur->value);
00335                }
00336             } else if (key == CURLOPT_PROXYTYPE) {
00337                if (0) {
00338 #if CURLVERSION_ATLEAST(7,15,2)
00339                } else if ((long)cur->value == CURLPROXY_SOCKS4) {
00340                   if (buf) {
00341                      ast_copy_string(buf, "socks4", len);
00342                   } else {
00343                      ast_str_set(bufstr, 0, "socks4");
00344                   }
00345 #endif
00346 #if CURLVERSION_ATLEAST(7,18,0)
00347                } else if ((long)cur->value == CURLPROXY_SOCKS4A) {
00348                   if (buf) {
00349                      ast_copy_string(buf, "socks4a", len);
00350                   } else {
00351                      ast_str_set(bufstr, 0, "socks4a");
00352                   }
00353 #endif
00354                } else if ((long)cur->value == CURLPROXY_SOCKS5) {
00355                   if (buf) {
00356                      ast_copy_string(buf, "socks5", len);
00357                   } else {
00358                      ast_str_set(bufstr, 0, "socks5");
00359                   }
00360 #if CURLVERSION_ATLEAST(7,18,0)
00361                } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
00362                   if (buf) {
00363                      ast_copy_string(buf, "socks5hostname", len);
00364                   } else {
00365                      ast_str_set(bufstr, 0, "socks5hostname");
00366                   }
00367 #endif
00368 #if CURLVERSION_ATLEAST(7,10,0)
00369                } else if ((long)cur->value == CURLPROXY_HTTP) {
00370                   if (buf) {
00371                      ast_copy_string(buf, "http", len);
00372                   } else {
00373                      ast_str_set(bufstr, 0, "http");
00374                   }
00375 #endif
00376                } else {
00377                   if (buf) {
00378                      ast_copy_string(buf, "unknown", len);
00379                   } else {
00380                      ast_str_set(bufstr, 0, "unknown");
00381                   }
00382                }
00383             }
00384             break;
00385          }
00386       }
00387       AST_LIST_UNLOCK(list[i]);
00388       if (cur) {
00389          break;
00390       }
00391    }
00392 
00393    return cur ? 0 : -1;
00394 }
00395 
00396 static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00397 {
00398    return acf_curlopt_helper(chan, cmd, data, buf, NULL, len);
00399 }
00400 
00401 static int acf_curlopt_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00402 {
00403    return acf_curlopt_helper(chan, cmd, data, NULL, buf, len);
00404 }
00405 
00406 static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
00407 {
00408    register int realsize = size * nmemb;
00409    struct ast_str **pstr = (struct ast_str **)data;
00410 
00411    ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, ast_str_size(*pstr), ast_str_strlen(*pstr));
00412 
00413    ast_str_append_substr(pstr, 0, ptr, realsize);
00414 
00415    ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr));
00416 
00417    return realsize;
00418 }
00419 
00420 static const char * const global_useragent = "asterisk-libcurl-agent/1.0";
00421 
00422 static int curl_instance_init(void *data)
00423 {
00424    CURL **curl = data;
00425 
00426    if (!(*curl = curl_easy_init()))
00427       return -1;
00428 
00429    curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
00430    curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
00431    curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
00432    curl_easy_setopt(*curl, CURLOPT_USERAGENT, global_useragent);
00433 
00434    return 0;
00435 }
00436 
00437 static void curl_instance_cleanup(void *data)
00438 {
00439    CURL **curl = data;
00440 
00441    curl_easy_cleanup(*curl);
00442 
00443    ast_free(data);
00444 }
00445 
00446 AST_THREADSTORAGE_CUSTOM(curl_instance, curl_instance_init, curl_instance_cleanup);
00447 AST_THREADSTORAGE(thread_escapebuf);
00448 
00449 static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info, char *buf, struct ast_str **input_str, ssize_t len)
00450 {
00451    struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
00452    struct ast_str *str = ast_str_create(16);
00453    int ret = -1;
00454    AST_DECLARE_APP_ARGS(args,
00455       AST_APP_ARG(url);
00456       AST_APP_ARG(postdata);
00457    );
00458    CURL **curl;
00459    struct curl_settings *cur;
00460    struct ast_datastore *store = NULL;
00461    int hashcompat = 0;
00462    AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL;
00463 
00464    if (buf) {
00465       *buf = '\0';
00466    }
00467 
00468    if (!str) {
00469       return -1;
00470    }
00471 
00472    if (!escapebuf) {
00473       ast_free(str);
00474       return -1;
00475    }
00476 
00477    if (ast_strlen_zero(info)) {
00478       ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
00479       ast_free(str);
00480       return -1;
00481    }
00482 
00483    AST_STANDARD_APP_ARGS(args, info);
00484 
00485    if (chan) {
00486       ast_autoservice_start(chan);
00487    }
00488 
00489    if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
00490       ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
00491       return -1;
00492    }
00493 
00494    AST_LIST_LOCK(&global_curl_info);
00495    AST_LIST_TRAVERSE(&global_curl_info, cur, list) {
00496       if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
00497          hashcompat = (cur->value != NULL) ? 1 : 0;
00498       } else {
00499          curl_easy_setopt(*curl, cur->key, cur->value);
00500       }
00501    }
00502 
00503    if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
00504       list = store->data;
00505       AST_LIST_LOCK(list);
00506       AST_LIST_TRAVERSE(list, cur, list) {
00507          if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
00508             hashcompat = (cur->value != NULL) ? 1 : 0;
00509          } else {
00510             curl_easy_setopt(*curl, cur->key, cur->value);
00511          }
00512       }
00513    }
00514 
00515    curl_easy_setopt(*curl, CURLOPT_URL, args.url);
00516    curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str);
00517 
00518    if (args.postdata) {
00519       curl_easy_setopt(*curl, CURLOPT_POST, 1);
00520       curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata);
00521    }
00522 
00523    curl_easy_perform(*curl);
00524 
00525    if (store) {
00526       AST_LIST_UNLOCK(list);
00527    }
00528    AST_LIST_UNLOCK(&global_curl_info);
00529 
00530    if (args.postdata) {
00531       curl_easy_setopt(*curl, CURLOPT_POST, 0);
00532    }
00533 
00534    if (ast_str_strlen(str)) {
00535       ast_str_trim_blanks(str);
00536 
00537       ast_debug(3, "str='%s'\n", ast_str_buffer(str));
00538       if (hashcompat) {
00539          char *remainder = ast_str_buffer(str);
00540          char *piece;
00541          struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2);
00542          struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2);
00543          int rowcount = 0;
00544          while (fields && values && (piece = strsep(&remainder, "&"))) {
00545             char *name = strsep(&piece, "=");
00546             if (piece) {
00547                ast_uri_decode(piece);
00548             }
00549             ast_uri_decode(name);
00550             ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, name, INT_MAX));
00551             ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, S_OR(piece, ""), INT_MAX));
00552             rowcount++;
00553          }
00554          pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00555          if (buf) {
00556             ast_copy_string(buf, ast_str_buffer(values), len);
00557          } else {
00558             ast_str_set(input_str, len, "%s", ast_str_buffer(values));
00559          }
00560          ast_free(fields);
00561          ast_free(values);
00562       } else {
00563          if (buf) {
00564             ast_copy_string(buf, ast_str_buffer(str), len);
00565          } else {
00566             ast_str_set(input_str, len, "%s", ast_str_buffer(str));
00567          }
00568       }
00569       ret = 0;
00570    }
00571    ast_free(str);
00572 
00573    if (chan)
00574       ast_autoservice_stop(chan);
00575 
00576    return ret;
00577 }
00578 
00579 static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len)
00580 {
00581    return acf_curl_helper(chan, cmd, info, buf, NULL, len);
00582 }
00583 
00584 static int acf_curl2_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
00585 {
00586    return acf_curl_helper(chan, cmd, info, NULL, buf, len);
00587 }
00588 
00589 static struct ast_custom_function acf_curl = {
00590    .name = "CURL",
00591    .synopsis = "Retrieves the contents of a URL",
00592    .syntax = "CURL(url[,post-data])",
00593    .desc =
00594    "  url       - URL to retrieve\n"
00595    "  post-data - Optional data to send as a POST (GET is default action)\n",
00596    .read = acf_curl_exec,
00597    .read2 = acf_curl2_exec,
00598 };
00599 
00600 static struct ast_custom_function acf_curlopt = {
00601    .name = "CURLOPT",
00602    .synopsis = "Set options for use with the CURL() function",
00603    .syntax = "CURLOPT(<option>)",
00604    .desc =
00605 "  cookie         - Send cookie with request [none]\n"
00606 "  conntimeout    - Number of seconds to wait for connection\n"
00607 "  dnstimeout     - Number of seconds to wait for DNS response\n"
00608 "  ftptext        - For FTP, force a text transfer (boolean)\n"
00609 "  ftptimeout     - For FTP, the server response timeout\n"
00610 "  header         - Retrieve header information (boolean)\n"
00611 "  httptimeout    - Number of seconds to wait for HTTP response\n"
00612 "  maxredirs      - Maximum number of redirects to follow\n"
00613 "  proxy          - Hostname or IP to use as a proxy\n"
00614 "  proxytype      - http, socks4, or socks5\n"
00615 "  proxyport      - port number of the proxy\n"
00616 "  proxyuserpwd   - A <user>:<pass> to use for authentication\n"
00617 "  referer        - Referer URL to use for the request\n"
00618 "  useragent      - UserAgent string to use\n"
00619 "  userpwd        - A <user>:<pass> to use for authentication\n"
00620 "  ssl_verifypeer - Whether to verify the peer certificate (boolean)\n"
00621 "  hashcompat     - Result data will be compatible for use with HASH()\n"
00622 "",
00623    .read = acf_curlopt_read,
00624    .read2 = acf_curlopt_read2,
00625    .write = acf_curlopt_write,
00626 };
00627 
00628 static int unload_module(void)
00629 {
00630    int res;
00631 
00632    res = ast_custom_function_unregister(&acf_curl);
00633    res |= ast_custom_function_unregister(&acf_curlopt);
00634 
00635    return res;
00636 }
00637 
00638 static int load_module(void)
00639 {
00640    int res;
00641 
00642    if (!ast_module_check("res_curl.so")) {
00643       if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00644          ast_log(LOG_ERROR, "Cannot load res_curl, so func_curl cannot be loaded\n");
00645          return AST_MODULE_LOAD_DECLINE;
00646       }
00647    }
00648 
00649    res = ast_custom_function_register(&acf_curl);
00650    res |= ast_custom_function_register(&acf_curlopt);
00651 
00652    return res;
00653 }
00654 
00655 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Load external URL",
00656       .load = load_module,
00657       .unload = unload_module,
00658       .load_pri = AST_MODPRI_REALTIME_DEPEND2,
00659    );
00660 

Generated on Mon Mar 19 11:30:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7