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: 383667 $")
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, i = 0;
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=%s%%3A%d",
00495 i > 0 ? "&" : "",
00496 field,
00497 type == RQ_CHAR ? "char" :
00498 type == RQ_INTEGER1 ? "integer1" :
00499 type == RQ_UINTEGER1 ? "uinteger1" :
00500 type == RQ_INTEGER2 ? "integer2" :
00501 type == RQ_UINTEGER2 ? "uinteger2" :
00502 type == RQ_INTEGER3 ? "integer3" :
00503 type == RQ_UINTEGER3 ? "uinteger3" :
00504 type == RQ_INTEGER4 ? "integer4" :
00505 type == RQ_UINTEGER4 ? "uinteger4" :
00506 type == RQ_INTEGER8 ? "integer8" :
00507 type == RQ_UINTEGER8 ? "uinteger8" :
00508 type == RQ_DATE ? "date" :
00509 type == RQ_DATETIME ? "datetime" :
00510 type == RQ_FLOAT ? "float" :
00511 "unknown", size);
00512 i++;
00513 }
00514
00515 ast_str_append(&query, 0, ")}");
00516 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00517 return atoi(ast_str_buffer(buffer));
00518 }
00519
00520 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)
00521 {
00522 struct ast_str *query, *buffer;
00523 char buf1[200];
00524 char *stringp, *line, *pair, *key;
00525 const int EncodeSpecialChars = 1;
00526 int last_cat_metric = -1, cat_metric = -1;
00527 struct ast_category *cat = NULL;
00528 char *cur_cat = "";
00529 char *category = "", *var_name = "", *var_val = "";
00530 struct ast_flags loader_flags = { 0 };
00531
00532 if (!ast_custom_function_find("CURL")) {
00533 ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
00534 return NULL;
00535 }
00536
00537 if (!(query = ast_str_thread_get(&query_buf, 100))) {
00538 return NULL;
00539 }
00540
00541 if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
00542 return NULL;
00543 }
00544
00545 ast_uri_encode(file, buf1, sizeof(buf1), EncodeSpecialChars);
00546 ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
00547
00548
00549 ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
00550
00551
00552 stringp = ast_str_buffer(buffer);
00553 cat = ast_config_get_current_category(cfg);
00554
00555 while ((line = strsep(&stringp, "\r\n"))) {
00556 if (ast_strlen_zero(line)) {
00557 continue;
00558 }
00559
00560 while ((pair = strsep(&line, "&"))) {
00561 key = strsep(&pair, "=");
00562 ast_uri_decode(key);
00563 if (pair) {
00564 ast_uri_decode(pair);
00565 }
00566
00567 if (!strcasecmp(key, "category")) {
00568 category = S_OR(pair, "");
00569 } else if (!strcasecmp(key, "var_name")) {
00570 var_name = S_OR(pair, "");
00571 } else if (!strcasecmp(key, "var_val")) {
00572 var_val = S_OR(pair, "");
00573 } else if (!strcasecmp(key, "cat_metric")) {
00574 cat_metric = pair ? atoi(pair) : 0;
00575 }
00576 }
00577
00578 if (!strcmp(var_name, "#include")) {
00579 if (!ast_config_internal_load(var_val, cfg, loader_flags, "", who_asked))
00580 return NULL;
00581 }
00582
00583 if (!cat || strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
00584 if (!(cat = ast_category_new(category, "", 99999)))
00585 break;
00586 cur_cat = category;
00587 last_cat_metric = cat_metric;
00588 ast_category_append(cfg, cat);
00589 }
00590 ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
00591 }
00592
00593 return cfg;
00594 }
00595
00596 static struct ast_config_engine curl_engine = {
00597 .name = "curl",
00598 .load_func = config_curl,
00599 .realtime_func = realtime_curl,
00600 .realtime_multi_func = realtime_multi_curl,
00601 .store_func = store_curl,
00602 .destroy_func = destroy_curl,
00603 .update_func = update_curl,
00604 .update2_func = update2_curl,
00605 .require_func = require_curl,
00606 };
00607
00608 static int reload_module(void)
00609 {
00610 struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
00611 struct ast_config *cfg;
00612 struct ast_variable *var;
00613
00614 if (!(cfg = ast_config_load("res_curl.conf", flags))) {
00615 return 0;
00616 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00617 ast_log(LOG_WARNING, "res_curl.conf could not be parsed!\n");
00618 return 0;
00619 }
00620
00621 if (!(var = ast_variable_browse(cfg, "globals")) && !(var = ast_variable_browse(cfg, "global")) && !(var = ast_variable_browse(cfg, "general"))) {
00622 ast_log(LOG_WARNING, "[globals] not found in res_curl.conf\n");
00623 ast_config_destroy(cfg);
00624 return 0;
00625 }
00626
00627 for (; var; var = var->next) {
00628 if (strncmp(var->name, "CURLOPT(", 8)) {
00629 char name[256];
00630 snprintf(name, sizeof(name), "CURLOPT(%s)", var->name);
00631 pbx_builtin_setvar_helper(NULL, name, var->value);
00632 } else {
00633 pbx_builtin_setvar_helper(NULL, var->name, var->value);
00634 }
00635 }
00636 ast_config_destroy(cfg);
00637 return 0;
00638 }
00639
00640 static int unload_module(void)
00641 {
00642 ast_config_engine_deregister(&curl_engine);
00643 ast_verb(1, "res_config_curl unloaded.\n");
00644 return 0;
00645 }
00646
00647 static int load_module(void)
00648 {
00649 if (!ast_module_check("res_curl.so")) {
00650 if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00651 ast_log(LOG_ERROR, "Cannot load res_curl, so res_config_curl cannot be loaded\n");
00652 return AST_MODULE_LOAD_DECLINE;
00653 }
00654 }
00655
00656 if (!ast_module_check("func_curl.so")) {
00657 if (ast_load_resource("func_curl.so") != AST_MODULE_LOAD_SUCCESS) {
00658 ast_log(LOG_ERROR, "Cannot load func_curl, so res_config_curl cannot be loaded\n");
00659 return AST_MODULE_LOAD_DECLINE;
00660 }
00661 }
00662
00663 reload_module();
00664
00665 ast_config_engine_register(&curl_engine);
00666 ast_verb(1, "res_config_curl loaded.\n");
00667 return 0;
00668 }
00669
00670 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime Curl configuration",
00671 .load = load_module,
00672 .unload = unload_module,
00673 .reload = reload_module,
00674 .load_pri = AST_MODPRI_REALTIME_DRIVER,
00675 );