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: 383461 $")
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 const 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 char curl_errbuf[CURL_ERROR_SIZE + 1];
00585
00586 if (buf) {
00587 *buf = '\0';
00588 }
00589
00590 if (!str) {
00591 return -1;
00592 }
00593
00594 if (!escapebuf) {
00595 ast_free(str);
00596 return -1;
00597 }
00598
00599 if (ast_strlen_zero(info)) {
00600 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
00601 ast_free(str);
00602 return -1;
00603 }
00604
00605 AST_STANDARD_APP_ARGS(args, info);
00606
00607 if (chan) {
00608 ast_autoservice_start(chan);
00609 }
00610
00611 if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
00612 ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
00613 ast_free(str);
00614 return -1;
00615 }
00616
00617 AST_LIST_LOCK(&global_curl_info);
00618 AST_LIST_TRAVERSE(&global_curl_info, cur, list) {
00619 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
00620 hashcompat = (long) cur->value;
00621 } else {
00622 curl_easy_setopt(*curl, cur->key, cur->value);
00623 }
00624 }
00625
00626 if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
00627 list = store->data;
00628 AST_LIST_LOCK(list);
00629 AST_LIST_TRAVERSE(list, cur, list) {
00630 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
00631 hashcompat = (long) cur->value;
00632 } else {
00633 curl_easy_setopt(*curl, cur->key, cur->value);
00634 }
00635 }
00636 }
00637
00638 curl_easy_setopt(*curl, CURLOPT_URL, args.url);
00639 curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str);
00640
00641 if (args.postdata) {
00642 curl_easy_setopt(*curl, CURLOPT_POST, 1);
00643 curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata);
00644 }
00645
00646
00647 curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0';
00648 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf);
00649
00650 if (curl_easy_perform(*curl) != 0) {
00651 ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args.url);
00652 }
00653
00654
00655
00656
00657
00658 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
00659
00660 if (store) {
00661 AST_LIST_UNLOCK(list);
00662 }
00663 AST_LIST_UNLOCK(&global_curl_info);
00664
00665 if (args.postdata) {
00666 curl_easy_setopt(*curl, CURLOPT_POST, 0);
00667 }
00668
00669 if (ast_str_strlen(str)) {
00670 ast_str_trim_blanks(str);
00671
00672 ast_debug(3, "str='%s'\n", ast_str_buffer(str));
00673 if (hashcompat) {
00674 char *remainder = ast_str_buffer(str);
00675 char *piece;
00676 struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2);
00677 struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2);
00678 int rowcount = 0;
00679 while (fields && values && (piece = strsep(&remainder, "&"))) {
00680 char *name = strsep(&piece, "=");
00681 struct ast_flags mode = (hashcompat == HASHCOMPAT_LEGACY ? ast_uri_http_legacy : ast_uri_http);
00682 if (piece) {
00683 ast_uri_decode(piece, mode);
00684 }
00685 ast_uri_decode(name, mode);
00686 ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, name, INT_MAX));
00687 ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, S_OR(piece, ""), INT_MAX));
00688 rowcount++;
00689 }
00690 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
00691 if (buf) {
00692 ast_copy_string(buf, ast_str_buffer(values), len);
00693 } else {
00694 ast_str_set(input_str, len, "%s", ast_str_buffer(values));
00695 }
00696 ast_free(fields);
00697 ast_free(values);
00698 } else {
00699 if (buf) {
00700 ast_copy_string(buf, ast_str_buffer(str), len);
00701 } else {
00702 ast_str_set(input_str, len, "%s", ast_str_buffer(str));
00703 }
00704 }
00705 ret = 0;
00706 }
00707 ast_free(str);
00708
00709 if (chan)
00710 ast_autoservice_stop(chan);
00711
00712 return ret;
00713 }
00714
00715 static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len)
00716 {
00717 return acf_curl_helper(chan, cmd, info, buf, NULL, len);
00718 }
00719
00720 static int acf_curl2_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
00721 {
00722 return acf_curl_helper(chan, cmd, info, NULL, buf, len);
00723 }
00724
00725 static struct ast_custom_function acf_curl = {
00726 .name = "CURL",
00727 .synopsis = "Retrieves the contents of a URL",
00728 .syntax = "CURL(url[,post-data])",
00729 .desc =
00730 " url - URL to retrieve\n"
00731 " post-data - Optional data to send as a POST (GET is default action)\n",
00732 .read = acf_curl_exec,
00733 .read2 = acf_curl2_exec,
00734 };
00735
00736 static struct ast_custom_function acf_curlopt = {
00737 .name = "CURLOPT",
00738 .synopsis = "Set options for use with the CURL() function",
00739 .syntax = "CURLOPT(<option>)",
00740 .desc =
00741 " cookie - Send cookie with request [none]\n"
00742 " conntimeout - Number of seconds to wait for connection\n"
00743 " dnstimeout - Number of seconds to wait for DNS response\n"
00744 " ftptext - For FTP, force a text transfer (boolean)\n"
00745 " ftptimeout - For FTP, the server response timeout\n"
00746 " header - Retrieve header information (boolean)\n"
00747 " httptimeout - Number of seconds to wait for HTTP response\n"
00748 " maxredirs - Maximum number of redirects to follow\n"
00749 " proxy - Hostname or IP to use as a proxy\n"
00750 " proxytype - http, socks4, or socks5\n"
00751 " proxyport - port number of the proxy\n"
00752 " proxyuserpwd - A <user>:<pass> to use for authentication\n"
00753 " referer - Referer URL to use for the request\n"
00754 " useragent - UserAgent string to use\n"
00755 " userpwd - A <user>:<pass> to use for authentication\n"
00756 " ssl_verifypeer - Whether to verify the peer certificate (boolean)\n"
00757 " hashcompat - Result data will be compatible for use with HASH()\n"
00758 " - if value is \"legacy\", will translate '+' to ' '\n"
00759 "",
00760 .read = acf_curlopt_read,
00761 .read2 = acf_curlopt_read2,
00762 .write = acf_curlopt_write,
00763 };
00764
00765 static int unload_module(void)
00766 {
00767 int res;
00768
00769 res = ast_custom_function_unregister(&acf_curl);
00770 res |= ast_custom_function_unregister(&acf_curlopt);
00771
00772 return res;
00773 }
00774
00775 static int load_module(void)
00776 {
00777 int res;
00778
00779 if (!ast_module_check("res_curl.so")) {
00780 if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00781 ast_log(LOG_ERROR, "Cannot load res_curl, so func_curl cannot be loaded\n");
00782 return AST_MODULE_LOAD_DECLINE;
00783 }
00784 }
00785
00786 res = ast_custom_function_register(&acf_curl);
00787 res |= ast_custom_function_register(&acf_curlopt);
00788
00789 return res;
00790 }
00791
00792 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Load external URL",
00793 .load = load_module,
00794 .unload = unload_module,
00795 .load_pri = AST_MODPRI_REALTIME_DEPEND2,
00796 );
00797