Curl - Load a URL. More...
#include "asterisk.h"#include <curl/curl.h>#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/cli.h"#include "asterisk/module.h"#include "asterisk/app.h"#include "asterisk/utils.h"#include "asterisk/threadstorage.h"
Go to the source code of this file.
Data Structures | |
| struct | curl_settings |
| struct | global_curl_info |
Defines | |
| #define | CURLOPT_SPECIAL_HASHCOMPAT -500 |
| #define | CURLVERSION_ATLEAST(a, b, c) ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) |
Enumerations | |
| enum | optiontype { OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, OT_ENUM } |
Functions | |
| static void | __init_curl_instance (void) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | acf_curl_exec (struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) |
| static int | acf_curlopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | acf_curlopt_write (struct ast_channel *chan, const char *cmd, char *name, const char *value) |
| static void | curl_instance_cleanup (void *data) |
| static int | curl_instance_init (void *data) |
| static void | curlds_free (void *data) |
| static int | load_module (void) |
| static int | parse_curlopt_key (const char *name, CURLoption *key, enum optiontype *ot) |
| static int | unload_module (void) |
| static size_t | WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
| struct ast_custom_function | acf_curl |
| struct ast_custom_function | acf_curlopt |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_datastore_info | curl_info |
| static struct ast_threadstorage | curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , } |
| struct global_curl_info | global_curl_info |
| static const char * | global_useragent = "asterisk-libcurl-agent/1.0" |
Curl - Load a URL.
Definition in file func_curl.c.
| #define CURLOPT_SPECIAL_HASHCOMPAT -500 |
Definition at line 56 of file func_curl.c.
Referenced by acf_curl_exec(), and parse_curlopt_key().
| #define CURLVERSION_ATLEAST | ( | a, | |
| b, | |||
| c | |||
| ) | ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) |
Definition at line 53 of file func_curl.c.
| enum optiontype |
Definition at line 86 of file func_curl.c.
{
OT_BOOLEAN,
OT_INTEGER,
OT_INTEGER_MS,
OT_STRING,
OT_ENUM,
};
| static void __init_curl_instance | ( | void | ) | [static] |
Definition at line 395 of file func_curl.c.
{
| static void __reg_module | ( | void | ) | [static] |
Definition at line 575 of file func_curl.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 575 of file func_curl.c.
| static int acf_curl_exec | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | info, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 397 of file func_curl.c.
References AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_datastore_find(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_str_trim_blanks(), ast_strlen_zero(), ast_threadstorage_get(), ast_uri_decode(), curl_instance, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, curl_settings::key, curl_settings::list, LOG_ERROR, LOG_WARNING, name, pbx_builtin_setvar_helper(), S_OR, str, strsep(), url, and curl_settings::value.
{
struct ast_str *str = ast_str_create(16);
int ret = -1;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(url);
AST_APP_ARG(postdata);
);
CURL **curl;
struct curl_settings *cur;
struct ast_datastore *store = NULL;
int hashcompat = 0;
AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL;
*buf = '\0';
if (!str) {
return -1;
}
if (ast_strlen_zero(info)) {
ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
ast_free(str);
return -1;
}
AST_STANDARD_APP_ARGS(args, info);
if (chan) {
ast_autoservice_start(chan);
}
if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
return -1;
}
AST_LIST_LOCK(&global_curl_info);
AST_LIST_TRAVERSE(&global_curl_info, cur, list) {
if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
hashcompat = (cur->value != NULL) ? 1 : 0;
} else {
curl_easy_setopt(*curl, cur->key, cur->value);
}
}
if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
list = store->data;
AST_LIST_LOCK(list);
AST_LIST_TRAVERSE(list, cur, list) {
if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
hashcompat = (cur->value != NULL) ? 1 : 0;
} else {
curl_easy_setopt(*curl, cur->key, cur->value);
}
}
}
curl_easy_setopt(*curl, CURLOPT_URL, args.url);
curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str);
if (args.postdata) {
curl_easy_setopt(*curl, CURLOPT_POST, 1);
curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata);
}
curl_easy_perform(*curl);
if (store) {
AST_LIST_UNLOCK(list);
}
AST_LIST_UNLOCK(&global_curl_info);
if (args.postdata) {
curl_easy_setopt(*curl, CURLOPT_POST, 0);
}
if (ast_str_strlen(str)) {
ast_str_trim_blanks(str);
ast_debug(3, "str='%s'\n", ast_str_buffer(str));
if (hashcompat) {
char *remainder = ast_str_buffer(str);
char *piece;
struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2);
struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2);
int rowcount = 0;
while (fields && values && (piece = strsep(&remainder, "&"))) {
char *name = strsep(&piece, "=");
if (piece) {
ast_uri_decode(piece);
}
ast_uri_decode(name);
ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", name);
ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", S_OR(piece, ""));
rowcount++;
}
pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
ast_copy_string(buf, ast_str_buffer(values), len);
ast_free(fields);
ast_free(values);
} else {
ast_copy_string(buf, ast_str_buffer(str), len);
}
ret = 0;
}
ast_free(str);
if (chan)
ast_autoservice_stop(chan);
return ret;
}
| static int acf_curlopt_read | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | data, | ||
| char * | buf, | ||
| size_t | len | ||
| ) | [static] |
Definition at line 282 of file func_curl.c.
References ast_channel_datastore_find(), ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, global_curl_info, curl_settings::key, curl_settings::list, LOG_ERROR, OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and curl_settings::value.
{
struct ast_datastore *store;
struct global_curl_info *list[2] = { &global_curl_info, NULL };
struct curl_settings *cur = NULL;
CURLoption key;
enum optiontype ot;
int i;
if (parse_curlopt_key(data, &key, &ot)) {
ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data);
return -1;
}
if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
list[0] = store->data;
list[1] = &global_curl_info;
}
for (i = 0; i < 2; i++) {
if (!list[i]) {
break;
}
AST_LIST_LOCK(list[i]);
AST_LIST_TRAVERSE(list[i], cur, list) {
if (cur->key == key) {
if (ot == OT_BOOLEAN || ot == OT_INTEGER) {
snprintf(buf, len, "%ld", (long)cur->value);
} else if (ot == OT_INTEGER_MS) {
if ((long)cur->value % 1000 == 0) {
snprintf(buf, len, "%ld", (long)cur->value / 1000);
} else {
snprintf(buf, len, "%.3f", (double)((long)cur->value) / 1000.0);
}
} else if (ot == OT_STRING) {
ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value);
ast_copy_string(buf, cur->value, len);
} else if (key == CURLOPT_PROXYTYPE) {
if (0) {
#if CURLVERSION_ATLEAST(7,15,2)
} else if ((long)cur->value == CURLPROXY_SOCKS4) {
ast_copy_string(buf, "socks4", len);
#endif
#if CURLVERSION_ATLEAST(7,18,0)
} else if ((long)cur->value == CURLPROXY_SOCKS4A) {
ast_copy_string(buf, "socks4a", len);
#endif
} else if ((long)cur->value == CURLPROXY_SOCKS5) {
ast_copy_string(buf, "socks5", len);
#if CURLVERSION_ATLEAST(7,18,0)
} else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
ast_copy_string(buf, "socks5hostname", len);
#endif
#if CURLVERSION_ATLEAST(7,10,0)
} else if ((long)cur->value == CURLPROXY_HTTP) {
ast_copy_string(buf, "http", len);
#endif
} else {
ast_copy_string(buf, "unknown", len);
}
}
break;
}
}
AST_LIST_UNLOCK(list[i]);
if (cur) {
break;
}
}
return cur ? 0 : -1;
}
| static int acf_curlopt_write | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | name, | ||
| const char * | value | ||
| ) | [static] |
Definition at line 163 of file func_curl.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc(), ast_datastore_free(), ast_debug, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_true(), ast_datastore::data, free, global_curl_info, curl_settings::key, curl_settings::list, LOG_ERROR, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, OT_STRING, and parse_curlopt_key().
{
struct ast_datastore *store;
struct global_curl_info *list;
struct curl_settings *cur, *new = NULL;
CURLoption key;
enum optiontype ot;
if (chan) {
if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
/* Create a new datastore */
if (!(store = ast_datastore_alloc(&curl_info, NULL))) {
ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n");
return -1;
}
if (!(list = ast_calloc(1, sizeof(*list)))) {
ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n");
ast_datastore_free(store);
}
store->data = list;
AST_LIST_HEAD_INIT(list);
ast_channel_datastore_add(chan, store);
} else {
list = store->data;
}
} else {
/* Populate the global structure */
list = &global_curl_info;
}
if (!parse_curlopt_key(name, &key, &ot)) {
if (ot == OT_BOOLEAN) {
if ((new = ast_calloc(1, sizeof(*new)))) {
new->value = (void *)((long) ast_true(value));
}
} else if (ot == OT_INTEGER) {
long tmp = atol(value);
if ((new = ast_calloc(1, sizeof(*new)))) {
new->value = (void *)tmp;
}
} else if (ot == OT_INTEGER_MS) {
long tmp = atof(value) * 1000.0;
if ((new = ast_calloc(1, sizeof(*new)))) {
new->value = (void *)tmp;
}
} else if (ot == OT_STRING) {
if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) {
new->value = (char *)new + sizeof(*new);
strcpy(new->value, value);
}
} else if (ot == OT_ENUM) {
if (key == CURLOPT_PROXYTYPE) {
long ptype =
#if CURLVERSION_ATLEAST(7,10,0)
CURLPROXY_HTTP;
#else
CURLPROXY_SOCKS5;
#endif
if (0) {
#if CURLVERSION_ATLEAST(7,15,2)
} else if (!strcasecmp(value, "socks4")) {
ptype = CURLPROXY_SOCKS4;
#endif
#if CURLVERSION_ATLEAST(7,18,0)
} else if (!strcasecmp(value, "socks4a")) {
ptype = CURLPROXY_SOCKS4A;
#endif
#if CURLVERSION_ATLEAST(7,18,0)
} else if (!strcasecmp(value, "socks5")) {
ptype = CURLPROXY_SOCKS5;
#endif
#if CURLVERSION_ATLEAST(7,18,0)
} else if (!strncasecmp(value, "socks5", 6)) {
ptype = CURLPROXY_SOCKS5_HOSTNAME;
#endif
}
if ((new = ast_calloc(1, sizeof(*new)))) {
new->value = (void *)ptype;
}
} else {
/* Highly unlikely */
goto yuck;
}
}
/* Memory allocation error */
if (!new) {
return -1;
}
new->key = key;
} else {
yuck:
ast_log(LOG_ERROR, "Unrecognized option: %s\n", name);
return -1;
}
/* Remove any existing entry */
AST_LIST_LOCK(list);
AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) {
if (cur->key == new->key) {
AST_LIST_REMOVE_CURRENT(list);
free(cur);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END
/* Insert new entry */
ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value);
AST_LIST_INSERT_TAIL(list, new, list);
AST_LIST_UNLOCK(list);
return 0;
}
| static void curl_instance_cleanup | ( | void * | data | ) | [static] |
Definition at line 386 of file func_curl.c.
References ast_free.
{
CURL **curl = data;
curl_easy_cleanup(*curl);
ast_free(data);
}
| static int curl_instance_init | ( | void * | data | ) | [static] |
Definition at line 371 of file func_curl.c.
References global_useragent, and WriteMemoryCallback().
{
CURL **curl = data;
if (!(*curl = curl_easy_init()))
return -1;
curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(*curl, CURLOPT_USERAGENT, global_useragent);
return 0;
}
| static void curlds_free | ( | void * | data | ) | [static] |
Definition at line 73 of file func_curl.c.
References AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, and free.
{
AST_LIST_HEAD(global_curl_info, curl_settings) *list = data;
struct curl_settings *setting;
if (!list) {
return;
}
while ((setting = AST_LIST_REMOVE_HEAD(list, list))) {
free(setting);
}
AST_LIST_HEAD_DESTROY(list);
}
| static int load_module | ( | void | ) | [static] |
Definition at line 558 of file func_curl.c.
References acf_curl, acf_curlopt, ast_custom_function_register, ast_load_resource(), ast_log(), ast_module_check(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and LOG_ERROR.
{
int res;
if (!ast_module_check("res_curl.so")) {
if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
ast_log(LOG_ERROR, "Cannot load res_curl, so func_curl cannot be loaded\n");
return AST_MODULE_LOAD_DECLINE;
}
}
res = ast_custom_function_register(&acf_curl);
res |= ast_custom_function_register(&acf_curlopt);
return res;
}
| static int parse_curlopt_key | ( | const char * | name, |
| CURLoption * | key, | ||
| enum optiontype * | ot | ||
| ) | [static] |
Definition at line 94 of file func_curl.c.
References CURLOPT_SPECIAL_HASHCOMPAT, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, and OT_STRING.
Referenced by acf_curlopt_read(), and acf_curlopt_write().
{
if (!strcasecmp(name, "header")) {
*key = CURLOPT_HEADER;
*ot = OT_BOOLEAN;
} else if (!strcasecmp(name, "proxy")) {
*key = CURLOPT_PROXY;
*ot = OT_STRING;
} else if (!strcasecmp(name, "proxyport")) {
*key = CURLOPT_PROXYPORT;
*ot = OT_INTEGER;
} else if (!strcasecmp(name, "proxytype")) {
*key = CURLOPT_PROXYTYPE;
*ot = OT_ENUM;
} else if (!strcasecmp(name, "dnstimeout")) {
*key = CURLOPT_DNS_CACHE_TIMEOUT;
*ot = OT_INTEGER;
} else if (!strcasecmp(name, "userpwd")) {
*key = CURLOPT_USERPWD;
*ot = OT_STRING;
} else if (!strcasecmp(name, "proxyuserpwd")) {
*key = CURLOPT_PROXYUSERPWD;
*ot = OT_STRING;
} else if (!strcasecmp(name, "maxredirs")) {
*key = CURLOPT_MAXREDIRS;
*ot = OT_INTEGER;
} else if (!strcasecmp(name, "referer")) {
*key = CURLOPT_REFERER;
*ot = OT_STRING;
} else if (!strcasecmp(name, "useragent")) {
*key = CURLOPT_USERAGENT;
*ot = OT_STRING;
} else if (!strcasecmp(name, "cookie")) {
*key = CURLOPT_COOKIE;
*ot = OT_STRING;
} else if (!strcasecmp(name, "ftptimeout")) {
*key = CURLOPT_FTP_RESPONSE_TIMEOUT;
*ot = OT_INTEGER;
} else if (!strcasecmp(name, "httptimeout")) {
#if CURLVERSION_ATLEAST(7,16,2)
*key = CURLOPT_TIMEOUT_MS;
*ot = OT_INTEGER_MS;
#else
*key = CURLOPT_TIMEOUT;
*ot = OT_INTEGER;
#endif
} else if (!strcasecmp(name, "conntimeout")) {
#if CURLVERSION_ATLEAST(7,16,2)
*key = CURLOPT_CONNECTTIMEOUT_MS;
*ot = OT_INTEGER_MS;
#else
*key = CURLOPT_CONNECTTIMEOUT;
*ot = OT_INTEGER;
#endif
} else if (!strcasecmp(name, "ftptext")) {
*key = CURLOPT_TRANSFERTEXT;
*ot = OT_BOOLEAN;
} else if (!strcasecmp(name, "ssl_verifypeer")) {
*key = CURLOPT_SSL_VERIFYPEER;
*ot = OT_BOOLEAN;
} else if (!strcasecmp(name, "hashcompat")) {
*key = CURLOPT_SPECIAL_HASHCOMPAT;
*ot = OT_BOOLEAN;
} else {
return -1;
}
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 548 of file func_curl.c.
References acf_curl, acf_curlopt, and ast_custom_function_unregister().
{
int res;
res = ast_custom_function_unregister(&acf_curl);
res |= ast_custom_function_unregister(&acf_curlopt);
return res;
}
| static size_t WriteMemoryCallback | ( | void * | ptr, |
| size_t | size, | ||
| size_t | nmemb, | ||
| void * | data | ||
| ) | [static] |
Definition at line 355 of file func_curl.c.
References ast_debug, ast_str_append_substr(), ast_str_size(), and ast_str_strlen().
Referenced by curl_instance_init().
{
register int realsize = size * nmemb;
struct ast_str **pstr = (struct ast_str **)data;
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));
ast_str_append_substr(pstr, 0, ptr, realsize);
ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr));
return realsize;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 575 of file func_curl.c.
| struct ast_custom_function acf_curl |
Definition at line 511 of file func_curl.c.
Referenced by load_module(), and unload_module().
| struct ast_custom_function acf_curlopt |
Definition at line 521 of file func_curl.c.
Referenced by load_module(), and unload_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 575 of file func_curl.c.
struct ast_datastore_info curl_info [static] |
{
.type = "CURL",
.destroy = curlds_free,
}
Definition at line 60 of file func_curl.c.
struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , } [static] |
Definition at line 395 of file func_curl.c.
Referenced by acf_curl_exec().
| struct global_curl_info global_curl_info |
Referenced by acf_curlopt_read(), and acf_curlopt_write().
const char* global_useragent = "asterisk-libcurl-agent/1.0" [static] |
Definition at line 369 of file func_curl.c.
Referenced by curl_instance_init().