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