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