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