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 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 278132 $")
00036
00037 #include <curl/curl.h>
00038
00039 #include "asterisk/file.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/threadstorage.h"
00047
00048 AST_THREADSTORAGE(query_buf);
00049 AST_THREADSTORAGE(result_buf);
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap)
00061 {
00062 struct ast_str *query, *buffer;
00063 char buf1[256], buf2[256];
00064 const char *newparam, *newval;
00065 char *stringp, *pair, *key;
00066 int i;
00067 struct ast_variable *var = NULL, *prev = NULL;
00068 const int EncodeSpecialChars = 1;
00069
00070 if (!ast_custom_function_find("CURL")) {
00071 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00072 return NULL;
00073 }
00074
00075 if (!(query = ast_str_thread_get(&query_buf, 16))) {
00076 return NULL;
00077 }
00078
00079 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00080 return NULL;
00081 }
00082
00083 ast_str_set(&query, 0, "${CURL(%s/single,", url);
00084
00085 for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
00086 newval = va_arg(ap, const char *);
00087 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00088 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00089 ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
00090 }
00091 va_end(ap);
00092
00093 ast_str_append(&query, 0, ")}");
00094 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00095
00096
00097 if ((stringp = strchr(ast_str_buffer(buffer), '\r')) || (stringp = strchr(ast_str_buffer(buffer), '\n'))) {
00098 *stringp = '\0';
00099 }
00100
00101 stringp = ast_str_buffer(buffer);
00102 while ((pair = strsep(&stringp, "&"))) {
00103 key = strsep(&pair, "=");
00104 ast_uri_decode(key);
00105 if (pair) {
00106 ast_uri_decode(pair);
00107 }
00108
00109 if (!ast_strlen_zero(key)) {
00110 if (prev) {
00111 prev->next = ast_variable_new(key, S_OR(pair, ""), "");
00112 if (prev->next) {
00113 prev = prev->next;
00114 }
00115 } else {
00116 prev = var = ast_variable_new(key, S_OR(pair, ""), "");
00117 }
00118 }
00119 }
00120
00121 return var;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
00134 {
00135 struct ast_str *query, *buffer;
00136 char buf1[256], buf2[256];
00137 const char *newparam, *newval;
00138 char *stringp, *line, *pair, *key, *initfield = NULL;
00139 int i;
00140 const int EncodeSpecialChars = 1;
00141 struct ast_variable *var = NULL;
00142 struct ast_config *cfg = NULL;
00143 struct ast_category *cat = NULL;
00144
00145 if (!ast_custom_function_find("CURL")) {
00146 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00147 return NULL;
00148 }
00149
00150 if (!(query = ast_str_thread_get(&query_buf, 16))) {
00151 return NULL;
00152 }
00153
00154 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00155 return NULL;
00156 }
00157
00158 ast_str_set(&query, 0, "${CURL(%s/multi,", url);
00159
00160 for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
00161 newval = va_arg(ap, const char *);
00162 if (i == 0) {
00163 char *op;
00164 initfield = ast_strdupa(newparam);
00165 if ((op = strchr(initfield, ' ')))
00166 *op = '\0';
00167 }
00168 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00169 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00170 ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
00171 }
00172 va_end(ap);
00173
00174 ast_str_append(&query, 0, ")}");
00175
00176
00177 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00178
00179 if (!(cfg = ast_config_new())) {
00180 return NULL;
00181 }
00182
00183
00184 stringp = ast_str_buffer(buffer);
00185 while ((line = strsep(&stringp, "\r\n"))) {
00186 if (ast_strlen_zero(line)) {
00187 continue;
00188 }
00189
00190 if (!(cat = ast_category_new("", "", 99999))) {
00191 continue;
00192 }
00193
00194 while ((pair = strsep(&line, "&"))) {
00195 key = strsep(&pair, "=");
00196 ast_uri_decode(key);
00197 if (pair) {
00198 ast_uri_decode(pair);
00199 }
00200
00201 if (!strcasecmp(key, initfield) && pair) {
00202 ast_category_rename(cat, pair);
00203 }
00204
00205 if (!ast_strlen_zero(key)) {
00206 var = ast_variable_new(key, S_OR(pair, ""), "");
00207 ast_variable_append(cat, var);
00208 }
00209 }
00210 ast_category_append(cfg, cat);
00211 }
00212
00213 return cfg;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
00232 {
00233 struct ast_str *query, *buffer;
00234 char buf1[256], buf2[256];
00235 const char *newparam, *newval;
00236 char *stringp;
00237 int i, rowcount = -1;
00238 const int EncodeSpecialChars = 1;
00239
00240 if (!ast_custom_function_find("CURL")) {
00241 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00242 return -1;
00243 }
00244
00245 if (!(query = ast_str_thread_get(&query_buf, 16))) {
00246 return -1;
00247 }
00248
00249 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00250 return -1;
00251 }
00252
00253 ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
00254 ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
00255 ast_str_set(&query, 0, "${CURL(%s/update?%s=%s,", url, buf1, buf2);
00256
00257 for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
00258 newval = va_arg(ap, const char *);
00259 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00260 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00261 ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
00262 }
00263 va_end(ap);
00264
00265 ast_str_append(&query, 0, ")}");
00266 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00267
00268
00269 stringp = ast_str_buffer(buffer);
00270 while (*stringp <= ' ') {
00271 stringp++;
00272 }
00273 sscanf(stringp, "%30d", &rowcount);
00274
00275 if (rowcount >= 0) {
00276 return (int)rowcount;
00277 }
00278
00279 return -1;
00280 }
00281
00282 static int update2_curl(const char *url, const char *unused, va_list ap)
00283 {
00284 struct ast_str *query, *buffer;
00285 char buf1[200], buf2[200];
00286 const char *newparam, *newval;
00287 char *stringp;
00288 int rowcount = -1, lookup = 1, first = 1;
00289 const int EncodeSpecialChars = 1;
00290
00291 if (!ast_custom_function_find("CURL")) {
00292 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00293 return -1;
00294 }
00295
00296 if (!(query = ast_str_thread_get(&query_buf, 1000)))
00297 return -1;
00298
00299 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00300 return -1;
00301 }
00302
00303 ast_str_set(&query, 0, "${CURL(%s/update?", url);
00304
00305 for (;;) {
00306 if ((newparam = va_arg(ap, const char *)) == SENTINEL) {
00307 if (lookup) {
00308 lookup = 0;
00309 ast_str_append(&query, 0, ",");
00310
00311 first = 1;
00312 continue;
00313 } else {
00314 break;
00315 }
00316 }
00317 newval = va_arg(ap, const char *);
00318 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00319 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00320 ast_str_append(&query, 0, "%s%s=%s", first ? "" : "&", buf1, buf2);
00321 first = 0;
00322 }
00323 va_end(ap);
00324
00325 ast_str_append(&query, 0, ")}");
00326
00327
00328
00329
00330 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00331
00332
00333 stringp = ast_str_buffer(buffer);
00334 while (*stringp <= ' ') {
00335 stringp++;
00336 }
00337 sscanf(stringp, "%30d", &rowcount);
00338
00339 if (rowcount >= 0) {
00340 return (int)rowcount;
00341 }
00342
00343 return -1;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 static int store_curl(const char *url, const char *unused, va_list ap)
00360 {
00361 struct ast_str *query, *buffer;
00362 char buf1[256], buf2[256];
00363 const char *newparam, *newval;
00364 char *stringp;
00365 int i, rowcount = -1;
00366 const int EncodeSpecialChars = 1;
00367
00368 if (!ast_custom_function_find("CURL")) {
00369 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00370 return -1;
00371 }
00372
00373 if (!(query = ast_str_thread_get(&query_buf, 1000))) {
00374 return -1;
00375 }
00376
00377 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00378 return -1;
00379 }
00380
00381 ast_str_set(&query, 0, "${CURL(%s/store,", url);
00382
00383 for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
00384 newval = va_arg(ap, const char *);
00385 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00386 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00387 ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
00388 }
00389 va_end(ap);
00390
00391 ast_str_append(&query, 0, ")}");
00392 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00393
00394 stringp = ast_str_buffer(buffer);
00395 while (*stringp <= ' ') {
00396 stringp++;
00397 }
00398 sscanf(stringp, "%30d", &rowcount);
00399
00400 if (rowcount >= 0) {
00401 return rowcount;
00402 }
00403
00404 return -1;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
00423 {
00424 struct ast_str *query, *buffer;
00425 char buf1[200], buf2[200];
00426 const char *newparam, *newval;
00427 char *stringp;
00428 int i, rowcount = -1;
00429 const int EncodeSpecialChars = 1;
00430
00431 if (!ast_custom_function_find("CURL")) {
00432 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00433 return -1;
00434 }
00435
00436 if (!(query = ast_str_thread_get(&query_buf, 1000))) {
00437 return -1;
00438 }
00439
00440 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00441 return -1;
00442 }
00443
00444 ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
00445 ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
00446 ast_str_set(&query, 0, "${CURL(%s/destroy,%s=%s&", url, buf1, buf2);
00447
00448 for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
00449 newval = va_arg(ap, const char *);
00450 ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
00451 ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
00452 ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
00453 }
00454 va_end(ap);
00455
00456 ast_str_append(&query, 0, ")}");
00457 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00458
00459
00460 stringp = ast_str_buffer(buffer);
00461 while (*stringp <= ' ') {
00462 stringp++;
00463 }
00464 sscanf(stringp, "%30d", &rowcount);
00465
00466 if (rowcount >= 0) {
00467 return (int)rowcount;
00468 }
00469
00470 return -1;
00471 }
00472
00473 static int require_curl(const char *url, const char *unused, va_list ap)
00474 {
00475 struct ast_str *query, *buffer;
00476 char *elm, field[256];
00477 int type, size;
00478 const int EncodeSpecialChars = 1;
00479
00480 if (!ast_custom_function_find("CURL")) {
00481 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00482 return -1;
00483 }
00484
00485 if (!(query = ast_str_thread_get(&query_buf, 100))) {
00486 return -1;
00487 }
00488
00489 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00490 return -1;
00491 }
00492
00493 ast_str_set(&query, 0, "${CURL(%s/require,", url);
00494
00495 while ((elm = va_arg(ap, char *))) {
00496 type = va_arg(ap, require_type);
00497 size = va_arg(ap, int);
00498 ast_uri_encode(elm, field, sizeof(field), EncodeSpecialChars);
00499 ast_str_append(&query, 0, "%s=%s%%3A%d", field,
00500 type == RQ_CHAR ? "char" :
00501 type == RQ_INTEGER1 ? "integer1" :
00502 type == RQ_UINTEGER1 ? "uinteger1" :
00503 type == RQ_INTEGER2 ? "integer2" :
00504 type == RQ_UINTEGER2 ? "uinteger2" :
00505 type == RQ_INTEGER3 ? "integer3" :
00506 type == RQ_UINTEGER3 ? "uinteger3" :
00507 type == RQ_INTEGER4 ? "integer4" :
00508 type == RQ_UINTEGER4 ? "uinteger4" :
00509 type == RQ_INTEGER8 ? "integer8" :
00510 type == RQ_UINTEGER8 ? "uinteger8" :
00511 type == RQ_DATE ? "date" :
00512 type == RQ_DATETIME ? "datetime" :
00513 type == RQ_FLOAT ? "float" :
00514 "unknown", size);
00515 }
00516 va_end(ap);
00517
00518 ast_str_append(&query, 0, ")}");
00519 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00520 return atoi(ast_str_buffer(buffer));
00521 }
00522
00523 static struct ast_config *config_curl(const char *url, const char *unused, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
00524 {
00525 struct ast_str *query, *buffer;
00526 char buf1[200];
00527 char *stringp, *line, *pair, *key;
00528 const int EncodeSpecialChars = 1;
00529 int last_cat_metric = -1, cat_metric = -1;
00530 struct ast_category *cat = NULL;
00531 char *cur_cat = "";
00532 char *category = "", *var_name = "", *var_val = "";
00533 struct ast_flags loader_flags = { 0 };
00534
00535 if (!ast_custom_function_find("CURL")) {
00536 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00537 return NULL;
00538 }
00539
00540 if (!(query = ast_str_thread_get(&query_buf, 100))) {
00541 return NULL;
00542 }
00543
00544 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00545 return NULL;
00546 }
00547
00548 ast_uri_encode(file, buf1, sizeof(buf1), EncodeSpecialChars);
00549 ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
00550
00551
00552 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00553
00554
00555 stringp = ast_str_buffer(buffer);
00556 cat = ast_config_get_current_category(cfg);
00557
00558 while ((line = strsep(&stringp, "\r\n"))) {
00559 if (ast_strlen_zero(line)) {
00560 continue;
00561 }
00562
00563 while ((pair = strsep(&line, "&"))) {
00564 key = strsep(&pair, "=");
00565 ast_uri_decode(key);
00566 if (pair) {
00567 ast_uri_decode(pair);
00568 }
00569
00570 if (!strcasecmp(key, "category")) {
00571 category = S_OR(pair, "");
00572 } else if (!strcasecmp(key, "var_name")) {
00573 var_name = S_OR(pair, "");
00574 } else if (!strcasecmp(key, "var_val")) {
00575 var_val = S_OR(pair, "");
00576 } else if (!strcasecmp(key, "cat_metric")) {
00577 cat_metric = pair ? atoi(pair) : 0;
00578 }
00579 }
00580
00581 if (!strcmp(var_name, "#include")) {
00582 if (!ast_config_internal_load(var_val, cfg, loader_flags, "", who_asked))
00583 return NULL;
00584 }
00585
00586 if (strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
00587 if (!(cat = ast_category_new(category, "", 99999)))
00588 break;
00589 cur_cat = category;
00590 last_cat_metric = cat_metric;
00591 ast_category_append(cfg, cat);
00592 }
00593 ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
00594 }
00595
00596 return cfg;
00597 }
00598
00599 static struct ast_config_engine curl_engine = {
00600 .name = "curl",
00601 .load_func = config_curl,
00602 .realtime_func = realtime_curl,
00603 .realtime_multi_func = realtime_multi_curl,
00604 .store_func = store_curl,
00605 .destroy_func = destroy_curl,
00606 .update_func = update_curl,
00607 .update2_func = update2_curl,
00608 .require_func = require_curl,
00609 };
00610
00611 static int reload_module(void)
00612 {
00613 struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
00614 struct ast_config *cfg;
00615 struct ast_variable *var;
00616
00617 if (!(cfg = ast_config_load("res_curl.conf", flags))) {
00618 return 0;
00619 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00620 ast_log(LOG_WARNING, "res_curl.conf could not be parsed!\n");
00621 return 0;
00622 }
00623
00624 if (!(var = ast_variable_browse(cfg, "globals")) && !(var = ast_variable_browse(cfg, "global")) && !(var = ast_variable_browse(cfg, "general"))) {
00625 ast_log(LOG_WARNING, "[globals] not found in res_curl.conf\n");
00626 ast_config_destroy(cfg);
00627 return 0;
00628 }
00629
00630 for (; var; var = var->next) {
00631 if (strncmp(var->name, "CURLOPT(", 8)) {
00632 char name[256];
00633 snprintf(name, sizeof(name), "CURLOPT(%s)", var->name);
00634 pbx_builtin_setvar_helper(NULL, name, var->value);
00635 } else {
00636 pbx_builtin_setvar_helper(NULL, var->name, var->value);
00637 }
00638 }
00639 ast_config_destroy(cfg);
00640 return 0;
00641 }
00642
00643 static int unload_module(void)
00644 {
00645 ast_config_engine_deregister(&curl_engine);
00646 ast_verb(1, "res_config_curl unloaded.\n");
00647 return 0;
00648 }
00649
00650 static int load_module(void)
00651 {
00652 if (!ast_module_check("res_curl.so")) {
00653 if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00654 ast_log(LOG_ERROR, "Cannot load res_curl, so res_config_curl cannot be loaded\n");
00655 return AST_MODULE_LOAD_DECLINE;
00656 }
00657 }
00658
00659 if (!ast_module_check("func_curl.so")) {
00660 if (ast_load_resource("func_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00661 ast_log(LOG_ERROR, "Cannot load func_curl, so res_config_curl cannot be loaded\n");
00662 return AST_MODULE_LOAD_DECLINE;
00663 }
00664 }
00665
00666 reload_module();
00667
00668 ast_config_engine_register(&curl_engine);
00669 ast_verb(1, "res_config_curl loaded.\n");
00670 return 0;
00671 }
00672
00673 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime Curl configuration",
00674 .load = load_module,
00675 .unload = unload_module,
00676 .reload = reload_module,
00677 .load_pri = AST_MODPRI_REALTIME_DRIVER,
00678 );