pbx_variables.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2016, CFWare, LLC
  5. *
  6. * Corey Farrell <git@cfware.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 PBX variables routines.
  21. *
  22. * \author Corey Farrell <git@cfware.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/_private.h"
  30. #include "asterisk/app.h"
  31. #include "asterisk/ast_expr.h"
  32. #include "asterisk/chanvars.h"
  33. #include "asterisk/cli.h"
  34. #include "asterisk/linkedlists.h"
  35. #include "asterisk/lock.h"
  36. #include "asterisk/module.h"
  37. #include "asterisk/paths.h"
  38. #include "asterisk/pbx.h"
  39. #include "asterisk/stasis_channels.h"
  40. #include "pbx_private.h"
  41. /*** DOCUMENTATION
  42. <application name="Set" language="en_US">
  43. <synopsis>
  44. Set channel variable or function value.
  45. </synopsis>
  46. <syntax argsep="=">
  47. <parameter name="name" required="true" />
  48. <parameter name="value" required="true" />
  49. </syntax>
  50. <description>
  51. <para>This function can be used to set the value of channel variables or dialplan functions.
  52. When setting variables, if the variable name is prefixed with <literal>_</literal>,
  53. the variable will be inherited into channels created from the current channel.
  54. If the variable name is prefixed with <literal>__</literal>, the variable will be
  55. inherited into channels created from the current channel and all children channels.</para>
  56. <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
  57. a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
  58. the behavior of this app changes, and strips surrounding quotes from the right hand side as
  59. it did previously in 1.4.
  60. The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
  61. were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
  62. protect separators and quotes in various database access strings has been greatly
  63. reduced by these changes.</para></note>
  64. </description>
  65. <see-also>
  66. <ref type="application">MSet</ref>
  67. <ref type="function">GLOBAL</ref>
  68. <ref type="function">SET</ref>
  69. <ref type="function">ENV</ref>
  70. </see-also>
  71. </application>
  72. <application name="MSet" language="en_US">
  73. <synopsis>
  74. Set channel variable(s) or function value(s).
  75. </synopsis>
  76. <syntax>
  77. <parameter name="set1" required="true" argsep="=">
  78. <argument name="name1" required="true" />
  79. <argument name="value1" required="true" />
  80. </parameter>
  81. <parameter name="set2" multiple="true" argsep="=">
  82. <argument name="name2" required="true" />
  83. <argument name="value2" required="true" />
  84. </parameter>
  85. </syntax>
  86. <description>
  87. <para>This function can be used to set the value of channel variables or dialplan functions.
  88. When setting variables, if the variable name is prefixed with <literal>_</literal>,
  89. the variable will be inherited into channels created from the current channel
  90. If the variable name is prefixed with <literal>__</literal>, the variable will be
  91. inherited into channels created from the current channel and all children channels.
  92. MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
  93. prone to doing things that you may not expect. For example, it strips surrounding
  94. double-quotes from the right-hand side (value). If you need to put a separator
  95. character (comma or vert-bar), you will need to escape them by inserting a backslash
  96. before them. Avoid its use if possible.</para>
  97. </description>
  98. <see-also>
  99. <ref type="application">Set</ref>
  100. </see-also>
  101. </application>
  102. ***/
  103. AST_RWLOCK_DEFINE_STATIC(globalslock);
  104. static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
  105. /*!
  106. * \brief extract offset:length from variable name.
  107. * \return 1 if there is a offset:length part, which is
  108. * trimmed off (values go into variables)
  109. */
  110. static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
  111. {
  112. int parens = 0;
  113. *offset = 0;
  114. *length = INT_MAX;
  115. *isfunc = 0;
  116. for (; *var; var++) {
  117. if (*var == '(') {
  118. (*isfunc)++;
  119. parens++;
  120. } else if (*var == ')') {
  121. parens--;
  122. } else if (*var == ':' && parens == 0) {
  123. *var++ = '\0';
  124. sscanf(var, "%30d:%30d", offset, length);
  125. return 1; /* offset:length valid */
  126. }
  127. }
  128. return 0;
  129. }
  130. /*!
  131. *\brief takes a substring. It is ok to call with value == workspace.
  132. * \param value
  133. * \param offset < 0 means start from the end of the string and set the beginning
  134. * to be that many characters back.
  135. * \param length is the length of the substring, a value less than 0 means to leave
  136. * that many off the end.
  137. * \param workspace
  138. * \param workspace_len
  139. * Always return a copy in workspace.
  140. */
  141. static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
  142. {
  143. char *ret = workspace;
  144. int lr; /* length of the input string after the copy */
  145. ast_copy_string(workspace, value, workspace_len); /* always make a copy */
  146. lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
  147. /* Quick check if no need to do anything */
  148. if (offset == 0 && length >= lr) /* take the whole string */
  149. return ret;
  150. if (offset < 0) { /* translate negative offset into positive ones */
  151. offset = lr + offset;
  152. if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
  153. offset = 0;
  154. }
  155. /* too large offset result in empty string so we know what to return */
  156. if (offset >= lr)
  157. return ret + lr; /* the final '\0' */
  158. ret += offset; /* move to the start position */
  159. if (length >= 0 && length < lr - offset) /* truncate if necessary */
  160. ret[length] = '\0';
  161. else if (length < 0) {
  162. if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
  163. ret[lr + length - offset] = '\0';
  164. else
  165. ret[0] = '\0';
  166. }
  167. return ret;
  168. }
  169. static const char *ast_str_substring(struct ast_str *value, int offset, int length)
  170. {
  171. int lr; /* length of the input string after the copy */
  172. lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
  173. /* Quick check if no need to do anything */
  174. if (offset == 0 && length >= lr) /* take the whole string */
  175. return ast_str_buffer(value);
  176. if (offset < 0) { /* translate negative offset into positive ones */
  177. offset = lr + offset;
  178. if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
  179. offset = 0;
  180. }
  181. /* too large offset result in empty string so we know what to return */
  182. if (offset >= lr) {
  183. ast_str_reset(value);
  184. return ast_str_buffer(value);
  185. }
  186. if (offset > 0) {
  187. /* Go ahead and chop off the beginning */
  188. memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
  189. lr -= offset;
  190. }
  191. if (length >= 0 && length < lr) { /* truncate if necessary */
  192. char *tmp = ast_str_buffer(value);
  193. tmp[length] = '\0';
  194. ast_str_update(value);
  195. } else if (length < 0) {
  196. if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
  197. char *tmp = ast_str_buffer(value);
  198. tmp[lr + length] = '\0';
  199. ast_str_update(value);
  200. } else {
  201. ast_str_reset(value);
  202. }
  203. } else {
  204. /* Nothing to do, but update the buffer length */
  205. ast_str_update(value);
  206. }
  207. return ast_str_buffer(value);
  208. }
  209. /*! \brief Support for Asterisk built-in variables in the dialplan
  210. \note See also
  211. - \ref AstVar Channel variables
  212. - \ref AstCauses The HANGUPCAUSE variable
  213. */
  214. void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
  215. {
  216. struct ast_str *str = ast_str_create(16);
  217. const char *cret;
  218. cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
  219. ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
  220. *ret = cret ? workspace : NULL;
  221. ast_free(str);
  222. }
  223. const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
  224. {
  225. const char not_found = '\0';
  226. char *tmpvar;
  227. const char *ret;
  228. const char *s; /* the result */
  229. int offset, length;
  230. int i, need_substring;
  231. struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
  232. char workspace[20];
  233. if (c) {
  234. ast_channel_lock(c);
  235. places[0] = ast_channel_varshead(c);
  236. }
  237. /*
  238. * Make a copy of var because parse_variable_name() modifies the string.
  239. * Then if called directly, we might need to run substring() on the result;
  240. * remember this for later in 'need_substring', 'offset' and 'length'
  241. */
  242. tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
  243. need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
  244. /*
  245. * Look first into predefined variables, then into variable lists.
  246. * Variable 's' points to the result, according to the following rules:
  247. * s == &not_found (set at the beginning) means that we did not find a
  248. * matching variable and need to look into more places.
  249. * If s != &not_found, s is a valid result string as follows:
  250. * s = NULL if the variable does not have a value;
  251. * you typically do this when looking for an unset predefined variable.
  252. * s = workspace if the result has been assembled there;
  253. * typically done when the result is built e.g. with an snprintf(),
  254. * so we don't need to do an additional copy.
  255. * s != workspace in case we have a string, that needs to be copied
  256. * (the ast_copy_string is done once for all at the end).
  257. * Typically done when the result is already available in some string.
  258. */
  259. s = &not_found; /* default value */
  260. if (c) { /* This group requires a valid channel */
  261. /* Names with common parts are looked up a piece at a time using strncmp. */
  262. if (!strncmp(var, "CALL", 4)) {
  263. if (!strncmp(var + 4, "ING", 3)) {
  264. if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
  265. ast_str_set(str, maxlen, "%d",
  266. ast_party_id_presentation(&ast_channel_caller(c)->id));
  267. s = ast_str_buffer(*str);
  268. } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
  269. ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
  270. s = ast_str_buffer(*str);
  271. } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
  272. ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
  273. s = ast_str_buffer(*str);
  274. } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
  275. ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
  276. s = ast_str_buffer(*str);
  277. }
  278. }
  279. } else if (!strcmp(var, "HINT")) {
  280. s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
  281. } else if (!strcmp(var, "HINTNAME")) {
  282. s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
  283. } else if (!strcmp(var, "EXTEN")) {
  284. s = ast_channel_exten(c);
  285. } else if (!strcmp(var, "CONTEXT")) {
  286. s = ast_channel_context(c);
  287. } else if (!strcmp(var, "PRIORITY")) {
  288. ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
  289. s = ast_str_buffer(*str);
  290. } else if (!strcmp(var, "CHANNEL")) {
  291. s = ast_channel_name(c);
  292. } else if (!strcmp(var, "UNIQUEID")) {
  293. s = ast_channel_uniqueid(c);
  294. } else if (!strcmp(var, "HANGUPCAUSE")) {
  295. ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
  296. s = ast_str_buffer(*str);
  297. }
  298. }
  299. if (s == &not_found) { /* look for more */
  300. if (!strcmp(var, "EPOCH")) {
  301. ast_str_set(str, maxlen, "%d", (int) time(NULL));
  302. s = ast_str_buffer(*str);
  303. } else if (!strcmp(var, "SYSTEMNAME")) {
  304. s = ast_config_AST_SYSTEM_NAME;
  305. } else if (!strcmp(var, "ASTETCDIR")) {
  306. s = ast_config_AST_CONFIG_DIR;
  307. } else if (!strcmp(var, "ASTMODDIR")) {
  308. s = ast_config_AST_MODULE_DIR;
  309. } else if (!strcmp(var, "ASTVARLIBDIR")) {
  310. s = ast_config_AST_VAR_DIR;
  311. } else if (!strcmp(var, "ASTDBDIR")) {
  312. s = ast_config_AST_DB;
  313. } else if (!strcmp(var, "ASTKEYDIR")) {
  314. s = ast_config_AST_KEY_DIR;
  315. } else if (!strcmp(var, "ASTDATADIR")) {
  316. s = ast_config_AST_DATA_DIR;
  317. } else if (!strcmp(var, "ASTAGIDIR")) {
  318. s = ast_config_AST_AGI_DIR;
  319. } else if (!strcmp(var, "ASTSPOOLDIR")) {
  320. s = ast_config_AST_SPOOL_DIR;
  321. } else if (!strcmp(var, "ASTRUNDIR")) {
  322. s = ast_config_AST_RUN_DIR;
  323. } else if (!strcmp(var, "ASTLOGDIR")) {
  324. s = ast_config_AST_LOG_DIR;
  325. } else if (!strcmp(var, "ENTITYID")) {
  326. ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
  327. s = workspace;
  328. }
  329. }
  330. /* if not found, look into chanvars or global vars */
  331. for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
  332. struct ast_var_t *variables;
  333. if (!places[i])
  334. continue;
  335. if (places[i] == &globals)
  336. ast_rwlock_rdlock(&globalslock);
  337. AST_LIST_TRAVERSE(places[i], variables, entries) {
  338. if (!strcmp(ast_var_name(variables), var)) {
  339. s = ast_var_value(variables);
  340. break;
  341. }
  342. }
  343. if (places[i] == &globals)
  344. ast_rwlock_unlock(&globalslock);
  345. }
  346. if (s == &not_found || s == NULL) {
  347. ast_debug(5, "Result of '%s' is NULL\n", var);
  348. ret = NULL;
  349. } else {
  350. ast_debug(5, "Result of '%s' is '%s'\n", var, s);
  351. if (s != ast_str_buffer(*str)) {
  352. ast_str_set(str, maxlen, "%s", s);
  353. }
  354. ret = ast_str_buffer(*str);
  355. if (need_substring) {
  356. ret = ast_str_substring(*str, offset, length);
  357. ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
  358. }
  359. }
  360. if (c) {
  361. ast_channel_unlock(c);
  362. }
  363. return ret;
  364. }
  365. void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
  366. {
  367. /* Substitutes variables into buf, based on string templ */
  368. const char *whereweare;
  369. struct ast_str *substr1 = ast_str_create(16);
  370. struct ast_str *substr2 = NULL;
  371. struct ast_str *substr3 = ast_str_create(16);
  372. ast_str_reset(*buf);
  373. if (!substr1 || !substr3) {
  374. if (used) {
  375. *used = ast_str_strlen(*buf);
  376. }
  377. ast_free(substr1);
  378. ast_free(substr3);
  379. return;
  380. }
  381. whereweare = templ;
  382. while (!ast_strlen_zero(whereweare)) {
  383. const char *nextvar = NULL;
  384. const char *nextexp = NULL;
  385. const char *nextthing;
  386. const char *vars;
  387. const char *vare;
  388. char *finalvars;
  389. int pos;
  390. int brackets;
  391. int needsub;
  392. int len;
  393. /* reset our buffer */
  394. ast_str_reset(substr3);
  395. /* Determine how much simply needs to be copied to the output buf. */
  396. nextthing = strchr(whereweare, '$');
  397. if (nextthing) {
  398. pos = nextthing - whereweare;
  399. switch (nextthing[1]) {
  400. case '{':
  401. /* Variable substitution */
  402. nextvar = nextthing;
  403. break;
  404. case '[':
  405. /* Expression substitution */
  406. nextexp = nextthing;
  407. break;
  408. default:
  409. /* '$' is not part of a substitution so include it too. */
  410. ++pos;
  411. break;
  412. }
  413. } else {
  414. /* We're copying the whole remaining string */
  415. pos = strlen(whereweare);
  416. }
  417. if (pos) {
  418. /* Copy that many bytes */
  419. ast_str_append_substr(buf, maxlen, whereweare, pos);
  420. whereweare += pos;
  421. }
  422. if (nextvar) {
  423. int offset;
  424. int offset2;
  425. int isfunction;
  426. int res;
  427. /* We have a variable. Find the start and end, and determine
  428. if we are going to have to recursively call ourselves on the
  429. contents */
  430. vars = vare = nextvar + 2;
  431. brackets = 1;
  432. needsub = 0;
  433. /* Find the end of it */
  434. while (brackets && *vare) {
  435. if ((vare[0] == '$') && (vare[1] == '{')) {
  436. needsub++;
  437. brackets++;
  438. vare++;
  439. } else if (vare[0] == '{') {
  440. brackets++;
  441. } else if (vare[0] == '}') {
  442. brackets--;
  443. } else if ((vare[0] == '$') && (vare[1] == '[')) {
  444. needsub++;
  445. vare++;
  446. }
  447. vare++;
  448. }
  449. len = vare - vars;
  450. if (brackets) {
  451. ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
  452. } else {
  453. /* Don't count the closing '}' in the length. */
  454. --len;
  455. }
  456. /* Skip totally over variable string */
  457. whereweare = vare;
  458. /* Store variable name expression to lookup. */
  459. ast_str_set_substr(&substr1, 0, vars, len);
  460. ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
  461. /* Substitute if necessary */
  462. if (needsub) {
  463. if (!substr2) {
  464. substr2 = ast_str_create(16);
  465. if (!substr2) {
  466. continue;
  467. }
  468. }
  469. ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
  470. finalvars = ast_str_buffer(substr2);
  471. } else {
  472. finalvars = ast_str_buffer(substr1);
  473. }
  474. parse_variable_name(finalvars, &offset, &offset2, &isfunction);
  475. if (isfunction) {
  476. /* Evaluate function */
  477. if (c || !headp) {
  478. res = ast_func_read2(c, finalvars, &substr3, 0);
  479. } else {
  480. struct varshead old;
  481. struct ast_channel *bogus;
  482. bogus = ast_dummy_channel_alloc();
  483. if (bogus) {
  484. old = *ast_channel_varshead(bogus);
  485. *ast_channel_varshead(bogus) = *headp;
  486. res = ast_func_read2(bogus, finalvars, &substr3, 0);
  487. /* Don't deallocate the varshead that was passed in */
  488. *ast_channel_varshead(bogus) = old;
  489. ast_channel_unref(bogus);
  490. } else {
  491. ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
  492. res = -1;
  493. }
  494. }
  495. ast_debug(2, "Function %s result is '%s'\n",
  496. finalvars, res ? "" : ast_str_buffer(substr3));
  497. } else {
  498. /* Retrieve variable value */
  499. ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
  500. res = 0;
  501. }
  502. if (!res) {
  503. ast_str_substring(substr3, offset, offset2);
  504. ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
  505. }
  506. } else if (nextexp) {
  507. /* We have an expression. Find the start and end, and determine
  508. if we are going to have to recursively call ourselves on the
  509. contents */
  510. vars = vare = nextexp + 2;
  511. brackets = 1;
  512. needsub = 0;
  513. /* Find the end of it */
  514. while (brackets && *vare) {
  515. if ((vare[0] == '$') && (vare[1] == '[')) {
  516. needsub++;
  517. brackets++;
  518. vare++;
  519. } else if (vare[0] == '[') {
  520. brackets++;
  521. } else if (vare[0] == ']') {
  522. brackets--;
  523. } else if ((vare[0] == '$') && (vare[1] == '{')) {
  524. needsub++;
  525. vare++;
  526. }
  527. vare++;
  528. }
  529. len = vare - vars;
  530. if (brackets) {
  531. ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
  532. } else {
  533. /* Don't count the closing ']' in the length. */
  534. --len;
  535. }
  536. /* Skip totally over expression */
  537. whereweare = vare;
  538. /* Store expression to evaluate. */
  539. ast_str_set_substr(&substr1, 0, vars, len);
  540. /* Substitute if necessary */
  541. if (needsub) {
  542. if (!substr2) {
  543. substr2 = ast_str_create(16);
  544. if (!substr2) {
  545. continue;
  546. }
  547. }
  548. ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
  549. finalvars = ast_str_buffer(substr2);
  550. } else {
  551. finalvars = ast_str_buffer(substr1);
  552. }
  553. if (ast_str_expr(&substr3, 0, c, finalvars)) {
  554. ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
  555. }
  556. ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
  557. }
  558. }
  559. if (used) {
  560. *used = ast_str_strlen(*buf);
  561. }
  562. ast_free(substr1);
  563. ast_free(substr2);
  564. ast_free(substr3);
  565. }
  566. void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
  567. {
  568. ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
  569. }
  570. void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
  571. {
  572. ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
  573. }
  574. void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
  575. {
  576. /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
  577. const char *whereweare;
  578. const char *orig_cp2 = cp2;
  579. char *workspace = NULL;
  580. char *ltmp = NULL;
  581. char *var = NULL;
  582. *cp2 = 0; /* just in case nothing ends up there */
  583. whereweare = cp1;
  584. while (!ast_strlen_zero(whereweare) && count) {
  585. char *nextvar = NULL;
  586. char *nextexp = NULL;
  587. char *nextthing;
  588. char *vars;
  589. char *vare;
  590. int length;
  591. int pos;
  592. int brackets;
  593. int needsub;
  594. int len;
  595. /* Determine how much simply needs to be copied to the output buf. */
  596. nextthing = strchr(whereweare, '$');
  597. if (nextthing) {
  598. pos = nextthing - whereweare;
  599. switch (nextthing[1]) {
  600. case '{':
  601. /* Variable substitution */
  602. nextvar = nextthing;
  603. break;
  604. case '[':
  605. /* Expression substitution */
  606. nextexp = nextthing;
  607. break;
  608. default:
  609. /* '$' is not part of a substitution so include it too. */
  610. ++pos;
  611. break;
  612. }
  613. } else {
  614. /* We're copying the whole remaining string */
  615. pos = strlen(whereweare);
  616. }
  617. if (pos) {
  618. /* Can't copy more than 'count' bytes */
  619. if (pos > count)
  620. pos = count;
  621. /* Copy that many bytes */
  622. memcpy(cp2, whereweare, pos);
  623. count -= pos;
  624. cp2 += pos;
  625. whereweare += pos;
  626. *cp2 = 0;
  627. }
  628. if (nextvar) {
  629. int offset;
  630. int offset2;
  631. int isfunction;
  632. char *cp4;
  633. /* We have a variable. Find the start and end, and determine
  634. if we are going to have to recursively call ourselves on the
  635. contents */
  636. vars = vare = nextvar + 2;
  637. brackets = 1;
  638. needsub = 0;
  639. /* Find the end of it */
  640. while (brackets && *vare) {
  641. if ((vare[0] == '$') && (vare[1] == '{')) {
  642. needsub++;
  643. brackets++;
  644. vare++;
  645. } else if (vare[0] == '{') {
  646. brackets++;
  647. } else if (vare[0] == '}') {
  648. brackets--;
  649. } else if ((vare[0] == '$') && (vare[1] == '[')) {
  650. needsub++;
  651. vare++;
  652. }
  653. vare++;
  654. }
  655. len = vare - vars;
  656. if (brackets) {
  657. ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
  658. } else {
  659. /* Don't count the closing '}' in the length. */
  660. --len;
  661. }
  662. /* Skip totally over variable string */
  663. whereweare = vare;
  664. if (!var)
  665. var = ast_alloca(VAR_BUF_SIZE);
  666. /* Store variable name expression to lookup (and truncate). */
  667. ast_copy_string(var, vars, len + 1);
  668. /* Substitute if necessary */
  669. if (needsub) {
  670. if (!ltmp) {
  671. ltmp = ast_alloca(VAR_BUF_SIZE);
  672. }
  673. pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
  674. vars = ltmp;
  675. } else {
  676. vars = var;
  677. }
  678. if (!workspace)
  679. workspace = ast_alloca(VAR_BUF_SIZE);
  680. workspace[0] = '\0';
  681. parse_variable_name(vars, &offset, &offset2, &isfunction);
  682. if (isfunction) {
  683. /* Evaluate function */
  684. if (c || !headp)
  685. cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
  686. else {
  687. struct varshead old;
  688. struct ast_channel *bogus;
  689. bogus = ast_dummy_channel_alloc();
  690. if (bogus) {
  691. old = *ast_channel_varshead(bogus);
  692. *ast_channel_varshead(bogus) = *headp;
  693. cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
  694. /* Don't deallocate the varshead that was passed in */
  695. *ast_channel_varshead(bogus) = old;
  696. ast_channel_unref(bogus);
  697. } else {
  698. ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
  699. cp4 = NULL;
  700. }
  701. }
  702. ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
  703. } else {
  704. /* Retrieve variable value */
  705. pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
  706. }
  707. if (cp4) {
  708. cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
  709. length = strlen(cp4);
  710. if (length > count)
  711. length = count;
  712. memcpy(cp2, cp4, length);
  713. count -= length;
  714. cp2 += length;
  715. *cp2 = 0;
  716. }
  717. } else if (nextexp) {
  718. /* We have an expression. Find the start and end, and determine
  719. if we are going to have to recursively call ourselves on the
  720. contents */
  721. vars = vare = nextexp + 2;
  722. brackets = 1;
  723. needsub = 0;
  724. /* Find the end of it */
  725. while (brackets && *vare) {
  726. if ((vare[0] == '$') && (vare[1] == '[')) {
  727. needsub++;
  728. brackets++;
  729. vare++;
  730. } else if (vare[0] == '[') {
  731. brackets++;
  732. } else if (vare[0] == ']') {
  733. brackets--;
  734. } else if ((vare[0] == '$') && (vare[1] == '{')) {
  735. needsub++;
  736. vare++;
  737. }
  738. vare++;
  739. }
  740. len = vare - vars;
  741. if (brackets) {
  742. ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
  743. } else {
  744. /* Don't count the closing ']' in the length. */
  745. --len;
  746. }
  747. /* Skip totally over expression */
  748. whereweare = vare;
  749. if (!var)
  750. var = ast_alloca(VAR_BUF_SIZE);
  751. /* Store expression to evaluate (and truncate). */
  752. ast_copy_string(var, vars, len + 1);
  753. /* Substitute if necessary */
  754. if (needsub) {
  755. if (!ltmp) {
  756. ltmp = ast_alloca(VAR_BUF_SIZE);
  757. }
  758. pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, NULL);
  759. vars = ltmp;
  760. } else {
  761. vars = var;
  762. }
  763. length = ast_expr(vars, cp2, count, c);
  764. if (length) {
  765. ast_debug(1, "Expression result is '%s'\n", cp2);
  766. count -= length;
  767. cp2 += length;
  768. *cp2 = 0;
  769. }
  770. }
  771. }
  772. if (used) {
  773. *used = cp2 - orig_cp2;
  774. }
  775. }
  776. void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
  777. {
  778. pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, NULL);
  779. }
  780. void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
  781. {
  782. pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
  783. }
  784. /*! \brief CLI support for listing global variables in a parseable way */
  785. static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  786. {
  787. int i = 0;
  788. struct ast_var_t *newvariable;
  789. switch (cmd) {
  790. case CLI_INIT:
  791. e->command = "dialplan show globals";
  792. e->usage =
  793. "Usage: dialplan show globals\n"
  794. " List current global dialplan variables and their values\n";
  795. return NULL;
  796. case CLI_GENERATE:
  797. return NULL;
  798. }
  799. ast_rwlock_rdlock(&globalslock);
  800. AST_LIST_TRAVERSE (&globals, newvariable, entries) {
  801. i++;
  802. ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
  803. }
  804. ast_rwlock_unlock(&globalslock);
  805. ast_cli(a->fd, "\n -- %d variable(s)\n", i);
  806. return CLI_SUCCESS;
  807. }
  808. /*! \brief CLI support for listing chanvar's variables in a parseable way */
  809. static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  810. {
  811. struct ast_channel *chan;
  812. struct ast_var_t *var;
  813. switch (cmd) {
  814. case CLI_INIT:
  815. e->command = "dialplan show chanvar";
  816. e->usage =
  817. "Usage: dialplan show chanvar <channel>\n"
  818. " List current channel variables and their values\n";
  819. return NULL;
  820. case CLI_GENERATE:
  821. return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
  822. }
  823. if (a->argc != e->args + 1) {
  824. return CLI_SHOWUSAGE;
  825. }
  826. chan = ast_channel_get_by_name(a->argv[e->args]);
  827. if (!chan) {
  828. ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
  829. return CLI_FAILURE;
  830. }
  831. ast_channel_lock(chan);
  832. AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
  833. ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
  834. }
  835. ast_channel_unlock(chan);
  836. ast_channel_unref(chan);
  837. return CLI_SUCCESS;
  838. }
  839. static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  840. {
  841. switch (cmd) {
  842. case CLI_INIT:
  843. e->command = "dialplan set global";
  844. e->usage =
  845. "Usage: dialplan set global <name> <value>\n"
  846. " Set global dialplan variable <name> to <value>\n";
  847. return NULL;
  848. case CLI_GENERATE:
  849. return NULL;
  850. }
  851. if (a->argc != e->args + 2)
  852. return CLI_SHOWUSAGE;
  853. pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
  854. ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
  855. return CLI_SUCCESS;
  856. }
  857. static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  858. {
  859. struct ast_channel *chan;
  860. const char *chan_name, *var_name, *var_value;
  861. switch (cmd) {
  862. case CLI_INIT:
  863. e->command = "dialplan set chanvar";
  864. e->usage =
  865. "Usage: dialplan set chanvar <channel> <varname> <value>\n"
  866. " Set channel variable <varname> to <value>\n";
  867. return NULL;
  868. case CLI_GENERATE:
  869. return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
  870. }
  871. if (a->argc != e->args + 3)
  872. return CLI_SHOWUSAGE;
  873. chan_name = a->argv[e->args];
  874. var_name = a->argv[e->args + 1];
  875. var_value = a->argv[e->args + 2];
  876. if (!(chan = ast_channel_get_by_name(chan_name))) {
  877. ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
  878. return CLI_FAILURE;
  879. }
  880. pbx_builtin_setvar_helper(chan, var_name, var_value);
  881. chan = ast_channel_unref(chan);
  882. ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
  883. return CLI_SUCCESS;
  884. }
  885. int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
  886. {
  887. struct ast_var_t *variables;
  888. const char *var, *val;
  889. int total = 0;
  890. if (!chan)
  891. return 0;
  892. ast_str_reset(*buf);
  893. ast_channel_lock(chan);
  894. AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
  895. if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
  896. /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
  897. ) {
  898. if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
  899. ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
  900. break;
  901. } else
  902. total++;
  903. } else
  904. break;
  905. }
  906. ast_channel_unlock(chan);
  907. return total;
  908. }
  909. const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
  910. {
  911. struct ast_var_t *variables;
  912. const char *ret = NULL;
  913. int i;
  914. struct varshead *places[2] = { NULL, &globals };
  915. if (!name)
  916. return NULL;
  917. if (chan) {
  918. ast_channel_lock(chan);
  919. places[0] = ast_channel_varshead(chan);
  920. }
  921. for (i = 0; i < 2; i++) {
  922. if (!places[i])
  923. continue;
  924. if (places[i] == &globals)
  925. ast_rwlock_rdlock(&globalslock);
  926. AST_LIST_TRAVERSE(places[i], variables, entries) {
  927. if (!strcmp(name, ast_var_name(variables))) {
  928. ret = ast_var_value(variables);
  929. break;
  930. }
  931. }
  932. if (places[i] == &globals)
  933. ast_rwlock_unlock(&globalslock);
  934. if (ret)
  935. break;
  936. }
  937. if (chan)
  938. ast_channel_unlock(chan);
  939. return ret;
  940. }
  941. void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
  942. {
  943. struct ast_var_t *newvariable;
  944. struct varshead *headp;
  945. if (name[strlen(name)-1] == ')') {
  946. char *function = ast_strdupa(name);
  947. ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
  948. ast_func_write(chan, function, value);
  949. return;
  950. }
  951. if (chan) {
  952. ast_channel_lock(chan);
  953. headp = ast_channel_varshead(chan);
  954. } else {
  955. ast_rwlock_wrlock(&globalslock);
  956. headp = &globals;
  957. }
  958. if (value && (newvariable = ast_var_assign(name, value))) {
  959. if (headp == &globals)
  960. ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
  961. AST_LIST_INSERT_HEAD(headp, newvariable, entries);
  962. }
  963. if (chan)
  964. ast_channel_unlock(chan);
  965. else
  966. ast_rwlock_unlock(&globalslock);
  967. }
  968. int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
  969. {
  970. struct ast_var_t *newvariable;
  971. struct varshead *headp;
  972. const char *nametail = name;
  973. /*! True if the old value was not an empty string. */
  974. int old_value_existed = 0;
  975. if (name[strlen(name) - 1] == ')') {
  976. char *function = ast_strdupa(name);
  977. return ast_func_write(chan, function, value);
  978. }
  979. if (chan) {
  980. ast_channel_lock(chan);
  981. headp = ast_channel_varshead(chan);
  982. } else {
  983. ast_rwlock_wrlock(&globalslock);
  984. headp = &globals;
  985. }
  986. /* For comparison purposes, we have to strip leading underscores */
  987. if (*nametail == '_') {
  988. nametail++;
  989. if (*nametail == '_')
  990. nametail++;
  991. }
  992. AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
  993. if (strcmp(ast_var_name(newvariable), nametail) == 0) {
  994. /* there is already such a variable, delete it */
  995. AST_LIST_REMOVE_CURRENT(entries);
  996. old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
  997. ast_var_delete(newvariable);
  998. break;
  999. }
  1000. }
  1001. AST_LIST_TRAVERSE_SAFE_END;
  1002. if (value && (newvariable = ast_var_assign(name, value))) {
  1003. if (headp == &globals) {
  1004. ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
  1005. }
  1006. AST_LIST_INSERT_HEAD(headp, newvariable, entries);
  1007. ast_channel_publish_varset(chan, name, value);
  1008. } else if (old_value_existed) {
  1009. /* We just deleted a non-empty dialplan variable. */
  1010. ast_channel_publish_varset(chan, name, "");
  1011. }
  1012. if (chan)
  1013. ast_channel_unlock(chan);
  1014. else
  1015. ast_rwlock_unlock(&globalslock);
  1016. return 0;
  1017. }
  1018. int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
  1019. {
  1020. char *name, *value, *mydata;
  1021. if (ast_strlen_zero(data)) {
  1022. ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
  1023. return 0;
  1024. }
  1025. mydata = ast_strdupa(data);
  1026. name = strsep(&mydata, "=");
  1027. value = mydata;
  1028. if (!value) {
  1029. ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
  1030. return 0;
  1031. }
  1032. if (strchr(name, ' ')) {
  1033. ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
  1034. }
  1035. pbx_builtin_setvar_helper(chan, name, value);
  1036. return 0;
  1037. }
  1038. int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
  1039. {
  1040. char *data;
  1041. int x;
  1042. AST_DECLARE_APP_ARGS(args,
  1043. AST_APP_ARG(pair)[24];
  1044. );
  1045. AST_DECLARE_APP_ARGS(pair,
  1046. AST_APP_ARG(name);
  1047. AST_APP_ARG(value);
  1048. );
  1049. if (ast_strlen_zero(vdata)) {
  1050. ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
  1051. return 0;
  1052. }
  1053. data = ast_strdupa(vdata);
  1054. AST_STANDARD_APP_ARGS(args, data);
  1055. for (x = 0; x < args.argc; x++) {
  1056. AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
  1057. if (pair.argc == 2) {
  1058. pbx_builtin_setvar_helper(chan, pair.name, pair.value);
  1059. if (strchr(pair.name, ' '))
  1060. ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
  1061. } else if (!chan) {
  1062. ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
  1063. } else {
  1064. ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
  1065. }
  1066. }
  1067. return 0;
  1068. }
  1069. void pbx_builtin_clear_globals(void)
  1070. {
  1071. struct ast_var_t *vardata;
  1072. ast_rwlock_wrlock(&globalslock);
  1073. while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
  1074. ast_var_delete(vardata);
  1075. ast_rwlock_unlock(&globalslock);
  1076. }
  1077. static struct ast_cli_entry vars_cli[] = {
  1078. AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
  1079. AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
  1080. AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
  1081. AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
  1082. };
  1083. static void unload_pbx_variables(void)
  1084. {
  1085. ast_cli_unregister_multiple(vars_cli, ARRAY_LEN(vars_cli));
  1086. ast_unregister_application("Set");
  1087. ast_unregister_application("MSet");
  1088. pbx_builtin_clear_globals();
  1089. }
  1090. int load_pbx_variables(void)
  1091. {
  1092. int res = 0;
  1093. res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));
  1094. res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
  1095. res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
  1096. ast_register_cleanup(unload_pbx_variables);
  1097. return res;
  1098. }