res_config_curl.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2008, Digium, Inc.
  5. *
  6. * Tilghman Lesher <res_config_curl_v1@the-tilghman.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief curl plugin for portable configuration engine
  21. *
  22. * \author Tilghman Lesher <res_config_curl_v1@the-tilghman.com>
  23. *
  24. * \extref Depends on the CURL library - http://curl.haxx.se/
  25. *
  26. */
  27. /*** MODULEINFO
  28. <depend>curl</depend>
  29. <support_level>core</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include <curl/curl.h>
  34. #include "asterisk/file.h"
  35. #include "asterisk/channel.h"
  36. #include "asterisk/pbx.h"
  37. #include "asterisk/config.h"
  38. #include "asterisk/module.h"
  39. #include "asterisk/lock.h"
  40. #include "asterisk/utils.h"
  41. #include "asterisk/threadstorage.h"
  42. AST_THREADSTORAGE(query_buf);
  43. AST_THREADSTORAGE(result_buf);
  44. /*!
  45. * \brief Execute a curl query and return ast_variable list
  46. * \param url The base URL from which to retrieve data
  47. * \param unused Not currently used
  48. * \param ap list containing one or more field/operator/value set.
  49. *
  50. * \retval var on success
  51. * \retval NULL on failure
  52. */
  53. static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap)
  54. {
  55. struct ast_str *query, *buffer;
  56. char buf1[256], buf2[256];
  57. const char *newparam, *newval;
  58. char *stringp, *pair, *key;
  59. int i;
  60. struct ast_variable *var = NULL, *prev = NULL;
  61. const int EncodeSpecialChars = 1;
  62. if (!ast_custom_function_find("CURL")) {
  63. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  64. return NULL;
  65. }
  66. if (!(query = ast_str_thread_get(&query_buf, 16))) {
  67. return NULL;
  68. }
  69. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  70. return NULL;
  71. }
  72. ast_str_set(&query, 0, "${CURL(%s/single,", url);
  73. for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
  74. newval = va_arg(ap, const char *);
  75. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  76. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  77. ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
  78. }
  79. va_end(ap);
  80. ast_str_append(&query, 0, ")}");
  81. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  82. /* Remove any trailing newline characters */
  83. if ((stringp = strchr(ast_str_buffer(buffer), '\r')) || (stringp = strchr(ast_str_buffer(buffer), '\n'))) {
  84. *stringp = '\0';
  85. }
  86. stringp = ast_str_buffer(buffer);
  87. while ((pair = strsep(&stringp, "&"))) {
  88. key = strsep(&pair, "=");
  89. ast_uri_decode(key);
  90. if (pair) {
  91. ast_uri_decode(pair);
  92. }
  93. if (!ast_strlen_zero(key)) {
  94. if (prev) {
  95. prev->next = ast_variable_new(key, S_OR(pair, ""), "");
  96. if (prev->next) {
  97. prev = prev->next;
  98. }
  99. } else {
  100. prev = var = ast_variable_new(key, S_OR(pair, ""), "");
  101. }
  102. }
  103. }
  104. return var;
  105. }
  106. /*!
  107. * \brief Excute an Select query and return ast_config list
  108. * \param url
  109. * \param unused
  110. * \param ap list containing one or more field/operator/value set.
  111. *
  112. * \retval struct ast_config pointer on success
  113. * \retval NULL on failure
  114. */
  115. static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
  116. {
  117. struct ast_str *query, *buffer;
  118. char buf1[256], buf2[256];
  119. const char *newparam, *newval;
  120. char *stringp, *line, *pair, *key, *initfield = NULL;
  121. int i;
  122. const int EncodeSpecialChars = 1;
  123. struct ast_variable *var = NULL;
  124. struct ast_config *cfg = NULL;
  125. struct ast_category *cat = NULL;
  126. if (!ast_custom_function_find("CURL")) {
  127. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  128. return NULL;
  129. }
  130. if (!(query = ast_str_thread_get(&query_buf, 16))) {
  131. return NULL;
  132. }
  133. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  134. return NULL;
  135. }
  136. ast_str_set(&query, 0, "${CURL(%s/multi,", url);
  137. for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
  138. newval = va_arg(ap, const char *);
  139. if (i == 0) {
  140. char *op;
  141. initfield = ast_strdupa(newparam);
  142. if ((op = strchr(initfield, ' ')))
  143. *op = '\0';
  144. }
  145. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  146. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  147. ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
  148. }
  149. va_end(ap);
  150. ast_str_append(&query, 0, ")}");
  151. /* Do the CURL query */
  152. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  153. if (!(cfg = ast_config_new())) {
  154. return NULL;
  155. }
  156. /* Line oriented output */
  157. stringp = ast_str_buffer(buffer);
  158. while ((line = strsep(&stringp, "\r\n"))) {
  159. if (ast_strlen_zero(line)) {
  160. continue;
  161. }
  162. if (!(cat = ast_category_new("", "", 99999))) {
  163. continue;
  164. }
  165. while ((pair = strsep(&line, "&"))) {
  166. key = strsep(&pair, "=");
  167. ast_uri_decode(key);
  168. if (pair) {
  169. ast_uri_decode(pair);
  170. }
  171. if (!strcasecmp(key, initfield) && pair) {
  172. ast_category_rename(cat, pair);
  173. }
  174. if (!ast_strlen_zero(key)) {
  175. var = ast_variable_new(key, S_OR(pair, ""), "");
  176. ast_variable_append(cat, var);
  177. }
  178. }
  179. ast_category_append(cfg, cat);
  180. }
  181. return cfg;
  182. }
  183. /*!
  184. * \brief Execute an UPDATE query
  185. * \param url
  186. * \param unused
  187. * \param keyfield where clause field
  188. * \param lookup value of field for where clause
  189. * \param ap list containing one or more field/value set(s).
  190. *
  191. * Update a database table, prepare the sql statement using keyfield and lookup
  192. * control the number of records to change. All values to be changed are stored in ap list.
  193. * Sub-in the values to the prepared statement and execute it.
  194. *
  195. * \retval number of rows affected
  196. * \retval -1 on failure
  197. */
  198. static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
  199. {
  200. struct ast_str *query, *buffer;
  201. char buf1[256], buf2[256];
  202. const char *newparam, *newval;
  203. char *stringp;
  204. int i, rowcount = -1;
  205. const int EncodeSpecialChars = 1;
  206. if (!ast_custom_function_find("CURL")) {
  207. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  208. return -1;
  209. }
  210. if (!(query = ast_str_thread_get(&query_buf, 16))) {
  211. return -1;
  212. }
  213. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  214. return -1;
  215. }
  216. ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
  217. ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
  218. ast_str_set(&query, 0, "${CURL(%s/update?%s=%s,", url, buf1, buf2);
  219. for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
  220. newval = va_arg(ap, const char *);
  221. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  222. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  223. ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
  224. }
  225. va_end(ap);
  226. ast_str_append(&query, 0, ")}");
  227. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  228. /* Line oriented output */
  229. stringp = ast_str_buffer(buffer);
  230. while (*stringp <= ' ') {
  231. stringp++;
  232. }
  233. sscanf(stringp, "%30d", &rowcount);
  234. if (rowcount >= 0) {
  235. return (int)rowcount;
  236. }
  237. return -1;
  238. }
  239. static int update2_curl(const char *url, const char *unused, va_list ap)
  240. {
  241. struct ast_str *query, *buffer;
  242. char buf1[200], buf2[200];
  243. const char *newparam, *newval;
  244. char *stringp;
  245. int rowcount = -1, lookup = 1, first = 1;
  246. const int EncodeSpecialChars = 1;
  247. if (!ast_custom_function_find("CURL")) {
  248. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  249. return -1;
  250. }
  251. if (!(query = ast_str_thread_get(&query_buf, 1000)))
  252. return -1;
  253. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  254. return -1;
  255. }
  256. ast_str_set(&query, 0, "${CURL(%s/update?", url);
  257. for (;;) {
  258. if ((newparam = va_arg(ap, const char *)) == SENTINEL) {
  259. if (lookup) {
  260. lookup = 0;
  261. ast_str_append(&query, 0, ",");
  262. /* Back to the first parameter; we don't need a starting '&' */
  263. first = 1;
  264. continue;
  265. } else {
  266. break;
  267. }
  268. }
  269. newval = va_arg(ap, const char *);
  270. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  271. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  272. ast_str_append(&query, 0, "%s%s=%s", first ? "" : "&", buf1, buf2);
  273. first = 0;
  274. }
  275. va_end(ap);
  276. ast_str_append(&query, 0, ")}");
  277. /* Proxies work, by setting CURLOPT options in the [globals] section of
  278. * extensions.conf. Unfortunately, this means preloading pbx_config.so
  279. * so that they have an opportunity to be set prior to startup realtime
  280. * queries. */
  281. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  282. /* Line oriented output */
  283. stringp = ast_str_buffer(buffer);
  284. while (*stringp <= ' ') {
  285. stringp++;
  286. }
  287. sscanf(stringp, "%30d", &rowcount);
  288. if (rowcount >= 0) {
  289. return (int)rowcount;
  290. }
  291. return -1;
  292. }
  293. /*!
  294. * \brief Execute an INSERT query
  295. * \param url
  296. * \param unused
  297. * \param ap list containing one or more field/value set(s)
  298. *
  299. * Insert a new record into database table, prepare the sql statement.
  300. * All values to be changed are stored in ap list.
  301. * Sub-in the values to the prepared statement and execute it.
  302. *
  303. * \retval number of rows affected
  304. * \retval -1 on failure
  305. */
  306. static int store_curl(const char *url, const char *unused, va_list ap)
  307. {
  308. struct ast_str *query, *buffer;
  309. char buf1[256], buf2[256];
  310. const char *newparam, *newval;
  311. char *stringp;
  312. int i, rowcount = -1;
  313. const int EncodeSpecialChars = 1;
  314. if (!ast_custom_function_find("CURL")) {
  315. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  316. return -1;
  317. }
  318. if (!(query = ast_str_thread_get(&query_buf, 1000))) {
  319. return -1;
  320. }
  321. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  322. return -1;
  323. }
  324. ast_str_set(&query, 0, "${CURL(%s/store,", url);
  325. for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
  326. newval = va_arg(ap, const char *);
  327. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  328. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  329. ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
  330. }
  331. va_end(ap);
  332. ast_str_append(&query, 0, ")}");
  333. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  334. stringp = ast_str_buffer(buffer);
  335. while (*stringp <= ' ') {
  336. stringp++;
  337. }
  338. sscanf(stringp, "%30d", &rowcount);
  339. if (rowcount >= 0) {
  340. return rowcount;
  341. }
  342. return -1;
  343. }
  344. /*!
  345. * \brief Execute an DELETE query
  346. * \param url
  347. * \param unused
  348. * \param keyfield where clause field
  349. * \param lookup value of field for where clause
  350. * \param ap list containing one or more field/value set(s)
  351. *
  352. * Delete a row from a database table, prepare the sql statement using keyfield and lookup
  353. * control the number of records to change. Additional params to match rows are stored in ap list.
  354. * Sub-in the values to the prepared statement and execute it.
  355. *
  356. * \retval number of rows affected
  357. * \retval -1 on failure
  358. */
  359. static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
  360. {
  361. struct ast_str *query, *buffer;
  362. char buf1[200], buf2[200];
  363. const char *newparam, *newval;
  364. char *stringp;
  365. int i, rowcount = -1;
  366. const int EncodeSpecialChars = 1;
  367. if (!ast_custom_function_find("CURL")) {
  368. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  369. return -1;
  370. }
  371. if (!(query = ast_str_thread_get(&query_buf, 1000))) {
  372. return -1;
  373. }
  374. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  375. return -1;
  376. }
  377. ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
  378. ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
  379. ast_str_set(&query, 0, "${CURL(%s/destroy,%s=%s&", url, buf1, buf2);
  380. for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
  381. newval = va_arg(ap, const char *);
  382. ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
  383. ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
  384. ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
  385. }
  386. va_end(ap);
  387. ast_str_append(&query, 0, ")}");
  388. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  389. /* Line oriented output */
  390. stringp = ast_str_buffer(buffer);
  391. while (*stringp <= ' ') {
  392. stringp++;
  393. }
  394. sscanf(stringp, "%30d", &rowcount);
  395. if (rowcount >= 0) {
  396. return (int)rowcount;
  397. }
  398. return -1;
  399. }
  400. static int require_curl(const char *url, const char *unused, va_list ap)
  401. {
  402. struct ast_str *query, *buffer;
  403. char *elm, field[256];
  404. int type, size;
  405. const int EncodeSpecialChars = 1;
  406. if (!ast_custom_function_find("CURL")) {
  407. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  408. return -1;
  409. }
  410. if (!(query = ast_str_thread_get(&query_buf, 100))) {
  411. return -1;
  412. }
  413. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  414. return -1;
  415. }
  416. ast_str_set(&query, 0, "${CURL(%s/require,", url);
  417. while ((elm = va_arg(ap, char *))) {
  418. type = va_arg(ap, require_type);
  419. size = va_arg(ap, int);
  420. ast_uri_encode(elm, field, sizeof(field), EncodeSpecialChars);
  421. ast_str_append(&query, 0, "%s=%s%%3A%d", field,
  422. type == RQ_CHAR ? "char" :
  423. type == RQ_INTEGER1 ? "integer1" :
  424. type == RQ_UINTEGER1 ? "uinteger1" :
  425. type == RQ_INTEGER2 ? "integer2" :
  426. type == RQ_UINTEGER2 ? "uinteger2" :
  427. type == RQ_INTEGER3 ? "integer3" :
  428. type == RQ_UINTEGER3 ? "uinteger3" :
  429. type == RQ_INTEGER4 ? "integer4" :
  430. type == RQ_UINTEGER4 ? "uinteger4" :
  431. type == RQ_INTEGER8 ? "integer8" :
  432. type == RQ_UINTEGER8 ? "uinteger8" :
  433. type == RQ_DATE ? "date" :
  434. type == RQ_DATETIME ? "datetime" :
  435. type == RQ_FLOAT ? "float" :
  436. "unknown", size);
  437. }
  438. va_end(ap);
  439. ast_str_append(&query, 0, ")}");
  440. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  441. return atoi(ast_str_buffer(buffer));
  442. }
  443. 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)
  444. {
  445. struct ast_str *query, *buffer;
  446. char buf1[200];
  447. char *stringp, *line, *pair, *key;
  448. const int EncodeSpecialChars = 1;
  449. int last_cat_metric = -1, cat_metric = -1;
  450. struct ast_category *cat = NULL;
  451. char *cur_cat = "";
  452. char *category = "", *var_name = "", *var_val = "";
  453. struct ast_flags loader_flags = { 0 };
  454. if (!ast_custom_function_find("CURL")) {
  455. ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
  456. return NULL;
  457. }
  458. if (!(query = ast_str_thread_get(&query_buf, 100))) {
  459. return NULL;
  460. }
  461. if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
  462. return NULL;
  463. }
  464. ast_uri_encode(file, buf1, sizeof(buf1), EncodeSpecialChars);
  465. ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
  466. /* Do the CURL query */
  467. ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));
  468. /* Line oriented output */
  469. stringp = ast_str_buffer(buffer);
  470. cat = ast_config_get_current_category(cfg);
  471. while ((line = strsep(&stringp, "\r\n"))) {
  472. if (ast_strlen_zero(line)) {
  473. continue;
  474. }
  475. while ((pair = strsep(&line, "&"))) {
  476. key = strsep(&pair, "=");
  477. ast_uri_decode(key);
  478. if (pair) {
  479. ast_uri_decode(pair);
  480. }
  481. if (!strcasecmp(key, "category")) {
  482. category = S_OR(pair, "");
  483. } else if (!strcasecmp(key, "var_name")) {
  484. var_name = S_OR(pair, "");
  485. } else if (!strcasecmp(key, "var_val")) {
  486. var_val = S_OR(pair, "");
  487. } else if (!strcasecmp(key, "cat_metric")) {
  488. cat_metric = pair ? atoi(pair) : 0;
  489. }
  490. }
  491. if (!strcmp(var_name, "#include")) {
  492. if (!ast_config_internal_load(var_val, cfg, loader_flags, "", who_asked))
  493. return NULL;
  494. }
  495. if (!cat || strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
  496. if (!(cat = ast_category_new(category, "", 99999)))
  497. break;
  498. cur_cat = category;
  499. last_cat_metric = cat_metric;
  500. ast_category_append(cfg, cat);
  501. }
  502. ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
  503. }
  504. return cfg;
  505. }
  506. static struct ast_config_engine curl_engine = {
  507. .name = "curl",
  508. .load_func = config_curl,
  509. .realtime_func = realtime_curl,
  510. .realtime_multi_func = realtime_multi_curl,
  511. .store_func = store_curl,
  512. .destroy_func = destroy_curl,
  513. .update_func = update_curl,
  514. .update2_func = update2_curl,
  515. .require_func = require_curl,
  516. };
  517. static int reload_module(void)
  518. {
  519. struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
  520. struct ast_config *cfg;
  521. struct ast_variable *var;
  522. if (!(cfg = ast_config_load("res_curl.conf", flags))) {
  523. return 0;
  524. } else if (cfg == CONFIG_STATUS_FILEINVALID) {
  525. ast_log(LOG_WARNING, "res_curl.conf could not be parsed!\n");
  526. return 0;
  527. }
  528. if (!(var = ast_variable_browse(cfg, "globals")) && !(var = ast_variable_browse(cfg, "global")) && !(var = ast_variable_browse(cfg, "general"))) {
  529. ast_log(LOG_WARNING, "[globals] not found in res_curl.conf\n");
  530. ast_config_destroy(cfg);
  531. return 0;
  532. }
  533. for (; var; var = var->next) {
  534. if (strncmp(var->name, "CURLOPT(", 8)) {
  535. char name[256];
  536. snprintf(name, sizeof(name), "CURLOPT(%s)", var->name);
  537. pbx_builtin_setvar_helper(NULL, name, var->value);
  538. } else {
  539. pbx_builtin_setvar_helper(NULL, var->name, var->value);
  540. }
  541. }
  542. ast_config_destroy(cfg);
  543. return 0;
  544. }
  545. static int unload_module(void)
  546. {
  547. ast_config_engine_deregister(&curl_engine);
  548. ast_verb(1, "res_config_curl unloaded.\n");
  549. return 0;
  550. }
  551. static int load_module(void)
  552. {
  553. if (!ast_module_check("res_curl.so")) {
  554. if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) {
  555. ast_log(LOG_ERROR, "Cannot load res_curl, so res_config_curl cannot be loaded\n");
  556. return AST_MODULE_LOAD_DECLINE;
  557. }
  558. }
  559. if (!ast_module_check("func_curl.so")) {
  560. if (ast_load_resource("func_curl.so") != AST_MODULE_LOAD_SUCCESS) {
  561. ast_log(LOG_ERROR, "Cannot load func_curl, so res_config_curl cannot be loaded\n");
  562. return AST_MODULE_LOAD_DECLINE;
  563. }
  564. }
  565. reload_module();
  566. ast_config_engine_register(&curl_engine);
  567. ast_verb(1, "res_config_curl loaded.\n");
  568. return 0;
  569. }
  570. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Realtime Curl configuration",
  571. .load = load_module,
  572. .unload = unload_module,
  573. .reload = reload_module,
  574. .load_pri = AST_MODPRI_REALTIME_DRIVER,
  575. );