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