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