1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "zbxserver.h"
22 #include "evalfunc.h"
23 #include "db.h"
24 #include "log.h"
25 #include "zbxalgo.h"
26 #include "valuecache.h"
27 #include "macrofunc.h"
28 #include "zbxregexp.h"
29 #ifdef HAVE_LIBXML2
30 #	include <libxml/parser.h>
31 #	include <libxml/tree.h>
32 #	include <libxml/xpath.h>
33 #	include <libxml/xmlerror.h>
34 
35 typedef struct
36 {
37 	char	*buf;
38 	size_t	len;
39 }
40 zbx_libxml_error_t;
41 #endif
42 
43 /* The following definitions are used to identify the request field */
44 /* for various value getters grouped by their scope:                */
45 
46 /* DBget_item_value(), get_interface_value() */
47 #define ZBX_REQUEST_HOST_IP		1
48 #define ZBX_REQUEST_HOST_DNS		2
49 #define ZBX_REQUEST_HOST_CONN		3
50 #define ZBX_REQUEST_HOST_PORT		4
51 
52 /* DBget_item_value() */
53 #define ZBX_REQUEST_HOST_ID		101
54 #define ZBX_REQUEST_HOST_HOST		102
55 #define ZBX_REQUEST_HOST_NAME		103
56 #define ZBX_REQUEST_HOST_DESCRIPTION	104
57 #define ZBX_REQUEST_ITEM_ID		105
58 #define ZBX_REQUEST_ITEM_NAME		106
59 #define ZBX_REQUEST_ITEM_NAME_ORIG	107
60 #define ZBX_REQUEST_ITEM_KEY		108
61 #define ZBX_REQUEST_ITEM_KEY_ORIG	109
62 #define ZBX_REQUEST_ITEM_DESCRIPTION	110
63 #define ZBX_REQUEST_PROXY_NAME		111
64 #define ZBX_REQUEST_PROXY_DESCRIPTION	112
65 
66 /* DBget_history_log_value() */
67 #define ZBX_REQUEST_ITEM_LOG_DATE	201
68 #define ZBX_REQUEST_ITEM_LOG_TIME	202
69 #define ZBX_REQUEST_ITEM_LOG_AGE	203
70 #define ZBX_REQUEST_ITEM_LOG_SOURCE	204
71 #define ZBX_REQUEST_ITEM_LOG_SEVERITY	205
72 #define ZBX_REQUEST_ITEM_LOG_NSEVERITY	206
73 #define ZBX_REQUEST_ITEM_LOG_EVENTID	207
74 
75 /******************************************************************************
76  *                                                                            *
77  * Function: get_N_functionid                                                 *
78  *                                                                            *
79  * Parameters: expression   - [IN] null terminated trigger expression         *
80  *                            '{11}=1 & {2346734}>5'                          *
81  *             N_functionid - [IN] number of function in trigger expression   *
82  *             functionid   - [OUT] ID of an N-th function in expression      *
83  *             end          - [OUT] a pointer to text following the extracted *
84  *                            function id (can be NULL)                       *
85  *                                                                            *
86  ******************************************************************************/
get_N_functionid(const char * expression,int N_functionid,zbx_uint64_t * functionid,const char ** end)87 int	get_N_functionid(const char *expression, int N_functionid, zbx_uint64_t *functionid, const char **end)
88 {
89 	enum state_t {NORMAL, ID}	state = NORMAL;
90 	int				num = 0, ret = FAIL;
91 	const char			*c, *p_functionid = NULL;
92 
93 	for (c = expression; '\0' != *c; c++)
94 	{
95 		if ('{' == *c)
96 		{
97 			/* skip user macros */
98 			if ('$' == c[1])
99 			{
100 				int	macro_r, context_l, context_r;
101 
102 				if (SUCCEED == zbx_user_macro_parse(c, &macro_r, &context_l, &context_r))
103 					c += macro_r;
104 				else
105 					c++;
106 
107 				continue;
108 			}
109 
110 			state = ID;
111 			p_functionid = c + 1;
112 		}
113 		else if ('}' == *c && ID == state && NULL != p_functionid)
114 		{
115 			if (SUCCEED == is_uint64_n(p_functionid, c - p_functionid, functionid))
116 			{
117 				if (++num == N_functionid)
118 				{
119 					if (NULL != end)
120 						*end = c + 1;
121 
122 					ret = SUCCEED;
123 					break;
124 				}
125 			}
126 
127 			state = NORMAL;
128 		}
129 	}
130 
131 	return ret;
132 }
133 
134 /******************************************************************************
135  *                                                                            *
136  * Function: get_functionids                                                  *
137  *                                                                            *
138  * Purpose: get identifiers of the functions used in expression               *
139  *                                                                            *
140  * Parameters: functionids - [OUT] the resulting vector of function ids       *
141  *             expression  - [IN] null terminated trigger expression          *
142  *                           '{11}=1 & {2346734}>5'                           *
143  *                                                                            *
144  ******************************************************************************/
get_functionids(zbx_vector_uint64_t * functionids,const char * expression)145 void	get_functionids(zbx_vector_uint64_t *functionids, const char *expression)
146 {
147 	zbx_token_t	token;
148 	int		pos = 0;
149 	zbx_uint64_t	functionid;
150 
151 	if ('\0' == *expression)
152 		return;
153 
154 	for (; SUCCEED == zbx_token_find(expression, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
155 	{
156 		switch (token.type)
157 		{
158 			case ZBX_TOKEN_OBJECTID:
159 				is_uint64_n(expression + token.loc.l + 1, token.loc.r - token.loc.l - 1,
160 						&functionid);
161 				zbx_vector_uint64_append(functionids, functionid);
162 				ZBX_FALLTHROUGH;
163 			case ZBX_TOKEN_USER_MACRO:
164 			case ZBX_TOKEN_SIMPLE_MACRO:
165 			case ZBX_TOKEN_MACRO:
166 				pos = token.loc.r;
167 				break;
168 		}
169 	}
170 
171 	zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
172 	zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
173 }
174 
175 /******************************************************************************
176  *                                                                            *
177  * Function: get_N_itemid                                                     *
178  *                                                                            *
179  * Parameters: expression   - [IN] null terminated trigger expression         *
180  *                            '{11}=1 & {2346734}>5'                          *
181  *             N_functionid - [IN] number of function in trigger expression   *
182  *             itemid       - [OUT] ID of an item of N-th function in         *
183  *                            expression                                      *
184  *                                                                            *
185  ******************************************************************************/
get_N_itemid(const char * expression,int N_functionid,zbx_uint64_t * itemid)186 static int	get_N_itemid(const char *expression, int N_functionid, zbx_uint64_t *itemid)
187 {
188 	const char	*__function_name = "get_N_itemid";
189 
190 	zbx_uint64_t	functionid;
191 	DC_FUNCTION	function;
192 	int		errcode, ret = FAIL;
193 
194 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s' N_functionid:%d",
195 			__function_name, expression, N_functionid);
196 
197 	if (SUCCEED == get_N_functionid(expression, N_functionid, &functionid, NULL))
198 	{
199 		DCconfig_get_functions_by_functionids(&function, &functionid, &errcode, 1);
200 
201 		if (SUCCEED == errcode)
202 		{
203 			*itemid = function.itemid;
204 			ret = SUCCEED;
205 		}
206 
207 		DCconfig_clean_functions(&function, &errcode, 1);
208 	}
209 
210 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
211 
212 	return ret;
213 }
214 
215 /******************************************************************************
216  *                                                                            *
217  * Function: get_expanded_expression                                          *
218  *                                                                            *
219  * Purpose: get trigger expression with expanded user macros                  *
220  *                                                                            *
221  * Comments: removes ' ', '\r', '\n' and '\t' for easier number search        *
222  *                                                                            *
223  ******************************************************************************/
get_expanded_expression(const char * expression)224 static char	*get_expanded_expression(const char *expression)
225 {
226 	char	*expression_ex;
227 
228 	if (NULL != (expression_ex = DCexpression_expand_user_macros(expression)))
229 		zbx_remove_whitespace(expression_ex);
230 
231 	return expression_ex;
232 }
233 
234 /******************************************************************************
235  *                                                                            *
236  * Function: get_trigger_expression_constant                                  *
237  *                                                                            *
238  * Purpose: get constant from a trigger expression corresponding a given      *
239  *          reference from trigger name                                       *
240  *                                                                            *
241  * Parameters: expression - [IN] trigger expression, source of constants      *
242  *             reference  - [IN] reference from a trigger name ($1, $2, ...)  *
243  *             constant   - [OUT] pointer to the constant's location in       *
244  *                            trigger expression or empty string if there is  *
245  *                            no corresponding constant                       *
246  *             length     - [OUT] length of constant                          *
247  *                                                                            *
248  ******************************************************************************/
get_trigger_expression_constant(const char * expression,const zbx_token_reference_t * reference,const char ** constant,size_t * length)249 static void	get_trigger_expression_constant(const char *expression, const zbx_token_reference_t *reference,
250 		const char **constant, size_t *length)
251 {
252 	size_t		pos;
253 	zbx_strloc_t	number;
254 	int		index;
255 
256 	for (pos = 0, index = 1; SUCCEED == zbx_number_find(expression, pos, &number); pos = number.r + 1, index++)
257 	{
258 		if (index < reference->index)
259 			continue;
260 
261 		*length = number.r - number.l + 1;
262 		*constant = expression + number.l;
263 		return;
264 	}
265 
266 	*length = 0;
267 	*constant = "";
268 }
269 
DCexpand_trigger_expression(char ** expression)270 static void	DCexpand_trigger_expression(char **expression)
271 {
272 	const char	*__function_name = "DCexpand_trigger_expression";
273 
274 	char		*tmp = NULL;
275 	size_t		tmp_alloc = 256, tmp_offset = 0, l, r;
276 	DC_FUNCTION	function;
277 	DC_ITEM		item;
278 	zbx_uint64_t	functionid;
279 	int		errcode[2];
280 
281 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:'%s'", __function_name, *expression);
282 
283 	tmp = (char *)zbx_malloc(tmp, tmp_alloc);
284 
285 	for (l = 0; '\0' != (*expression)[l]; l++)
286 	{
287 		if ('{' != (*expression)[l])
288 		{
289 			zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
290 			continue;
291 		}
292 
293 		/* skip user macros */
294 		if ('$' == (*expression)[l + 1])
295 		{
296 			int	macro_r, context_l, context_r;
297 
298 			if (SUCCEED == zbx_user_macro_parse(*expression + l, &macro_r, &context_l, &context_r))
299 			{
300 				zbx_strncpy_alloc(&tmp, &tmp_alloc, &tmp_offset, *expression + l, macro_r + 1);
301 				l += macro_r;
302 				continue;
303 			}
304 
305 			zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '{');
306 			zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '$');
307 			l++;
308 			continue;
309 		}
310 
311 		for (r = l + 1; 0 != isdigit((*expression)[r]); r++)
312 			;
313 
314 		if ('}' != (*expression)[r])
315 		{
316 			zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
317 			continue;
318 		}
319 
320 		(*expression)[r] = '\0';
321 
322 		if (SUCCEED == is_uint64(&(*expression)[l + 1], &functionid))
323 		{
324 			DCconfig_get_functions_by_functionids(&function, &functionid, &errcode[0], 1);
325 
326 			if (SUCCEED == errcode[0])
327 			{
328 				DCconfig_get_items_by_itemids(&item, &function.itemid, &errcode[1], 1);
329 
330 				if (SUCCEED == errcode[1])
331 				{
332 					zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '{');
333 					zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, item.host.host);
334 					zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ':');
335 					zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, item.key_orig);
336 					zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '.');
337 					zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, function.function);
338 					zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, '(');
339 					zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, function.parameter);
340 					zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, ")}");
341 				}
342 
343 				DCconfig_clean_items(&item, &errcode[1], 1);
344 			}
345 
346 			DCconfig_clean_functions(&function, &errcode[0], 1);
347 
348 			if (SUCCEED != errcode[0] || SUCCEED != errcode[1])
349 				zbx_strcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, "*ERROR*");
350 
351 			l = r;
352 		}
353 		else
354 			zbx_chrcpy_alloc(&tmp, &tmp_alloc, &tmp_offset, (*expression)[l]);
355 
356 		(*expression)[r] = '}';
357 	}
358 
359 	zbx_free(*expression);
360 	*expression = tmp;
361 
362 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() expression:'%s'", __function_name, *expression);
363 }
364 
365 /******************************************************************************
366  *                                                                            *
367  * Function: get_trigger_severity_name                                        *
368  *                                                                            *
369  * Purpose: get trigger severity name                                         *
370  *                                                                            *
371  * Parameters: trigger    - [IN] a trigger data with priority field;          *
372  *                               TRIGGER_SEVERITY_*                           *
373  *             replace_to - [OUT] pointer to a buffer that will receive       *
374  *                          a null-terminated trigger severity string         *
375  *                                                                            *
376  * Return value: upon successful completion return SUCCEED                    *
377  *               otherwise FAIL                                               *
378  *                                                                            *
379  ******************************************************************************/
get_trigger_severity_name(unsigned char priority,char ** replace_to)380 static int	get_trigger_severity_name(unsigned char priority, char **replace_to)
381 {
382 	zbx_config_t	cfg;
383 
384 	if (TRIGGER_SEVERITY_COUNT <= priority)
385 		return FAIL;
386 
387 	zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
388 
389 	*replace_to = zbx_strdup(*replace_to, cfg.severity_name[priority]);
390 
391 	zbx_config_clean(&cfg);
392 
393 	return SUCCEED;
394 }
395 
396 /******************************************************************************
397  *                                                                            *
398  * Function: get_problem_update_actions                                       *
399  *                                                                            *
400  * Purpose: get human readable list of problem update actions                 *
401  *                                                                            *
402  * Parameters: ack     - [IN] the acknowledge (problem update) data           *
403  *             actions - [IN] the required action flags                       *
404  *             out     - [OUT] the output buffer                              *
405  *                                                                            *
406  * Return value: SUCCEED - successfully returned list of problem update       *
407  *               FAIL    - no matching actions were made                      *
408  *                                                                            *
409  ******************************************************************************/
get_problem_update_actions(const DB_ACKNOWLEDGE * ack,int actions,char ** out)410 static int	get_problem_update_actions(const DB_ACKNOWLEDGE *ack, int actions, char **out)
411 {
412 	char	*buf = NULL, *prefixes[] = {"", ", ", ", ", ", "};
413 	size_t	buf_alloc = 0, buf_offset = 0;
414 	int	i, index, flags;
415 
416 	if (0 == (flags = ack->action & actions))
417 		return FAIL;
418 
419 	for (i = 0, index = 0; i < ZBX_PROBLEM_UPDATE_ACTION_COUNT; i++)
420 	{
421 		if (0 != (flags & (1 << i)))
422 			index++;
423 	}
424 
425 	if (1 < index)
426 		prefixes[index - 1] = " and ";
427 
428 	index = 0;
429 
430 	if (0 != (flags & ZBX_PROBLEM_UPDATE_ACKNOWLEDGE))
431 	{
432 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "acknowledged");
433 		index++;
434 	}
435 
436 	if (0 != (flags & ZBX_PROBLEM_UPDATE_MESSAGE))
437 	{
438 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
439 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "commented");
440 	}
441 
442 	if (0 != (flags & ZBX_PROBLEM_UPDATE_SEVERITY))
443 	{
444 		zbx_config_t	cfg;
445 		const char	*from = "unknown", *to = "unknown";
446 
447 		zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_SEVERITY_NAME);
448 
449 		if (TRIGGER_SEVERITY_COUNT > ack->old_severity && 0 <= ack->old_severity)
450 			from = cfg.severity_name[ack->old_severity];
451 
452 		if (TRIGGER_SEVERITY_COUNT > ack->new_severity && 0 <= ack->new_severity)
453 			to = cfg.severity_name[ack->new_severity];
454 
455 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
456 		zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "changed severity from %s to %s",
457 				from, to);
458 
459 		zbx_config_clean(&cfg);
460 	}
461 
462 	if (0 != (flags & ZBX_PROBLEM_UPDATE_CLOSE))
463 	{
464 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, prefixes[index++]);
465 		zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, "closed");
466 	}
467 
468 	zbx_free(*out);
469 	*out = buf;
470 
471 	return SUCCEED;
472 }
473 
474 /******************************************************************************
475  *                                                                            *
476  * Function: item_description                                                 *
477  *                                                                            *
478  * Purpose: substitute key parameters and user macros in                      *
479  *          the item description string with real values                      *
480  *                                                                            *
481  ******************************************************************************/
item_description(char ** data,const char * key,zbx_uint64_t hostid)482 static void	item_description(char **data, const char *key, zbx_uint64_t hostid)
483 {
484 	AGENT_REQUEST	request;
485 	const char	*param;
486 	char		c, *p, *m, *n, *str_out = NULL, *replace_to = NULL;
487 	int		macro_r, context_l, context_r;
488 
489 	init_request(&request);
490 
491 	if (SUCCEED != parse_item_key(key, &request))
492 		goto out;
493 
494 	p = *data;
495 
496 	while (NULL != (m = strchr(p, '$')))
497 	{
498 		if (m > p && '{' == *(m - 1) && FAIL != zbx_user_macro_parse(m - 1, &macro_r, &context_l, &context_r))
499 		{
500 			/* user macros */
501 
502 			n = m + macro_r;
503 			c = *n;
504 			*n = '\0';
505 			DCget_user_macro(&hostid, 1, m - 1, &replace_to);
506 
507 			if (NULL != replace_to)
508 			{
509 				*(m - 1) = '\0';
510 				str_out = zbx_strdcat(str_out, p);
511 				*(m - 1) = '{';
512 
513 				str_out = zbx_strdcat(str_out, replace_to);
514 				zbx_free(replace_to);
515 			}
516 			else
517 				str_out = zbx_strdcat(str_out, p);
518 
519 			*n = c;
520 			p = n;
521 		}
522 		else if ('1' <= *(m + 1) && *(m + 1) <= '9')
523 		{
524 			/* macros $1, $2, ... */
525 
526 			*m = '\0';
527 			str_out = zbx_strdcat(str_out, p);
528 			*m++ = '$';
529 
530 			if (NULL != (param = get_rparam(&request, *m - '0' - 1)))
531 				str_out = zbx_strdcat(str_out, param);
532 
533 			p = m + 1;
534 		}
535 		else
536 		{
537 			/* just a dollar sign */
538 
539 			c = *++m;
540 			*m = '\0';
541 			str_out = zbx_strdcat(str_out, p);
542 			*m = c;
543 			p = m;
544 		}
545 	}
546 
547 	if (NULL != str_out)
548 	{
549 		str_out = zbx_strdcat(str_out, p);
550 		zbx_free(*data);
551 		*data = str_out;
552 	}
553 out:
554 	free_request(&request);
555 }
556 
557 /******************************************************************************
558  *                                                                            *
559  * Function: DBget_host_value                                                 *
560  *                                                                            *
561  * Purpose: request host name by hostid                                       *
562  *                                                                            *
563  * Return value: upon successful completion return SUCCEED                    *
564  *               otherwise FAIL                                               *
565  *                                                                            *
566  ******************************************************************************/
DBget_host_value(zbx_uint64_t hostid,char ** replace_to,const char * field_name)567 static int	DBget_host_value(zbx_uint64_t hostid, char **replace_to, const char *field_name)
568 {
569 	DB_RESULT	result;
570 	DB_ROW		row;
571 	int		ret = FAIL;
572 
573 	result = DBselect(
574 			"select %s"
575 			" from hosts"
576 			" where hostid=" ZBX_FS_UI64,
577 			field_name, hostid);
578 
579 	if (NULL != (row = DBfetch(result)))
580 	{
581 		*replace_to = zbx_strdup(*replace_to, row[0]);
582 		ret = SUCCEED;
583 	}
584 	DBfree_result(result);
585 
586 	return ret;
587 }
588 
589 /******************************************************************************
590  *                                                                            *
591  * Function: DBget_templateid_by_triggerid                                    *
592  *                                                                            *
593  * Purpose: get template trigger ID from which the trigger is inherited       *
594  *                                                                            *
595  * Return value: upon successful completion return SUCCEED                    *
596  *               otherwise FAIL                                               *
597  *                                                                            *
598  ******************************************************************************/
DBget_templateid_by_triggerid(zbx_uint64_t triggerid,zbx_uint64_t * templateid)599 static int	DBget_templateid_by_triggerid(zbx_uint64_t triggerid, zbx_uint64_t *templateid)
600 {
601 	DB_RESULT	result;
602 	DB_ROW		row;
603 	int		ret = FAIL;
604 
605 	result = DBselect(
606 			"select templateid"
607 			" from triggers"
608 			" where triggerid=" ZBX_FS_UI64,
609 			triggerid);
610 
611 	if (NULL != (row = DBfetch(result)))
612 	{
613 		ZBX_DBROW2UINT64(*templateid, row[0]);
614 		ret = SUCCEED;
615 	}
616 	DBfree_result(result);
617 
618 	return ret;
619 }
620 
621 /******************************************************************************
622  *                                                                            *
623  * Function: DBget_trigger_template_name                                      *
624  *                                                                            *
625  * Purpose: get comma-space separated trigger template names in which         *
626  *          the trigger is defined                                            *
627  *                                                                            *
628  * Return value: upon successful completion return SUCCEED                    *
629  *               otherwise FAIL                                               *
630  *                                                                            *
631  * Comments: based on the patch submitted by Hmami Mohamed                    *
632  *                                                                            *
633  ******************************************************************************/
DBget_trigger_template_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)634 static int	DBget_trigger_template_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
635 {
636 	const char	*__function_name = "DBget_trigger_template_name";
637 
638 	DB_RESULT	result;
639 	DB_ROW		row;
640 	int		ret = FAIL;
641 	zbx_uint64_t	templateid;
642 	char		*sql = NULL;
643 	size_t		replace_to_alloc = 64, replace_to_offset = 0,
644 			sql_alloc = 256, sql_offset = 0;
645 	int		user_type = -1;
646 
647 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
648 
649 	if (NULL != userid)
650 	{
651 		result = DBselect("select type from users where userid=" ZBX_FS_UI64, *userid);
652 
653 		if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
654 			user_type = atoi(row[0]);
655 		DBfree_result(result);
656 
657 		if (-1 == user_type)
658 		{
659 			zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __function_name);
660 			goto out;
661 		}
662 	}
663 
664 	/* use parent trigger ID for lld generated triggers */
665 	result = DBselect(
666 			"select parent_triggerid"
667 			" from trigger_discovery"
668 			" where triggerid=" ZBX_FS_UI64,
669 			triggerid);
670 
671 	if (NULL != (row = DBfetch(result)))
672 		ZBX_STR2UINT64(triggerid, row[0]);
673 	DBfree_result(result);
674 
675 	if (SUCCEED != DBget_templateid_by_triggerid(triggerid, &templateid) || 0 == templateid)
676 	{
677 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found or not templated", __function_name);
678 		goto out;
679 	}
680 
681 	do
682 	{
683 		triggerid = templateid;
684 	}
685 	while (SUCCEED == (ret = DBget_templateid_by_triggerid(triggerid, &templateid)) && 0 != templateid);
686 
687 	if (SUCCEED != ret)
688 	{
689 		zabbix_log(LOG_LEVEL_DEBUG, "%s() trigger not found", __function_name);
690 		goto out;
691 	}
692 
693 	*replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
694 	**replace_to = '\0';
695 
696 	sql = (char *)zbx_malloc(sql, sql_alloc);
697 
698 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
699 			"select distinct h.name"
700 			" from hosts h,items i,functions f"
701 			" where h.hostid=i.hostid"
702 				" and i.itemid=f.itemid"
703 				" and f.triggerid=" ZBX_FS_UI64,
704 			triggerid);
705 	if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
706 	{
707 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
708 				" and exists("
709 					"select null"
710 					" from hosts_groups hg,rights r,users_groups ug"
711 					" where h.hostid=hg.hostid"
712 						" and hg.groupid=r.id"
713 						" and r.groupid=ug.usrgrpid"
714 						" and ug.userid=" ZBX_FS_UI64
715 					" group by hg.hostid"
716 					" having min(r.permission)>=%d"
717 				")",
718 				*userid, PERM_READ);
719 	}
720 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by h.name");
721 
722 	result = DBselect("%s", sql);
723 
724 	zbx_free(sql);
725 
726 	while (NULL != (row = DBfetch(result)))
727 	{
728 		if (0 != replace_to_offset)
729 			zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
730 		zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
731 	}
732 	DBfree_result(result);
733 out:
734 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
735 
736 	return ret;
737 }
738 
739 /******************************************************************************
740  *                                                                            *
741  * Function: DBget_trigger_hostgroup_name                                     *
742  *                                                                            *
743  * Purpose: get comma-space separated host group names in which the trigger   *
744  *          is defined                                                        *
745  *                                                                            *
746  * Return value: upon successful completion return SUCCEED                    *
747  *               otherwise FAIL                                               *
748  *                                                                            *
749  ******************************************************************************/
DBget_trigger_hostgroup_name(zbx_uint64_t triggerid,const zbx_uint64_t * userid,char ** replace_to)750 static int	DBget_trigger_hostgroup_name(zbx_uint64_t triggerid, const zbx_uint64_t *userid, char **replace_to)
751 {
752 	const char	*__function_name = "DBget_trigger_hostgroup_name";
753 
754 	DB_RESULT	result;
755 	DB_ROW		row;
756 	int		ret = FAIL;
757 	char		*sql = NULL;
758 	size_t		replace_to_alloc = 64, replace_to_offset = 0,
759 			sql_alloc = 256, sql_offset = 0;
760 	int		user_type = -1;
761 
762 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
763 
764 	if (NULL != userid)
765 	{
766 		result = DBselect("select type from users where userid=" ZBX_FS_UI64, *userid);
767 
768 		if (NULL != (row = DBfetch(result)) && FAIL == DBis_null(row[0]))
769 			user_type = atoi(row[0]);
770 		DBfree_result(result);
771 
772 		if (-1 == user_type)
773 		{
774 			zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot check permissions", __function_name);
775 			goto out;
776 		}
777 	}
778 
779 	*replace_to = (char *)zbx_realloc(*replace_to, replace_to_alloc);
780 	**replace_to = '\0';
781 
782 	sql = (char *)zbx_malloc(sql, sql_alloc);
783 
784 	zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
785 			"select distinct g.name"
786 			" from hstgrp g,hosts_groups hg,items i,functions f"
787 			" where g.groupid=hg.groupid"
788 				" and hg.hostid=i.hostid"
789 				" and i.itemid=f.itemid"
790 				" and f.triggerid=" ZBX_FS_UI64,
791 			triggerid);
792 	if (NULL != userid && USER_TYPE_SUPER_ADMIN != user_type)
793 	{
794 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
795 				" and exists("
796 					"select null"
797 					" from rights r,users_groups ug"
798 					" where g.groupid=r.id"
799 						" and r.groupid=ug.usrgrpid"
800 						" and ug.userid=" ZBX_FS_UI64
801 					" group by r.id"
802 					" having min(r.permission)>=%d"
803 				")",
804 				*userid, PERM_READ);
805 	}
806 	zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " order by g.name");
807 
808 	result = DBselect("%s", sql);
809 
810 	zbx_free(sql);
811 
812 	while (NULL != (row = DBfetch(result)))
813 	{
814 		if (0 != replace_to_offset)
815 			zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
816 		zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, row[0]);
817 		ret = SUCCEED;
818 	}
819 	DBfree_result(result);
820 out:
821 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
822 
823 	return ret;
824 }
825 
826 /******************************************************************************
827  *                                                                            *
828  * Function: get_interface_value                                              *
829  *                                                                            *
830  * Purpose: retrieve a particular value associated with the interface         *
831  *                                                                            *
832  * Return value: upon successful completion return SUCCEED                    *
833  *               otherwise FAIL                                               *
834  *                                                                            *
835  ******************************************************************************/
get_interface_value(zbx_uint64_t hostid,zbx_uint64_t itemid,char ** replace_to,int request)836 static int	get_interface_value(zbx_uint64_t hostid, zbx_uint64_t itemid, char **replace_to, int request)
837 {
838 	int		res;
839 	DC_INTERFACE	interface;
840 
841 	if (SUCCEED != (res = DCconfig_get_interface(&interface, hostid, itemid)))
842 		return res;
843 
844 	switch (request)
845 	{
846 		case ZBX_REQUEST_HOST_IP:
847 			*replace_to = zbx_strdup(*replace_to, interface.ip_orig);
848 			break;
849 		case ZBX_REQUEST_HOST_DNS:
850 			*replace_to = zbx_strdup(*replace_to, interface.dns_orig);
851 			break;
852 		case ZBX_REQUEST_HOST_CONN:
853 			*replace_to = zbx_strdup(*replace_to, interface.addr);
854 			break;
855 		case ZBX_REQUEST_HOST_PORT:
856 			*replace_to = zbx_strdup(*replace_to, interface.port_orig);
857 			break;
858 		default:
859 			THIS_SHOULD_NEVER_HAPPEN;
860 			res = FAIL;
861 	}
862 
863 	return res;
864 }
865 
get_host_value(zbx_uint64_t itemid,char ** replace_to,int request)866 static int	get_host_value(zbx_uint64_t itemid, char **replace_to, int request)
867 {
868 	int	ret;
869 	DC_HOST	host;
870 
871 	DCconfig_get_hosts_by_itemids(&host, &itemid, &ret, 1);
872 
873 	if (FAIL == ret)
874 		return FAIL;
875 
876 	switch (request)
877 	{
878 		case ZBX_REQUEST_HOST_ID:
879 			*replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, host.hostid);
880 			break;
881 		case ZBX_REQUEST_HOST_HOST:
882 			*replace_to = zbx_strdup(*replace_to, host.host);
883 			break;
884 		case ZBX_REQUEST_HOST_NAME:
885 			*replace_to = zbx_strdup(*replace_to, host.name);
886 			break;
887 		default:
888 			THIS_SHOULD_NEVER_HAPPEN;
889 			ret = FAIL;
890 	}
891 
892 	return ret;
893 }
894 
895 /******************************************************************************
896  *                                                                            *
897  * Function: zbx_substitute_item_name_macros                                  *
898  *                                                                            *
899  * Purpose: substitute key macros and use it to substitute item name macros if*
900  *          item name is specified                                            *
901  *                                                                            *
902  * Parameters: dc_item    - [IN] item information used in substitution        *
903  *             name       - [IN] optional item name to substitute             *
904  *             replace_to - [OUT] expanded item name or key if name is absent *
905  *                                                                            *
906  ******************************************************************************/
zbx_substitute_item_name_macros(DC_ITEM * dc_item,const char * name,char ** replace_to)907 int	zbx_substitute_item_name_macros(DC_ITEM *dc_item, const char *name, char **replace_to)
908 {
909 	int	ret;
910 	char	*key;
911 
912 	if (INTERFACE_TYPE_UNKNOWN == dc_item->interface.type)
913 		ret = DCconfig_get_interface(&dc_item->interface, dc_item->host.hostid, 0);
914 	else
915 		ret = SUCCEED;
916 
917 	if (ret == FAIL)
918 		return FAIL;
919 
920 	key = zbx_strdup(NULL, dc_item->key_orig);
921 	substitute_key_macros(&key, NULL, dc_item, NULL, MACRO_TYPE_ITEM_KEY,
922 			NULL, 0);
923 
924 	if (NULL != name)
925 	{
926 		*replace_to = zbx_strdup(*replace_to, name);
927 		item_description(replace_to, key, dc_item->host.hostid);
928 		zbx_free(key);
929 	}
930 	else	/* ZBX_REQUEST_ITEM_KEY */
931 	{
932 		zbx_free(*replace_to);
933 		*replace_to = key;
934 	}
935 
936 	return ret;
937 }
938 
939 /******************************************************************************
940  *                                                                            *
941  * Function: DBget_item_value                                                 *
942  *                                                                            *
943  * Purpose: retrieve a particular value associated with the item              *
944  *                                                                            *
945  * Return value: upon successful completion return SUCCEED                    *
946  *               otherwise FAIL                                               *
947  *                                                                            *
948  ******************************************************************************/
DBget_item_value(zbx_uint64_t itemid,char ** replace_to,int request)949 static int	DBget_item_value(zbx_uint64_t itemid, char **replace_to, int request)
950 {
951 	const char	*__function_name = "DBget_item_value";
952 	DB_RESULT	result;
953 	DB_ROW		row;
954 	DC_ITEM		dc_item;
955 	zbx_uint64_t	proxy_hostid;
956 	int		ret = FAIL, errcode;
957 
958 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
959 
960 	switch (request)
961 	{
962 		case ZBX_REQUEST_HOST_IP:
963 		case ZBX_REQUEST_HOST_DNS:
964 		case ZBX_REQUEST_HOST_CONN:
965 		case ZBX_REQUEST_HOST_PORT:
966 			return get_interface_value(0, itemid, replace_to, request);
967 		case ZBX_REQUEST_HOST_ID:
968 		case ZBX_REQUEST_HOST_HOST:
969 		case ZBX_REQUEST_HOST_NAME:
970 			return get_host_value(itemid, replace_to, request);
971 	}
972 
973 	result = DBselect(
974 			"select h.proxy_hostid,h.description,i.itemid,i.name,i.key_,i.description"
975 			" from items i"
976 				" join hosts h on h.hostid=i.hostid"
977 			" where i.itemid=" ZBX_FS_UI64, itemid);
978 
979 	if (NULL != (row = DBfetch(result)))
980 	{
981 		switch (request)
982 		{
983 			case ZBX_REQUEST_HOST_DESCRIPTION:
984 				*replace_to = zbx_strdup(*replace_to, row[1]);
985 				ret = SUCCEED;
986 				break;
987 			case ZBX_REQUEST_ITEM_ID:
988 				*replace_to = zbx_strdup(*replace_to, row[2]);
989 				ret = SUCCEED;
990 				break;
991 			case ZBX_REQUEST_ITEM_NAME:
992 				DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
993 
994 				if (SUCCEED == errcode)
995 					ret = zbx_substitute_item_name_macros(&dc_item, row[3], replace_to);
996 
997 				DCconfig_clean_items(&dc_item, &errcode, 1);
998 				break;
999 			case ZBX_REQUEST_ITEM_KEY:
1000 				DCconfig_get_items_by_itemids(&dc_item, &itemid, &errcode, 1);
1001 
1002 				if (SUCCEED == errcode)
1003 					ret = zbx_substitute_item_name_macros(&dc_item, NULL, replace_to);
1004 
1005 				DCconfig_clean_items(&dc_item, &errcode, 1);
1006 				break;
1007 			case ZBX_REQUEST_ITEM_NAME_ORIG:
1008 				*replace_to = zbx_strdup(*replace_to, row[3]);
1009 				ret = SUCCEED;
1010 				break;
1011 			case ZBX_REQUEST_ITEM_KEY_ORIG:
1012 				*replace_to = zbx_strdup(*replace_to, row[4]);
1013 				ret = SUCCEED;
1014 				break;
1015 			case ZBX_REQUEST_ITEM_DESCRIPTION:
1016 				*replace_to = zbx_strdup(*replace_to, row[5]);
1017 				ret = SUCCEED;
1018 				break;
1019 			case ZBX_REQUEST_PROXY_NAME:
1020 				ZBX_DBROW2UINT64(proxy_hostid, row[0]);
1021 
1022 				if (0 == proxy_hostid)
1023 				{
1024 					*replace_to = zbx_strdup(*replace_to, "");
1025 					ret = SUCCEED;
1026 				}
1027 				else
1028 					ret = DBget_host_value(proxy_hostid, replace_to, "host");
1029 				break;
1030 			case ZBX_REQUEST_PROXY_DESCRIPTION:
1031 				ZBX_DBROW2UINT64(proxy_hostid, row[0]);
1032 
1033 				if (0 == proxy_hostid)
1034 				{
1035 					*replace_to = zbx_strdup(*replace_to, "");
1036 					ret = SUCCEED;
1037 				}
1038 				else
1039 					ret = DBget_host_value(proxy_hostid, replace_to, "description");
1040 				break;
1041 		}
1042 	}
1043 	DBfree_result(result);
1044 
1045 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1046 
1047 	return ret;
1048 }
1049 
1050 /******************************************************************************
1051  *                                                                            *
1052  * Function: DBget_trigger_value                                              *
1053  *                                                                            *
1054  * Purpose: retrieve a particular value associated with the trigger's         *
1055  *          N_functionid'th function                                          *
1056  *                                                                            *
1057  * Return value: upon successful completion return SUCCEED                    *
1058  *               otherwise FAIL                                               *
1059  *                                                                            *
1060  ******************************************************************************/
DBget_trigger_value(const char * expression,char ** replace_to,int N_functionid,int request)1061 static int	DBget_trigger_value(const char *expression, char **replace_to, int N_functionid, int request)
1062 {
1063 	const char	*__function_name = "DBget_trigger_value";
1064 
1065 	zbx_uint64_t	itemid;
1066 	int		ret = FAIL;
1067 
1068 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1069 
1070 	if (SUCCEED == get_N_itemid(expression, N_functionid, &itemid))
1071 		ret = DBget_item_value(itemid, replace_to, request);
1072 
1073 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1074 
1075 	return ret;
1076 }
1077 
1078 /******************************************************************************
1079  *                                                                            *
1080  * Function: DBget_trigger_event_count                                        *
1081  *                                                                            *
1082  * Purpose: retrieve number of events (acknowledged or unacknowledged) for a  *
1083  *          trigger (in an OK or PROBLEM state) which generated an event      *
1084  *                                                                            *
1085  * Parameters: triggerid    - [IN] trigger identifier from database           *
1086  *             replace_to   - [IN/OUT] pointer to result buffer               *
1087  *             problem_only - [IN] selected trigger status:                   *
1088  *                             0 - TRIGGER_VALUE_PROBLEM and TRIGGER_VALUE_OK *
1089  *                             1 - TRIGGER_VALUE_PROBLEM                      *
1090  *             acknowledged - [IN] acknowledged event or not                  *
1091  *                                                                            *
1092  * Return value: upon successful completion return SUCCEED                    *
1093  *               otherwise FAIL                                               *
1094  *                                                                            *
1095  * Author: Alexander Vladishev, Aleksandrs Saveljevs                          *
1096  *                                                                            *
1097  * Comments:                                                                  *
1098  *                                                                            *
1099  ******************************************************************************/
DBget_trigger_event_count(zbx_uint64_t triggerid,char ** replace_to,int problem_only,int acknowledged)1100 static int	DBget_trigger_event_count(zbx_uint64_t triggerid, char **replace_to, int problem_only, int acknowledged)
1101 {
1102 	DB_RESULT	result;
1103 	DB_ROW		row;
1104 	char		value[4];
1105 	int		ret = FAIL;
1106 
1107 	if (problem_only)
1108 		zbx_snprintf(value, sizeof(value), "%d", TRIGGER_VALUE_PROBLEM);
1109 	else
1110 		zbx_snprintf(value, sizeof(value), "%d,%d", TRIGGER_VALUE_PROBLEM, TRIGGER_VALUE_OK);
1111 
1112 	result = DBselect(
1113 			"select count(*)"
1114 			" from events"
1115 			" where source=%d"
1116 				" and object=%d"
1117 				" and objectid=" ZBX_FS_UI64
1118 				" and value in (%s)"
1119 				" and acknowledged=%d",
1120 			EVENT_SOURCE_TRIGGERS,
1121 			EVENT_OBJECT_TRIGGER,
1122 			triggerid,
1123 			value,
1124 			acknowledged);
1125 
1126 	if (NULL != (row = DBfetch(result)))
1127 	{
1128 		*replace_to = zbx_strdup(*replace_to, row[0]);
1129 		ret = SUCCEED;
1130 	}
1131 	DBfree_result(result);
1132 
1133 	return ret;
1134 }
1135 
1136 /******************************************************************************
1137  *                                                                            *
1138  * Function: DBget_dhost_value_by_event                                       *
1139  *                                                                            *
1140  * Purpose: retrieve discovered host value by event and field name            *
1141  *                                                                            *
1142  * Parameters:                                                                *
1143  *                                                                            *
1144  * Return value: upon successful completion return SUCCEED                    *
1145  *               otherwise FAIL                                               *
1146  *                                                                            *
1147  * Author: Alexander Vladishev                                                *
1148  *                                                                            *
1149  * Comments:                                                                  *
1150  *                                                                            *
1151  ******************************************************************************/
DBget_dhost_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1152 static int	DBget_dhost_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1153 {
1154 	DB_RESULT	result;
1155 	DB_ROW		row;
1156 	int		ret = FAIL;
1157 	char		sql[MAX_STRING_LEN];
1158 
1159 	switch (event->object)
1160 	{
1161 		case EVENT_OBJECT_DHOST:
1162 			zbx_snprintf(sql, sizeof(sql),
1163 					"select %s"
1164 					" from drules r,dhosts h,dservices s"
1165 					" where r.druleid=h.druleid"
1166 						" and h.dhostid=s.dhostid"
1167 						" and h.dhostid=" ZBX_FS_UI64
1168 					" order by s.dserviceid",
1169 					fieldname,
1170 					event->objectid);
1171 			break;
1172 		case EVENT_OBJECT_DSERVICE:
1173 			zbx_snprintf(sql, sizeof(sql),
1174 					"select %s"
1175 					" from drules r,dhosts h,dservices s"
1176 					" where r.druleid=h.druleid"
1177 						" and h.dhostid=s.dhostid"
1178 						" and s.dserviceid=" ZBX_FS_UI64,
1179 					fieldname,
1180 					event->objectid);
1181 			break;
1182 		default:
1183 			return ret;
1184 	}
1185 
1186 	result = DBselectN(sql, 1);
1187 
1188 	if (NULL != (row = DBfetch(result)))
1189 	{
1190 		*replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1191 		ret = SUCCEED;
1192 	}
1193 	DBfree_result(result);
1194 
1195 	return ret;
1196 }
1197 
1198 /******************************************************************************
1199  *                                                                            *
1200  * Function: DBget_dchecks_value_by_event                                     *
1201  *                                                                            *
1202  * Purpose: retrieve discovery rule check value by event and field name       *
1203  *                                                                            *
1204  * Return value: upon successful completion return SUCCEED                    *
1205  *               otherwise FAIL                                               *
1206  *                                                                            *
1207  ******************************************************************************/
DBget_dchecks_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1208 static int	DBget_dchecks_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1209 {
1210 	DB_RESULT	result;
1211 	DB_ROW		row;
1212 	int		ret = FAIL;
1213 
1214 	switch (event->object)
1215 	{
1216 		case EVENT_OBJECT_DSERVICE:
1217 			result = DBselect("select %s from dchecks c,dservices s"
1218 					" where c.dcheckid=s.dcheckid and s.dserviceid=" ZBX_FS_UI64,
1219 					fieldname, event->objectid);
1220 			break;
1221 		default:
1222 			return ret;
1223 	}
1224 
1225 	if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
1226 	{
1227 		*replace_to = zbx_strdup(*replace_to, row[0]);
1228 		ret = SUCCEED;
1229 	}
1230 	DBfree_result(result);
1231 
1232 	return ret;
1233 }
1234 
1235 /******************************************************************************
1236  *                                                                            *
1237  * Function: DBget_dservice_value_by_event                                    *
1238  *                                                                            *
1239  * Purpose: retrieve discovered service value by event and field name         *
1240  *                                                                            *
1241  * Parameters:                                                                *
1242  *                                                                            *
1243  * Return value: upon successful completion return SUCCEED                    *
1244  *               otherwise FAIL                                               *
1245  *                                                                            *
1246  * Author: Alexander Vladishev                                                *
1247  *                                                                            *
1248  * Comments:                                                                  *
1249  *                                                                            *
1250  ******************************************************************************/
DBget_dservice_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1251 static int	DBget_dservice_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1252 {
1253 	DB_RESULT	result;
1254 	DB_ROW		row;
1255 	int		ret = FAIL;
1256 
1257 	switch (event->object)
1258 	{
1259 		case EVENT_OBJECT_DSERVICE:
1260 			result = DBselect("select %s from dservices s where s.dserviceid=" ZBX_FS_UI64,
1261 					fieldname, event->objectid);
1262 			break;
1263 		default:
1264 			return ret;
1265 	}
1266 
1267 	if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0]))
1268 	{
1269 		*replace_to = zbx_strdup(*replace_to, row[0]);
1270 		ret = SUCCEED;
1271 	}
1272 	DBfree_result(result);
1273 
1274 	return ret;
1275 }
1276 
1277 /******************************************************************************
1278  *                                                                            *
1279  * Function: DBget_drule_value_by_event                                       *
1280  *                                                                            *
1281  * Purpose: retrieve discovery rule value by event and field name             *
1282  *                                                                            *
1283  * Parameters:                                                                *
1284  *                                                                            *
1285  * Return value: upon successful completion return SUCCEED                    *
1286  *               otherwise FAIL                                               *
1287  *                                                                            *
1288  * Author: Alexander Vladishev                                                *
1289  *                                                                            *
1290  * Comments:                                                                  *
1291  *                                                                            *
1292  ******************************************************************************/
DBget_drule_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1293 static int	DBget_drule_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1294 {
1295 	DB_RESULT	result;
1296 	DB_ROW		row;
1297 	int		ret = FAIL;
1298 
1299 	if (EVENT_SOURCE_DISCOVERY != event->source)
1300 		return FAIL;
1301 
1302 	switch (event->object)
1303 	{
1304 		case EVENT_OBJECT_DHOST:
1305 			result = DBselect("select r.%s from drules r,dhosts h"
1306 					" where r.druleid=h.druleid and h.dhostid=" ZBX_FS_UI64,
1307 					fieldname, event->objectid);
1308 			break;
1309 		case EVENT_OBJECT_DSERVICE:
1310 			result = DBselect("select r.%s from drules r,dhosts h,dservices s"
1311 					" where r.druleid=h.druleid and h.dhostid=s.dhostid and s.dserviceid=" ZBX_FS_UI64,
1312 					fieldname, event->objectid);
1313 			break;
1314 		default:
1315 			return ret;
1316 	}
1317 
1318 	if (NULL != (row = DBfetch(result)))
1319 	{
1320 		*replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1321 		ret = SUCCEED;
1322 	}
1323 	DBfree_result(result);
1324 
1325 	return ret;
1326 }
1327 
1328 /******************************************************************************
1329  *                                                                            *
1330  * Function: DBget_history_log_value                                          *
1331  *                                                                            *
1332  * Purpose: retrieve a particular attribute of a log value                    *
1333  *                                                                            *
1334  * Return value: upon successful completion return SUCCEED                    *
1335  *               otherwise FAIL                                               *
1336  *                                                                            *
1337  ******************************************************************************/
DBget_history_log_value(zbx_uint64_t itemid,char ** replace_to,int request,int clock,int ns)1338 static int	DBget_history_log_value(zbx_uint64_t itemid, char **replace_to, int request, int clock, int ns)
1339 {
1340 	const char		*__function_name = "DBget_history_log_value";
1341 
1342 	DC_ITEM			item;
1343 	int			ret = FAIL, errcode = FAIL;
1344 	zbx_timespec_t		ts = {clock, ns};
1345 	zbx_history_record_t	value;
1346 
1347 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1348 
1349 	DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
1350 
1351 	if (SUCCEED != errcode || ITEM_VALUE_TYPE_LOG != item.value_type)
1352 		goto out;
1353 
1354 	if (SUCCEED != zbx_vc_get_value(itemid, item.value_type, &ts, &value))
1355 		goto out;
1356 
1357 	switch (request)
1358 	{
1359 		case ZBX_REQUEST_ITEM_LOG_DATE:
1360 			*replace_to = zbx_strdup(*replace_to, zbx_date2str((time_t)value.value.log->timestamp));
1361 			goto success;
1362 		case ZBX_REQUEST_ITEM_LOG_TIME:
1363 			*replace_to = zbx_strdup(*replace_to, zbx_time2str((time_t)value.value.log->timestamp));
1364 			goto success;
1365 		case ZBX_REQUEST_ITEM_LOG_AGE:
1366 			*replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - value.value.log->timestamp));
1367 			goto success;
1368 	}
1369 
1370 	/* the following attributes are set only for windows eventlog items */
1371 	if (0 != strncmp(item.key_orig, "eventlog[", 9))
1372 		goto clean;
1373 
1374 	switch (request)
1375 	{
1376 		case ZBX_REQUEST_ITEM_LOG_SOURCE:
1377 			*replace_to = zbx_strdup(*replace_to, (NULL == value.value.log->source ? "" :
1378 					value.value.log->source));
1379 			break;
1380 		case ZBX_REQUEST_ITEM_LOG_SEVERITY:
1381 			*replace_to = zbx_strdup(*replace_to,
1382 					zbx_item_logtype_string((unsigned char)value.value.log->severity));
1383 			break;
1384 		case ZBX_REQUEST_ITEM_LOG_NSEVERITY:
1385 			*replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->severity);
1386 			break;
1387 		case ZBX_REQUEST_ITEM_LOG_EVENTID:
1388 			*replace_to = zbx_dsprintf(*replace_to, "%d", value.value.log->logeventid);
1389 			break;
1390 	}
1391 success:
1392 	ret = SUCCEED;
1393 clean:
1394 	zbx_history_record_clear(&value, ITEM_VALUE_TYPE_LOG);
1395 out:
1396 	DCconfig_clean_items(&item, &errcode, 1);
1397 
1398 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1399 
1400 	return ret;
1401 }
1402 
1403 /******************************************************************************
1404  *                                                                            *
1405  * Function: get_history_log_value                                            *
1406  *                                                                            *
1407  * Purpose: retrieve a particular attribute of a log value                    *
1408  *                                                                            *
1409  * Return value: upon successful completion return SUCCEED                    *
1410  *               otherwise FAIL                                               *
1411  *                                                                            *
1412  ******************************************************************************/
get_history_log_value(const char * expression,char ** replace_to,int N_functionid,int request,int clock,int ns)1413 static int	get_history_log_value(const char *expression, char **replace_to, int N_functionid,
1414 		int request, int clock, int ns)
1415 {
1416 	const char	*__function_name = "get_history_log_value";
1417 
1418 	zbx_uint64_t	itemid;
1419 	int		ret = FAIL;
1420 
1421 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1422 
1423 	if (SUCCEED == get_N_itemid(expression, N_functionid, &itemid))
1424 		ret = DBget_history_log_value(itemid, replace_to, request, clock, ns);
1425 
1426 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1427 
1428 	return ret;
1429 }
1430 
1431 /******************************************************************************
1432  *                                                                            *
1433  * Function: DBitem_lastvalue                                                 *
1434  *                                                                            *
1435  * Purpose: retrieve item lastvalue by trigger expression                     *
1436  *          and number of function                                            *
1437  *                                                                            *
1438  * Parameters:                                                                *
1439  *                                                                            *
1440  * Return value: upon successful completion return SUCCEED                    *
1441  *               otherwise FAIL                                               *
1442  *                                                                            *
1443  * Author: Alexander Vladishev                                                *
1444  *                                                                            *
1445  * Comments:                                                                  *
1446  *                                                                            *
1447  ******************************************************************************/
DBitem_lastvalue(const char * expression,char ** lastvalue,int N_functionid,int raw)1448 static int	DBitem_lastvalue(const char *expression, char **lastvalue, int N_functionid, int raw)
1449 {
1450 	const char	*__function_name = "DBitem_lastvalue";
1451 
1452 	DB_RESULT	result;
1453 	DB_ROW		row;
1454 	zbx_uint64_t	itemid;
1455 	int		ret = FAIL;
1456 
1457 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1458 
1459 	if (FAIL == get_N_itemid(expression, N_functionid, &itemid))
1460 		goto out;
1461 
1462 	result = DBselect(
1463 			"select value_type,valuemapid,units"
1464 			" from items"
1465 			" where itemid=" ZBX_FS_UI64,
1466 			itemid);
1467 
1468 	if (NULL != (row = DBfetch(result)))
1469 	{
1470 		unsigned char		value_type;
1471 		zbx_uint64_t		valuemapid;
1472 		zbx_history_record_t	vc_value;
1473 		zbx_timespec_t		ts;
1474 
1475 		ts.sec = time(NULL);
1476 		ts.ns = 999999999;
1477 
1478 		value_type = (unsigned char)atoi(row[0]);
1479 		ZBX_DBROW2UINT64(valuemapid, row[1]);
1480 
1481 		if (SUCCEED == zbx_vc_get_value(itemid, value_type, &ts, &vc_value))
1482 		{
1483 			char	tmp[MAX_BUFFER_LEN];
1484 
1485 			zbx_history_value2str(tmp, sizeof(tmp), &vc_value.value, value_type);
1486 			zbx_history_record_clear(&vc_value, value_type);
1487 
1488 			if (0 == raw)
1489 				zbx_format_value(tmp, sizeof(tmp), valuemapid, row[2], value_type);
1490 
1491 			*lastvalue = zbx_strdup(*lastvalue, tmp);
1492 
1493 			ret = SUCCEED;
1494 		}
1495 	}
1496 	DBfree_result(result);
1497 out:
1498 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1499 
1500 	return ret;
1501 }
1502 
1503 /******************************************************************************
1504  *                                                                            *
1505  * Function: DBitem_value                                                     *
1506  *                                                                            *
1507  * Purpose: retrieve item value by trigger expression and number of function  *
1508  *                                                                            *
1509  * Return value: upon successful completion return SUCCEED                    *
1510  *               otherwise FAIL                                               *
1511  *                                                                            *
1512  ******************************************************************************/
DBitem_value(const char * expression,char ** value,int N_functionid,int clock,int ns,int raw)1513 static int	DBitem_value(const char *expression, char **value, int N_functionid, int clock, int ns, int raw)
1514 {
1515 	const char	*__function_name = "DBitem_value";
1516 
1517 	DB_RESULT	result;
1518 	DB_ROW		row;
1519 	zbx_uint64_t	itemid;
1520 	int		ret = FAIL;
1521 
1522 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1523 
1524 	if (FAIL == get_N_itemid(expression, N_functionid, &itemid))
1525 		goto out;
1526 
1527 	result = DBselect(
1528 			"select value_type,valuemapid,units"
1529 			" from items"
1530 			" where itemid=" ZBX_FS_UI64,
1531 			itemid);
1532 
1533 	if (NULL != (row = DBfetch(result)))
1534 	{
1535 		unsigned char		value_type;
1536 		zbx_uint64_t		valuemapid;
1537 		zbx_timespec_t		ts = {clock, ns};
1538 		zbx_history_record_t	vc_value;
1539 
1540 		value_type = (unsigned char)atoi(row[0]);
1541 		ZBX_DBROW2UINT64(valuemapid, row[1]);
1542 
1543 		if (SUCCEED == zbx_vc_get_value(itemid, value_type, &ts, &vc_value))
1544 		{
1545 			char	tmp[MAX_BUFFER_LEN];
1546 
1547 			zbx_history_value2str(tmp, sizeof(tmp), &vc_value.value, value_type);
1548 			zbx_history_record_clear(&vc_value, value_type);
1549 
1550 			if (0 == raw)
1551 				zbx_format_value(tmp, sizeof(tmp), valuemapid, row[2], value_type);
1552 
1553 			*value = zbx_strdup(*value, tmp);
1554 
1555 			ret = SUCCEED;
1556 		}
1557 	}
1558 	DBfree_result(result);
1559 out:
1560 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
1561 
1562 	return ret;
1563 }
1564 
1565 /******************************************************************************
1566  *                                                                            *
1567  * Function: get_escalation_history                                           *
1568  *                                                                            *
1569  * Purpose: retrieve escalation history                                       *
1570  *                                                                            *
1571  ******************************************************************************/
get_escalation_history(zbx_uint64_t actionid,const DB_EVENT * event,const DB_EVENT * r_event,char ** replace_to,const zbx_uint64_t * recipient_userid)1572 static void	get_escalation_history(zbx_uint64_t actionid, const DB_EVENT *event, const DB_EVENT *r_event,
1573 			char **replace_to, const zbx_uint64_t *recipient_userid)
1574 {
1575 	DB_RESULT	result;
1576 	DB_ROW		row;
1577 	char		*buf = NULL, *p;
1578 	size_t		buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1579 	int		esc_step;
1580 	unsigned char	type, status;
1581 	time_t		now;
1582 	zbx_uint64_t	userid;
1583 
1584 	buf = (char *)zbx_malloc(buf, buf_alloc);
1585 
1586 	zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem started: %s %s Age: %s\n",
1587 			zbx_date2str(event->clock), zbx_time2str(event->clock),
1588 			zbx_age2str(time(NULL) - event->clock));
1589 
1590 	result = DBselect("select a.clock,a.alerttype,a.status,mt.description,a.sendto"
1591 				",a.error,a.esc_step,a.userid,a.message"
1592 			" from alerts a"
1593 			" left join media_type mt"
1594 				" on mt.mediatypeid=a.mediatypeid"
1595 			" where a.eventid=" ZBX_FS_UI64
1596 				" and a.actionid=" ZBX_FS_UI64
1597 			" order by a.clock",
1598 			event->eventid, actionid);
1599 
1600 	while (NULL != (row = DBfetch(result)))
1601 	{
1602 		int	user_permit;
1603 
1604 		now = atoi(row[0]);
1605 		type = (unsigned char)atoi(row[1]);
1606 		status = (unsigned char)atoi(row[2]);
1607 		esc_step = atoi(row[6]);
1608 		ZBX_DBROW2UINT64(userid, row[7]);
1609 		user_permit = zbx_check_user_permissions(&userid, recipient_userid);
1610 
1611 		if (0 != esc_step)
1612 			zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%d. ", esc_step);
1613 
1614 		zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s %s %-7s %-11s",
1615 				zbx_date2str(now), zbx_time2str(now),	/* date, time */
1616 				zbx_alert_type_string(type),		/* alert type */
1617 				zbx_alert_status_string(type, status));	/* alert status */
1618 
1619 		if (ALERT_TYPE_COMMAND == type)
1620 		{
1621 			if (NULL != (p = strchr(row[8], ':')))
1622 			{
1623 				*p = '\0';
1624 				zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " \"%s\"", row[8]);	/* host */
1625 				*p = ':';
1626 			}
1627 		}
1628 		else
1629 		{
1630 			const char	*description, *send_to, *user_name;
1631 
1632 			description = (SUCCEED == DBis_null(row[3]) ? "" : row[3]);
1633 
1634 			if (SUCCEED == user_permit)
1635 			{
1636 				send_to = row[4];
1637 				user_name = zbx_user_string(userid);
1638 			}
1639 			else
1640 			{
1641 				send_to = "\"Inaccessible recipient details\"";
1642 				user_name = "Inaccessible user";
1643 			}
1644 
1645 			zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s %s \"%s\"",
1646 					description,	/* media type description */
1647 					send_to,	/* historical recipient */
1648 					user_name);	/* alert user full name */
1649 		}
1650 
1651 		if (ALERT_STATUS_FAILED == status)
1652 		{
1653 			/* alert error can be generated by SMTP Relay or other media and contain sensitive details */
1654 			if (SUCCEED == user_permit)
1655 				zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s", row[5]);
1656 			else
1657 				zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " \"Inaccessible error message\"");
1658 		}
1659 
1660 		zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1661 	}
1662 	DBfree_result(result);
1663 
1664 	if (NULL != r_event)
1665 	{
1666 		zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Problem ended: %s %s\n",
1667 				zbx_date2str(r_event->clock), zbx_time2str(r_event->clock));
1668 	}
1669 
1670 	if (0 != buf_offset)
1671 		buf[--buf_offset] = '\0';
1672 
1673 	*replace_to = buf;
1674 }
1675 
1676 /******************************************************************************
1677  *                                                                            *
1678  * Function: get_event_update_history                                         *
1679  *                                                                            *
1680  * Purpose: retrieve event acknowledges history                               *
1681  *                                                                            *
1682  * Parameters:                                                                *
1683  *                                                                            *
1684  * Author: Alexander Vladishev                                                *
1685  *                                                                            *
1686  * Comments:                                                                  *
1687  *                                                                            *
1688  ******************************************************************************/
get_event_update_history(const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid)1689 static void	get_event_update_history(const DB_EVENT *event, char **replace_to, const zbx_uint64_t *recipient_userid)
1690 {
1691 	DB_RESULT	result;
1692 	DB_ROW		row;
1693 	char		*buf = NULL;
1694 	size_t		buf_alloc = ZBX_KIBIBYTE, buf_offset = 0;
1695 
1696 	buf = (char *)zbx_malloc(buf, buf_alloc);
1697 	*buf = '\0';
1698 
1699 	result = DBselect("select clock,userid,message,action,old_severity,new_severity"
1700 			" from acknowledges"
1701 			" where eventid=" ZBX_FS_UI64 " order by clock",
1702 			event->eventid);
1703 
1704 	while (NULL != (row = DBfetch(result)))
1705 	{
1706 		const char	*user_name;
1707 		char		*actions = NULL;
1708 		DB_ACKNOWLEDGE	ack;
1709 
1710 		ack.clock = atoi(row[0]);
1711 		ZBX_STR2UINT64(ack.userid, row[1]);
1712 		ack.message = row[2];
1713 		ack.acknowledgeid = 0;
1714 		ack.action = atoi(row[3]);
1715 		ack.old_severity = atoi(row[4]);
1716 		ack.new_severity = atoi(row[5]);
1717 
1718 		if (SUCCEED == zbx_check_user_permissions(&ack.userid, recipient_userid))
1719 			user_name = zbx_user_string(ack.userid);
1720 		else
1721 			user_name = "Inaccessible user";
1722 
1723 		zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
1724 				"%s %s \"%s\"\n",
1725 				zbx_date2str(ack.clock),
1726 				zbx_time2str(ack.clock),
1727 				user_name);
1728 
1729 		if (SUCCEED == get_problem_update_actions(&ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
1730 					ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_SEVERITY, &actions))
1731 		{
1732 			zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "Actions: %s.\n", actions);
1733 			zbx_free(actions);
1734 		}
1735 
1736 		if ('\0' != *ack.message)
1737 			zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "%s\n", ack.message);
1738 
1739 		zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, '\n');
1740 	}
1741 	DBfree_result(result);
1742 
1743 	if (0 != buf_offset)
1744 	{
1745 		buf_offset -= 2;
1746 		buf[buf_offset] = '\0';
1747 	}
1748 
1749 	*replace_to = buf;
1750 }
1751 
1752 /******************************************************************************
1753  *                                                                            *
1754  * Function: get_autoreg_value_by_event                                       *
1755  *                                                                            *
1756  * Purpose: request value from autoreg_host table by event                    *
1757  *                                                                            *
1758  * Parameters:                                                                *
1759  *                                                                            *
1760  * Return value: upon successful completion return SUCCEED                    *
1761  *               otherwise FAIL                                               *
1762  *                                                                            *
1763  * Author: Alexander Vladishev                                                *
1764  *                                                                            *
1765  * Comments:                                                                  *
1766  *                                                                            *
1767  ******************************************************************************/
get_autoreg_value_by_event(const DB_EVENT * event,char ** replace_to,const char * fieldname)1768 static int	get_autoreg_value_by_event(const DB_EVENT *event, char **replace_to, const char *fieldname)
1769 {
1770 	DB_RESULT	result;
1771 	DB_ROW		row;
1772 	int		ret = FAIL;
1773 
1774 	result = DBselect(
1775 			"select %s"
1776 			" from autoreg_host"
1777 			" where autoreg_hostid=" ZBX_FS_UI64, fieldname, event->objectid);
1778 
1779 	if (NULL != (row = DBfetch(result)))
1780 	{
1781 		*replace_to = zbx_strdup(*replace_to, ZBX_NULL2STR(row[0]));
1782 		ret = SUCCEED;
1783 	}
1784 	DBfree_result(result);
1785 
1786 	return ret;
1787 }
1788 
1789 #define MVAR_ACTION			"{ACTION."			/* a prefix for all action macros */
1790 #define MVAR_ACTION_ID			MVAR_ACTION "ID}"
1791 #define MVAR_ACTION_NAME		MVAR_ACTION "NAME}"
1792 #define MVAR_DATE			"{DATE}"
1793 #define MVAR_EVENT			"{EVENT."			/* a prefix for all event macros */
1794 #define MVAR_EVENT_ACK_HISTORY		MVAR_EVENT "ACK.HISTORY}"	/* deprecated */
1795 #define MVAR_EVENT_ACK_STATUS		MVAR_EVENT "ACK.STATUS}"
1796 #define MVAR_EVENT_AGE			MVAR_EVENT "AGE}"
1797 #define MVAR_EVENT_DATE			MVAR_EVENT "DATE}"
1798 #define MVAR_EVENT_ID			MVAR_EVENT "ID}"
1799 #define MVAR_EVENT_NAME			MVAR_EVENT "NAME}"
1800 #define MVAR_EVENT_STATUS		MVAR_EVENT "STATUS}"
1801 #define MVAR_EVENT_TAGS			MVAR_EVENT "TAGS}"
1802 #define MVAR_EVENT_TIME			MVAR_EVENT "TIME}"
1803 #define MVAR_EVENT_VALUE		MVAR_EVENT "VALUE}"
1804 #define MVAR_EVENT_SEVERITY		MVAR_EVENT "SEVERITY}"
1805 #define MVAR_EVENT_NSEVERITY		MVAR_EVENT "NSEVERITY}"
1806 #define MVAR_EVENT_RECOVERY		MVAR_EVENT "RECOVERY."		/* a prefix for all recovery event macros */
1807 #define MVAR_EVENT_RECOVERY_DATE	MVAR_EVENT_RECOVERY "DATE}"
1808 #define MVAR_EVENT_RECOVERY_ID		MVAR_EVENT_RECOVERY "ID}"
1809 #define MVAR_EVENT_RECOVERY_STATUS	MVAR_EVENT_RECOVERY "STATUS}"	/* deprecated */
1810 #define MVAR_EVENT_RECOVERY_TAGS	MVAR_EVENT_RECOVERY "TAGS}"
1811 #define MVAR_EVENT_RECOVERY_TIME	MVAR_EVENT_RECOVERY "TIME}"
1812 #define MVAR_EVENT_RECOVERY_VALUE	MVAR_EVENT_RECOVERY "VALUE}"	/* deprecated */
1813 #define MVAR_EVENT_RECOVERY_NAME	MVAR_EVENT_RECOVERY "NAME}"
1814 #define MVAR_EVENT_UPDATE		MVAR_EVENT "UPDATE."
1815 #define MVAR_EVENT_UPDATE_ACTION	MVAR_EVENT_UPDATE "ACTION}"
1816 #define MVAR_EVENT_UPDATE_DATE		MVAR_EVENT_UPDATE "DATE}"
1817 #define MVAR_EVENT_UPDATE_HISTORY	MVAR_EVENT_UPDATE "HISTORY}"
1818 #define MVAR_EVENT_UPDATE_MESSAGE	MVAR_EVENT_UPDATE "MESSAGE}"
1819 #define MVAR_EVENT_UPDATE_TIME		MVAR_EVENT_UPDATE "TIME}"
1820 
1821 #define MVAR_ESC_HISTORY		"{ESC.HISTORY}"
1822 #define MVAR_PROXY_NAME			"{PROXY.NAME}"
1823 #define MVAR_PROXY_DESCRIPTION		"{PROXY.DESCRIPTION}"
1824 #define MVAR_HOST_DNS			"{HOST.DNS}"
1825 #define MVAR_HOST_CONN			"{HOST.CONN}"
1826 #define MVAR_HOST_HOST			"{HOST.HOST}"
1827 #define MVAR_HOST_ID			"{HOST.ID}"
1828 #define MVAR_HOST_IP			"{HOST.IP}"
1829 #define MVAR_IPADDRESS			"{IPADDRESS}"			/* deprecated */
1830 #define MVAR_HOST_METADATA		"{HOST.METADATA}"
1831 #define MVAR_HOST_NAME			"{HOST.NAME}"
1832 #define MVAR_HOSTNAME			"{HOSTNAME}"			/* deprecated */
1833 #define MVAR_HOST_DESCRIPTION		"{HOST.DESCRIPTION}"
1834 #define MVAR_HOST_PORT			"{HOST.PORT}"
1835 #define MVAR_TIME			"{TIME}"
1836 #define MVAR_ITEM_LASTVALUE		"{ITEM.LASTVALUE}"
1837 #define MVAR_ITEM_VALUE			"{ITEM.VALUE}"
1838 #define MVAR_ITEM_ID			"{ITEM.ID}"
1839 #define MVAR_ITEM_NAME			"{ITEM.NAME}"
1840 #define MVAR_ITEM_NAME_ORIG		"{ITEM.NAME.ORIG}"
1841 #define MVAR_ITEM_KEY			"{ITEM.KEY}"
1842 #define MVAR_ITEM_KEY_ORIG		"{ITEM.KEY.ORIG}"
1843 #define MVAR_ITEM_STATE			"{ITEM.STATE}"
1844 #define MVAR_TRIGGER_KEY		"{TRIGGER.KEY}"			/* deprecated */
1845 #define MVAR_ITEM_DESCRIPTION		"{ITEM.DESCRIPTION}"
1846 #define MVAR_ITEM_LOG_DATE		"{ITEM.LOG.DATE}"
1847 #define MVAR_ITEM_LOG_TIME		"{ITEM.LOG.TIME}"
1848 #define MVAR_ITEM_LOG_AGE		"{ITEM.LOG.AGE}"
1849 #define MVAR_ITEM_LOG_SOURCE		"{ITEM.LOG.SOURCE}"
1850 #define MVAR_ITEM_LOG_SEVERITY		"{ITEM.LOG.SEVERITY}"
1851 #define MVAR_ITEM_LOG_NSEVERITY		"{ITEM.LOG.NSEVERITY}"
1852 #define MVAR_ITEM_LOG_EVENTID		"{ITEM.LOG.EVENTID}"
1853 
1854 #define MVAR_TRIGGER_DESCRIPTION		"{TRIGGER.DESCRIPTION}"
1855 #define MVAR_TRIGGER_COMMENT			"{TRIGGER.COMMENT}"		/* deprecated */
1856 #define MVAR_TRIGGER_ID				"{TRIGGER.ID}"
1857 #define MVAR_TRIGGER_NAME			"{TRIGGER.NAME}"
1858 #define MVAR_TRIGGER_NAME_ORIG			"{TRIGGER.NAME.ORIG}"
1859 #define MVAR_TRIGGER_EXPRESSION			"{TRIGGER.EXPRESSION}"
1860 #define MVAR_TRIGGER_EXPRESSION_RECOVERY	"{TRIGGER.EXPRESSION.RECOVERY}"
1861 #define MVAR_TRIGGER_SEVERITY			"{TRIGGER.SEVERITY}"
1862 #define MVAR_TRIGGER_NSEVERITY			"{TRIGGER.NSEVERITY}"
1863 #define MVAR_TRIGGER_STATUS			"{TRIGGER.STATUS}"
1864 #define MVAR_TRIGGER_STATE			"{TRIGGER.STATE}"
1865 #define MVAR_TRIGGER_TEMPLATE_NAME		"{TRIGGER.TEMPLATE.NAME}"
1866 #define MVAR_TRIGGER_HOSTGROUP_NAME		"{TRIGGER.HOSTGROUP.NAME}"
1867 #define MVAR_STATUS				"{STATUS}"			/* deprecated */
1868 #define MVAR_TRIGGER_VALUE			"{TRIGGER.VALUE}"
1869 #define MVAR_TRIGGER_URL			"{TRIGGER.URL}"
1870 
1871 #define MVAR_TRIGGER_EVENTS_ACK			"{TRIGGER.EVENTS.ACK}"
1872 #define MVAR_TRIGGER_EVENTS_UNACK		"{TRIGGER.EVENTS.UNACK}"
1873 #define MVAR_TRIGGER_EVENTS_PROBLEM_ACK		"{TRIGGER.EVENTS.PROBLEM.ACK}"
1874 #define MVAR_TRIGGER_EVENTS_PROBLEM_UNACK	"{TRIGGER.EVENTS.PROBLEM.UNACK}"
1875 
1876 #define MVAR_LLDRULE_DESCRIPTION		"{LLDRULE.DESCRIPTION}"
1877 #define MVAR_LLDRULE_ID				"{LLDRULE.ID}"
1878 #define MVAR_LLDRULE_KEY			"{LLDRULE.KEY}"
1879 #define MVAR_LLDRULE_KEY_ORIG			"{LLDRULE.KEY.ORIG}"
1880 #define MVAR_LLDRULE_NAME			"{LLDRULE.NAME}"
1881 #define MVAR_LLDRULE_NAME_ORIG			"{LLDRULE.NAME.ORIG}"
1882 #define MVAR_LLDRULE_STATE			"{LLDRULE.STATE}"
1883 
1884 #define MVAR_INVENTORY				"{INVENTORY."			/* a prefix for all inventory macros */
1885 #define MVAR_INVENTORY_TYPE			MVAR_INVENTORY "TYPE}"
1886 #define MVAR_INVENTORY_TYPE_FULL		MVAR_INVENTORY "TYPE.FULL}"
1887 #define MVAR_INVENTORY_NAME			MVAR_INVENTORY "NAME}"
1888 #define MVAR_INVENTORY_ALIAS			MVAR_INVENTORY "ALIAS}"
1889 #define MVAR_INVENTORY_OS			MVAR_INVENTORY "OS}"
1890 #define MVAR_INVENTORY_OS_FULL			MVAR_INVENTORY "OS.FULL}"
1891 #define MVAR_INVENTORY_OS_SHORT			MVAR_INVENTORY "OS.SHORT}"
1892 #define MVAR_INVENTORY_SERIALNO_A		MVAR_INVENTORY "SERIALNO.A}"
1893 #define MVAR_INVENTORY_SERIALNO_B		MVAR_INVENTORY "SERIALNO.B}"
1894 #define MVAR_INVENTORY_TAG			MVAR_INVENTORY "TAG}"
1895 #define MVAR_INVENTORY_ASSET_TAG		MVAR_INVENTORY "ASSET.TAG}"
1896 #define MVAR_INVENTORY_MACADDRESS_A		MVAR_INVENTORY "MACADDRESS.A}"
1897 #define MVAR_INVENTORY_MACADDRESS_B		MVAR_INVENTORY "MACADDRESS.B}"
1898 #define MVAR_INVENTORY_HARDWARE			MVAR_INVENTORY "HARDWARE}"
1899 #define MVAR_INVENTORY_HARDWARE_FULL		MVAR_INVENTORY "HARDWARE.FULL}"
1900 #define MVAR_INVENTORY_SOFTWARE			MVAR_INVENTORY "SOFTWARE}"
1901 #define MVAR_INVENTORY_SOFTWARE_FULL		MVAR_INVENTORY "SOFTWARE.FULL}"
1902 #define MVAR_INVENTORY_SOFTWARE_APP_A		MVAR_INVENTORY "SOFTWARE.APP.A}"
1903 #define MVAR_INVENTORY_SOFTWARE_APP_B		MVAR_INVENTORY "SOFTWARE.APP.B}"
1904 #define MVAR_INVENTORY_SOFTWARE_APP_C		MVAR_INVENTORY "SOFTWARE.APP.C}"
1905 #define MVAR_INVENTORY_SOFTWARE_APP_D		MVAR_INVENTORY "SOFTWARE.APP.D}"
1906 #define MVAR_INVENTORY_SOFTWARE_APP_E		MVAR_INVENTORY "SOFTWARE.APP.E}"
1907 #define MVAR_INVENTORY_CONTACT			MVAR_INVENTORY "CONTACT}"
1908 #define MVAR_INVENTORY_LOCATION			MVAR_INVENTORY "LOCATION}"
1909 #define MVAR_INVENTORY_LOCATION_LAT		MVAR_INVENTORY "LOCATION.LAT}"
1910 #define MVAR_INVENTORY_LOCATION_LON		MVAR_INVENTORY "LOCATION.LON}"
1911 #define MVAR_INVENTORY_NOTES			MVAR_INVENTORY "NOTES}"
1912 #define MVAR_INVENTORY_CHASSIS			MVAR_INVENTORY "CHASSIS}"
1913 #define MVAR_INVENTORY_MODEL			MVAR_INVENTORY "MODEL}"
1914 #define MVAR_INVENTORY_HW_ARCH			MVAR_INVENTORY "HW.ARCH}"
1915 #define MVAR_INVENTORY_VENDOR			MVAR_INVENTORY "VENDOR}"
1916 #define MVAR_INVENTORY_CONTRACT_NUMBER		MVAR_INVENTORY "CONTRACT.NUMBER}"
1917 #define MVAR_INVENTORY_INSTALLER_NAME		MVAR_INVENTORY "INSTALLER.NAME}"
1918 #define MVAR_INVENTORY_DEPLOYMENT_STATUS	MVAR_INVENTORY "DEPLOYMENT.STATUS}"
1919 #define MVAR_INVENTORY_URL_A			MVAR_INVENTORY "URL.A}"
1920 #define MVAR_INVENTORY_URL_B			MVAR_INVENTORY "URL.B}"
1921 #define MVAR_INVENTORY_URL_C			MVAR_INVENTORY "URL.C}"
1922 #define MVAR_INVENTORY_HOST_NETWORKS		MVAR_INVENTORY "HOST.NETWORKS}"
1923 #define MVAR_INVENTORY_HOST_NETMASK		MVAR_INVENTORY "HOST.NETMASK}"
1924 #define MVAR_INVENTORY_HOST_ROUTER		MVAR_INVENTORY "HOST.ROUTER}"
1925 #define MVAR_INVENTORY_OOB_IP			MVAR_INVENTORY "OOB.IP}"
1926 #define MVAR_INVENTORY_OOB_NETMASK		MVAR_INVENTORY "OOB.NETMASK}"
1927 #define MVAR_INVENTORY_OOB_ROUTER		MVAR_INVENTORY "OOB.ROUTER}"
1928 #define MVAR_INVENTORY_HW_DATE_PURCHASE		MVAR_INVENTORY "HW.DATE.PURCHASE}"
1929 #define MVAR_INVENTORY_HW_DATE_INSTALL		MVAR_INVENTORY "HW.DATE.INSTALL}"
1930 #define MVAR_INVENTORY_HW_DATE_EXPIRY		MVAR_INVENTORY "HW.DATE.EXPIRY}"
1931 #define MVAR_INVENTORY_HW_DATE_DECOMM		MVAR_INVENTORY "HW.DATE.DECOMM}"
1932 #define MVAR_INVENTORY_SITE_ADDRESS_A		MVAR_INVENTORY "SITE.ADDRESS.A}"
1933 #define MVAR_INVENTORY_SITE_ADDRESS_B		MVAR_INVENTORY "SITE.ADDRESS.B}"
1934 #define MVAR_INVENTORY_SITE_ADDRESS_C		MVAR_INVENTORY "SITE.ADDRESS.C}"
1935 #define MVAR_INVENTORY_SITE_CITY		MVAR_INVENTORY "SITE.CITY}"
1936 #define MVAR_INVENTORY_SITE_STATE		MVAR_INVENTORY "SITE.STATE}"
1937 #define MVAR_INVENTORY_SITE_COUNTRY		MVAR_INVENTORY "SITE.COUNTRY}"
1938 #define MVAR_INVENTORY_SITE_ZIP			MVAR_INVENTORY "SITE.ZIP}"
1939 #define MVAR_INVENTORY_SITE_RACK		MVAR_INVENTORY "SITE.RACK}"
1940 #define MVAR_INVENTORY_SITE_NOTES		MVAR_INVENTORY "SITE.NOTES}"
1941 #define MVAR_INVENTORY_POC_PRIMARY_NAME		MVAR_INVENTORY "POC.PRIMARY.NAME}"
1942 #define MVAR_INVENTORY_POC_PRIMARY_EMAIL	MVAR_INVENTORY "POC.PRIMARY.EMAIL}"
1943 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_A	MVAR_INVENTORY "POC.PRIMARY.PHONE.A}"
1944 #define MVAR_INVENTORY_POC_PRIMARY_PHONE_B	MVAR_INVENTORY "POC.PRIMARY.PHONE.B}"
1945 #define MVAR_INVENTORY_POC_PRIMARY_CELL		MVAR_INVENTORY "POC.PRIMARY.CELL}"
1946 #define MVAR_INVENTORY_POC_PRIMARY_SCREEN	MVAR_INVENTORY "POC.PRIMARY.SCREEN}"
1947 #define MVAR_INVENTORY_POC_PRIMARY_NOTES	MVAR_INVENTORY "POC.PRIMARY.NOTES}"
1948 #define MVAR_INVENTORY_POC_SECONDARY_NAME	MVAR_INVENTORY "POC.SECONDARY.NAME}"
1949 #define MVAR_INVENTORY_POC_SECONDARY_EMAIL	MVAR_INVENTORY "POC.SECONDARY.EMAIL}"
1950 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_A	MVAR_INVENTORY "POC.SECONDARY.PHONE.A}"
1951 #define MVAR_INVENTORY_POC_SECONDARY_PHONE_B	MVAR_INVENTORY "POC.SECONDARY.PHONE.B}"
1952 #define MVAR_INVENTORY_POC_SECONDARY_CELL	MVAR_INVENTORY "POC.SECONDARY.CELL}"
1953 #define MVAR_INVENTORY_POC_SECONDARY_SCREEN	MVAR_INVENTORY "POC.SECONDARY.SCREEN}"
1954 #define MVAR_INVENTORY_POC_SECONDARY_NOTES	MVAR_INVENTORY "POC.SECONDARY.NOTES}"
1955 
1956 /* PROFILE.* is deprecated, use INVENTORY.* instead */
1957 #define MVAR_PROFILE			"{PROFILE."			/* prefix for profile macros */
1958 #define MVAR_PROFILE_DEVICETYPE		MVAR_PROFILE "DEVICETYPE}"
1959 #define MVAR_PROFILE_NAME		MVAR_PROFILE "NAME}"
1960 #define MVAR_PROFILE_OS			MVAR_PROFILE "OS}"
1961 #define MVAR_PROFILE_SERIALNO		MVAR_PROFILE "SERIALNO}"
1962 #define MVAR_PROFILE_TAG		MVAR_PROFILE "TAG}"
1963 #define MVAR_PROFILE_MACADDRESS		MVAR_PROFILE "MACADDRESS}"
1964 #define MVAR_PROFILE_HARDWARE		MVAR_PROFILE "HARDWARE}"
1965 #define MVAR_PROFILE_SOFTWARE		MVAR_PROFILE "SOFTWARE}"
1966 #define MVAR_PROFILE_CONTACT		MVAR_PROFILE "CONTACT}"
1967 #define MVAR_PROFILE_LOCATION		MVAR_PROFILE "LOCATION}"
1968 #define MVAR_PROFILE_NOTES		MVAR_PROFILE "NOTES}"
1969 
1970 #define MVAR_DISCOVERY_RULE_NAME	"{DISCOVERY.RULE.NAME}"
1971 #define MVAR_DISCOVERY_SERVICE_NAME	"{DISCOVERY.SERVICE.NAME}"
1972 #define MVAR_DISCOVERY_SERVICE_PORT	"{DISCOVERY.SERVICE.PORT}"
1973 #define MVAR_DISCOVERY_SERVICE_STATUS	"{DISCOVERY.SERVICE.STATUS}"
1974 #define MVAR_DISCOVERY_SERVICE_UPTIME	"{DISCOVERY.SERVICE.UPTIME}"
1975 #define MVAR_DISCOVERY_DEVICE_IPADDRESS	"{DISCOVERY.DEVICE.IPADDRESS}"
1976 #define MVAR_DISCOVERY_DEVICE_DNS	"{DISCOVERY.DEVICE.DNS}"
1977 #define MVAR_DISCOVERY_DEVICE_STATUS	"{DISCOVERY.DEVICE.STATUS}"
1978 #define MVAR_DISCOVERY_DEVICE_UPTIME	"{DISCOVERY.DEVICE.UPTIME}"
1979 
1980 #define MVAR_ALERT_SENDTO		"{ALERT.SENDTO}"
1981 #define MVAR_ALERT_SUBJECT		"{ALERT.SUBJECT}"
1982 #define MVAR_ALERT_MESSAGE		"{ALERT.MESSAGE}"
1983 
1984 #define MVAR_ACK_MESSAGE                "{ACK.MESSAGE}"			/* deprecated */
1985 #define MVAR_ACK_TIME	                "{ACK.TIME}"			/* deprecated */
1986 #define MVAR_ACK_DATE	                "{ACK.DATE}"			/* deprecated */
1987 #define MVAR_USER_FULLNAME          	"{USER.FULLNAME}"
1988 
1989 #define STR_UNKNOWN_VARIABLE		"*UNKNOWN*"
1990 
1991 /* macros that can be indexed */
1992 static const char	*ex_macros[] =
1993 {
1994 	MVAR_INVENTORY_TYPE, MVAR_INVENTORY_TYPE_FULL,
1995 	MVAR_INVENTORY_NAME, MVAR_INVENTORY_ALIAS, MVAR_INVENTORY_OS, MVAR_INVENTORY_OS_FULL, MVAR_INVENTORY_OS_SHORT,
1996 	MVAR_INVENTORY_SERIALNO_A, MVAR_INVENTORY_SERIALNO_B, MVAR_INVENTORY_TAG,
1997 	MVAR_INVENTORY_ASSET_TAG, MVAR_INVENTORY_MACADDRESS_A, MVAR_INVENTORY_MACADDRESS_B,
1998 	MVAR_INVENTORY_HARDWARE, MVAR_INVENTORY_HARDWARE_FULL, MVAR_INVENTORY_SOFTWARE, MVAR_INVENTORY_SOFTWARE_FULL,
1999 	MVAR_INVENTORY_SOFTWARE_APP_A, MVAR_INVENTORY_SOFTWARE_APP_B, MVAR_INVENTORY_SOFTWARE_APP_C,
2000 	MVAR_INVENTORY_SOFTWARE_APP_D, MVAR_INVENTORY_SOFTWARE_APP_E, MVAR_INVENTORY_CONTACT, MVAR_INVENTORY_LOCATION,
2001 	MVAR_INVENTORY_LOCATION_LAT, MVAR_INVENTORY_LOCATION_LON, MVAR_INVENTORY_NOTES, MVAR_INVENTORY_CHASSIS,
2002 	MVAR_INVENTORY_MODEL, MVAR_INVENTORY_HW_ARCH, MVAR_INVENTORY_VENDOR, MVAR_INVENTORY_CONTRACT_NUMBER,
2003 	MVAR_INVENTORY_INSTALLER_NAME, MVAR_INVENTORY_DEPLOYMENT_STATUS, MVAR_INVENTORY_URL_A, MVAR_INVENTORY_URL_B,
2004 	MVAR_INVENTORY_URL_C, MVAR_INVENTORY_HOST_NETWORKS, MVAR_INVENTORY_HOST_NETMASK, MVAR_INVENTORY_HOST_ROUTER,
2005 	MVAR_INVENTORY_OOB_IP, MVAR_INVENTORY_OOB_NETMASK, MVAR_INVENTORY_OOB_ROUTER, MVAR_INVENTORY_HW_DATE_PURCHASE,
2006 	MVAR_INVENTORY_HW_DATE_INSTALL, MVAR_INVENTORY_HW_DATE_EXPIRY, MVAR_INVENTORY_HW_DATE_DECOMM,
2007 	MVAR_INVENTORY_SITE_ADDRESS_A, MVAR_INVENTORY_SITE_ADDRESS_B, MVAR_INVENTORY_SITE_ADDRESS_C,
2008 	MVAR_INVENTORY_SITE_CITY, MVAR_INVENTORY_SITE_STATE, MVAR_INVENTORY_SITE_COUNTRY, MVAR_INVENTORY_SITE_ZIP,
2009 	MVAR_INVENTORY_SITE_RACK, MVAR_INVENTORY_SITE_NOTES, MVAR_INVENTORY_POC_PRIMARY_NAME,
2010 	MVAR_INVENTORY_POC_PRIMARY_EMAIL, MVAR_INVENTORY_POC_PRIMARY_PHONE_A, MVAR_INVENTORY_POC_PRIMARY_PHONE_B,
2011 	MVAR_INVENTORY_POC_PRIMARY_CELL, MVAR_INVENTORY_POC_PRIMARY_SCREEN, MVAR_INVENTORY_POC_PRIMARY_NOTES,
2012 	MVAR_INVENTORY_POC_SECONDARY_NAME, MVAR_INVENTORY_POC_SECONDARY_EMAIL, MVAR_INVENTORY_POC_SECONDARY_PHONE_A,
2013 	MVAR_INVENTORY_POC_SECONDARY_PHONE_B, MVAR_INVENTORY_POC_SECONDARY_CELL, MVAR_INVENTORY_POC_SECONDARY_SCREEN,
2014 	MVAR_INVENTORY_POC_SECONDARY_NOTES,
2015 	/* PROFILE.* is deprecated, use INVENTORY.* instead */
2016 	MVAR_PROFILE_DEVICETYPE, MVAR_PROFILE_NAME, MVAR_PROFILE_OS, MVAR_PROFILE_SERIALNO,
2017 	MVAR_PROFILE_TAG, MVAR_PROFILE_MACADDRESS, MVAR_PROFILE_HARDWARE, MVAR_PROFILE_SOFTWARE,
2018 	MVAR_PROFILE_CONTACT, MVAR_PROFILE_LOCATION, MVAR_PROFILE_NOTES,
2019 	MVAR_HOST_HOST, MVAR_HOSTNAME, MVAR_HOST_NAME, MVAR_HOST_DESCRIPTION, MVAR_PROXY_NAME, MVAR_PROXY_DESCRIPTION,
2020 	MVAR_HOST_CONN, MVAR_HOST_DNS, MVAR_HOST_IP, MVAR_HOST_PORT, MVAR_IPADDRESS, MVAR_HOST_ID,
2021 	MVAR_ITEM_ID, MVAR_ITEM_NAME, MVAR_ITEM_NAME_ORIG, MVAR_ITEM_DESCRIPTION,
2022 	MVAR_ITEM_KEY, MVAR_ITEM_KEY_ORIG, MVAR_TRIGGER_KEY,
2023 	MVAR_ITEM_LASTVALUE,
2024 	MVAR_ITEM_STATE,
2025 	MVAR_ITEM_VALUE,
2026 	MVAR_ITEM_LOG_DATE, MVAR_ITEM_LOG_TIME, MVAR_ITEM_LOG_AGE, MVAR_ITEM_LOG_SOURCE,
2027 	MVAR_ITEM_LOG_SEVERITY, MVAR_ITEM_LOG_NSEVERITY, MVAR_ITEM_LOG_EVENTID,
2028 	NULL
2029 };
2030 
2031 /* macros that are supported as simple macro host and item key */
2032 static const char	*simple_host_macros[] = {MVAR_HOST_HOST, MVAR_HOSTNAME, NULL};
2033 static const char	*simple_key_macros[] = {MVAR_ITEM_KEY, MVAR_TRIGGER_KEY, NULL};
2034 
2035 /* macros that can be modified using macro functions */
2036 static const char	*mod_macros[] = {MVAR_ITEM_VALUE, MVAR_ITEM_LASTVALUE, NULL};
2037 
2038 typedef struct
2039 {
2040 	const char	*macro;
2041 	int		idx;
2042 } inventory_field_t;
2043 
2044 static inventory_field_t	inventory_fields[] =
2045 {
2046 	{MVAR_INVENTORY_TYPE, 0},
2047 	{MVAR_PROFILE_DEVICETYPE, 0},	/* deprecated */
2048 	{MVAR_INVENTORY_TYPE_FULL, 1},
2049 	{MVAR_INVENTORY_NAME, 2},
2050 	{MVAR_PROFILE_NAME, 2},	/* deprecated */
2051 	{MVAR_INVENTORY_ALIAS, 3},
2052 	{MVAR_INVENTORY_OS, 4},
2053 	{MVAR_PROFILE_OS, 4},	/* deprecated */
2054 	{MVAR_INVENTORY_OS_FULL, 5},
2055 	{MVAR_INVENTORY_OS_SHORT, 6},
2056 	{MVAR_INVENTORY_SERIALNO_A, 7},
2057 	{MVAR_PROFILE_SERIALNO, 7},	/* deprecated */
2058 	{MVAR_INVENTORY_SERIALNO_B, 8},
2059 	{MVAR_INVENTORY_TAG, 9},
2060 	{MVAR_PROFILE_TAG, 9},	/* deprecated */
2061 	{MVAR_INVENTORY_ASSET_TAG, 10},
2062 	{MVAR_INVENTORY_MACADDRESS_A, 11},
2063 	{MVAR_PROFILE_MACADDRESS, 11},	/* deprecated */
2064 	{MVAR_INVENTORY_MACADDRESS_B, 12},
2065 	{MVAR_INVENTORY_HARDWARE, 13},
2066 	{MVAR_PROFILE_HARDWARE, 13},	/* deprecated */
2067 	{MVAR_INVENTORY_HARDWARE_FULL, 14},
2068 	{MVAR_INVENTORY_SOFTWARE, 15},
2069 	{MVAR_PROFILE_SOFTWARE, 15},	/* deprecated */
2070 	{MVAR_INVENTORY_SOFTWARE_FULL, 16},
2071 	{MVAR_INVENTORY_SOFTWARE_APP_A, 17},
2072 	{MVAR_INVENTORY_SOFTWARE_APP_B, 18},
2073 	{MVAR_INVENTORY_SOFTWARE_APP_C, 19},
2074 	{MVAR_INVENTORY_SOFTWARE_APP_D, 20},
2075 	{MVAR_INVENTORY_SOFTWARE_APP_E, 21},
2076 	{MVAR_INVENTORY_CONTACT, 22},
2077 	{MVAR_PROFILE_CONTACT, 22},	/* deprecated */
2078 	{MVAR_INVENTORY_LOCATION, 23},
2079 	{MVAR_PROFILE_LOCATION, 23},	/* deprecated */
2080 	{MVAR_INVENTORY_LOCATION_LAT, 24},
2081 	{MVAR_INVENTORY_LOCATION_LON, 25},
2082 	{MVAR_INVENTORY_NOTES, 26},
2083 	{MVAR_PROFILE_NOTES, 26},	/* deprecated */
2084 	{MVAR_INVENTORY_CHASSIS, 27},
2085 	{MVAR_INVENTORY_MODEL, 28},
2086 	{MVAR_INVENTORY_HW_ARCH, 29},
2087 	{MVAR_INVENTORY_VENDOR, 30},
2088 	{MVAR_INVENTORY_CONTRACT_NUMBER, 31},
2089 	{MVAR_INVENTORY_INSTALLER_NAME, 32},
2090 	{MVAR_INVENTORY_DEPLOYMENT_STATUS, 33},
2091 	{MVAR_INVENTORY_URL_A, 34},
2092 	{MVAR_INVENTORY_URL_B, 35},
2093 	{MVAR_INVENTORY_URL_C, 36},
2094 	{MVAR_INVENTORY_HOST_NETWORKS, 37},
2095 	{MVAR_INVENTORY_HOST_NETMASK, 38},
2096 	{MVAR_INVENTORY_HOST_ROUTER, 39},
2097 	{MVAR_INVENTORY_OOB_IP, 40},
2098 	{MVAR_INVENTORY_OOB_NETMASK, 41},
2099 	{MVAR_INVENTORY_OOB_ROUTER, 42},
2100 	{MVAR_INVENTORY_HW_DATE_PURCHASE, 43},
2101 	{MVAR_INVENTORY_HW_DATE_INSTALL, 44},
2102 	{MVAR_INVENTORY_HW_DATE_EXPIRY, 45},
2103 	{MVAR_INVENTORY_HW_DATE_DECOMM, 46},
2104 	{MVAR_INVENTORY_SITE_ADDRESS_A, 47},
2105 	{MVAR_INVENTORY_SITE_ADDRESS_B, 48},
2106 	{MVAR_INVENTORY_SITE_ADDRESS_C, 49},
2107 	{MVAR_INVENTORY_SITE_CITY, 50},
2108 	{MVAR_INVENTORY_SITE_STATE, 51},
2109 	{MVAR_INVENTORY_SITE_COUNTRY, 52},
2110 	{MVAR_INVENTORY_SITE_ZIP, 53},
2111 	{MVAR_INVENTORY_SITE_RACK, 54},
2112 	{MVAR_INVENTORY_SITE_NOTES, 55},
2113 	{MVAR_INVENTORY_POC_PRIMARY_NAME, 56},
2114 	{MVAR_INVENTORY_POC_PRIMARY_EMAIL, 57},
2115 	{MVAR_INVENTORY_POC_PRIMARY_PHONE_A, 58},
2116 	{MVAR_INVENTORY_POC_PRIMARY_PHONE_B, 59},
2117 	{MVAR_INVENTORY_POC_PRIMARY_CELL, 60},
2118 	{MVAR_INVENTORY_POC_PRIMARY_SCREEN, 61},
2119 	{MVAR_INVENTORY_POC_PRIMARY_NOTES, 62},
2120 	{MVAR_INVENTORY_POC_SECONDARY_NAME, 63},
2121 	{MVAR_INVENTORY_POC_SECONDARY_EMAIL, 64},
2122 	{MVAR_INVENTORY_POC_SECONDARY_PHONE_A, 65},
2123 	{MVAR_INVENTORY_POC_SECONDARY_PHONE_B, 66},
2124 	{MVAR_INVENTORY_POC_SECONDARY_CELL, 67},
2125 	{MVAR_INVENTORY_POC_SECONDARY_SCREEN, 68},
2126 	{MVAR_INVENTORY_POC_SECONDARY_NOTES, 69},
2127 	{NULL}
2128 };
2129 
2130 /******************************************************************************
2131  *                                                                            *
2132  * Function: get_action_value                                                 *
2133  *                                                                            *
2134  * Purpose: request action value by macro                                     *
2135  *                                                                            *
2136  * Return value: upon successful completion return SUCCEED                    *
2137  *               otherwise FAIL                                               *
2138  *                                                                            *
2139  ******************************************************************************/
get_action_value(const char * macro,zbx_uint64_t actionid,char ** replace_to)2140 static int	get_action_value(const char *macro, zbx_uint64_t actionid, char **replace_to)
2141 {
2142 	int	ret = SUCCEED;
2143 
2144 	if (0 == strcmp(macro, MVAR_ACTION_ID))
2145 	{
2146 		*replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, actionid);
2147 	}
2148 	else if (0 == strcmp(macro, MVAR_ACTION_NAME))
2149 	{
2150 		DB_RESULT	result;
2151 		DB_ROW		row;
2152 
2153 		result = DBselect("select name from actions where actionid=" ZBX_FS_UI64, actionid);
2154 
2155 		if (NULL != (row = DBfetch(result)))
2156 			*replace_to = zbx_strdup(*replace_to, row[0]);
2157 		else
2158 			ret = FAIL;
2159 
2160 		DBfree_result(result);
2161 	}
2162 
2163 	return ret;
2164 }
2165 
2166 /******************************************************************************
2167  *                                                                            *
2168  * Function: get_host_inventory                                               *
2169  *                                                                            *
2170  * Purpose: request host inventory value by macro and trigger                 *
2171  *                                                                            *
2172  * Return value: upon successful completion return SUCCEED                    *
2173  *               otherwise FAIL                                               *
2174  *                                                                            *
2175  ******************************************************************************/
get_host_inventory(const char * macro,const char * expression,char ** replace_to,int N_functionid)2176 static int	get_host_inventory(const char *macro, const char *expression, char **replace_to,
2177 		int N_functionid)
2178 {
2179 	int	i;
2180 
2181 	for (i = 0; NULL != inventory_fields[i].macro; i++)
2182 	{
2183 		if (0 == strcmp(macro, inventory_fields[i].macro))
2184 		{
2185 			zbx_uint64_t	itemid;
2186 
2187 			if (SUCCEED != get_N_itemid(expression, N_functionid, &itemid))
2188 				return FAIL;
2189 
2190 			return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
2191 		}
2192 	}
2193 
2194 	return FAIL;
2195 }
2196 
2197 /******************************************************************************
2198  *                                                                            *
2199  * Function: get_host_inventory_by_itemid                                     *
2200  *                                                                            *
2201  * Purpose: request host inventory value by macro and itemid                  *
2202  *                                                                            *
2203  * Return value: upon successful completion return SUCCEED                    *
2204  *               otherwise FAIL                                               *
2205  *                                                                            *
2206  ******************************************************************************/
get_host_inventory_by_itemid(const char * macro,zbx_uint64_t itemid,char ** replace_to)2207 static int	get_host_inventory_by_itemid(const char *macro, zbx_uint64_t itemid, char **replace_to)
2208 {
2209 	int	i;
2210 
2211 	for (i = 0; NULL != inventory_fields[i].macro; i++)
2212 	{
2213 		if (0 == strcmp(macro, inventory_fields[i].macro))
2214 			return DCget_host_inventory_value_by_itemid(itemid, replace_to, inventory_fields[i].idx);
2215 	}
2216 
2217 	return FAIL;
2218 }
2219 
2220 /******************************************************************************
2221  *                                                                            *
2222  * Function: compare_tags                                                     *
2223  *                                                                            *
2224  * Purpose: comparison function to sort tags by tag/value                     *
2225  *                                                                            *
2226  ******************************************************************************/
compare_tags(const void * d1,const void * d2)2227 static int	compare_tags(const void *d1, const void *d2)
2228 {
2229 	int	ret;
2230 
2231 	const zbx_tag_t	*tag1 = *(const zbx_tag_t **)d1;
2232 	const zbx_tag_t	*tag2 = *(const zbx_tag_t **)d2;
2233 
2234 	if (0 == (ret = zbx_strcmp_natural(tag1->tag, tag2->tag)))
2235 		ret = zbx_strcmp_natural(tag1->value, tag2->value);
2236 
2237 	return ret;
2238 }
2239 
2240 /******************************************************************************
2241  *                                                                            *
2242  * Function: get_event_tags                                                   *
2243  *                                                                            *
2244  * Purpose: format event tags string in format <tag1>[:<value1>], ...         *
2245  *                                                                            *
2246  * Parameters: event        [IN] the event                                    *
2247  *             replace_to - [OUT] replacement string                          *
2248  *                                                                            *
2249  ******************************************************************************/
get_event_tags(const DB_EVENT * event,char ** replace_to)2250 static void	get_event_tags(const DB_EVENT *event, char **replace_to)
2251 {
2252 	size_t			replace_to_offset = 0, replace_to_alloc = 0;
2253 	int			i;
2254 	zbx_vector_ptr_t	tags;
2255 
2256 	if (0 == event->tags.values_num)
2257 	{
2258 		*replace_to = zbx_strdup(*replace_to, "");
2259 		return;
2260 	}
2261 
2262 	zbx_free(*replace_to);
2263 
2264 	/* copy tags to temporary vector for sorting */
2265 
2266 	zbx_vector_ptr_create(&tags);
2267 	zbx_vector_ptr_reserve(&tags, event->tags.values_num);
2268 
2269 	for (i = 0; i < event->tags.values_num; i++)
2270 		zbx_vector_ptr_append(&tags, event->tags.values[i]);
2271 
2272 	zbx_vector_ptr_sort(&tags, compare_tags);
2273 
2274 	for (i = 0; i < tags.values_num; i++)
2275 	{
2276 		const zbx_tag_t	*tag = (const zbx_tag_t *)tags.values[i];
2277 
2278 		if (0 != i)
2279 			zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ", ");
2280 
2281 		zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->tag);
2282 
2283 		if ('\0' != *tag->value)
2284 		{
2285 			zbx_chrcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, ':');
2286 			zbx_strcpy_alloc(replace_to, &replace_to_alloc, &replace_to_offset, tag->value);
2287 		}
2288 	}
2289 
2290 	zbx_vector_ptr_destroy(&tags);
2291 }
2292 
2293 /******************************************************************************
2294  *                                                                            *
2295  * Function: get_recovery_event_value                                         *
2296  *                                                                            *
2297  * Purpose: request recovery event value by macro                             *
2298  *                                                                            *
2299  ******************************************************************************/
get_recovery_event_value(const char * macro,const DB_EVENT * r_event,char ** replace_to)2300 static void	get_recovery_event_value(const char *macro, const DB_EVENT *r_event, char **replace_to)
2301 {
2302 	if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_DATE))
2303 	{
2304 		*replace_to = zbx_strdup(*replace_to, zbx_date2str(r_event->clock));
2305 	}
2306 	else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_ID))
2307 	{
2308 		*replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, r_event->eventid);
2309 	}
2310 	else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_STATUS))
2311 	{
2312 		*replace_to = zbx_strdup(*replace_to,
2313 				zbx_event_value_string(r_event->source, r_event->object, r_event->value));
2314 	}
2315 	else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_TIME))
2316 	{
2317 		*replace_to = zbx_strdup(*replace_to, zbx_time2str(r_event->clock));
2318 	}
2319 	else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_VALUE))
2320 	{
2321 		*replace_to = zbx_dsprintf(*replace_to, "%d", r_event->value);
2322 	}
2323 	else if (EVENT_SOURCE_TRIGGERS == r_event->source && 0 == strcmp(macro, MVAR_EVENT_RECOVERY_TAGS))
2324 	{
2325 		get_event_tags(r_event, replace_to);
2326 	}
2327 	else if (0 == strcmp(macro, MVAR_EVENT_RECOVERY_NAME))
2328 	{
2329 		*replace_to = zbx_dsprintf(*replace_to, "%s", r_event->name);
2330 	}
2331 }
2332 
2333 /******************************************************************************
2334  *                                                                            *
2335  * Function: get_current_event_value                                          *
2336  *                                                                            *
2337  * Purpose: request current event value by macro                              *
2338  *                                                                            *
2339  ******************************************************************************/
get_current_event_value(const char * macro,const DB_EVENT * event,char ** replace_to)2340 static void	get_current_event_value(const char *macro, const DB_EVENT *event, char **replace_to)
2341 {
2342 	if (0 == strcmp(macro, MVAR_EVENT_STATUS))
2343 	{
2344 		*replace_to = zbx_strdup(*replace_to,
2345 				zbx_event_value_string(event->source, event->object, event->value));
2346 	}
2347 	else if (0 == strcmp(macro, MVAR_EVENT_VALUE))
2348 	{
2349 		*replace_to = zbx_dsprintf(*replace_to, "%d", event->value);
2350 	}
2351 }
2352 
2353 /******************************************************************************
2354  *                                                                            *
2355  * Function: get_event_value                                                  *
2356  *                                                                            *
2357  * Purpose: request event value by macro                                      *
2358  *                                                                            *
2359  ******************************************************************************/
get_event_value(const char * macro,const DB_EVENT * event,char ** replace_to,const zbx_uint64_t * recipient_userid)2360 static void	get_event_value(const char *macro, const DB_EVENT *event, char **replace_to,
2361 			const zbx_uint64_t *recipient_userid)
2362 {
2363 	if (0 == strcmp(macro, MVAR_EVENT_AGE))
2364 	{
2365 		*replace_to = zbx_strdup(*replace_to, zbx_age2str(time(NULL) - event->clock));
2366 	}
2367 	else if (0 == strcmp(macro, MVAR_EVENT_DATE))
2368 	{
2369 		*replace_to = zbx_strdup(*replace_to, zbx_date2str(event->clock));
2370 	}
2371 	else if (0 == strcmp(macro, MVAR_EVENT_ID))
2372 	{
2373 		*replace_to = zbx_dsprintf(*replace_to, ZBX_FS_UI64, event->eventid);
2374 	}
2375 	else if (0 == strcmp(macro, MVAR_EVENT_TIME))
2376 	{
2377 		*replace_to = zbx_strdup(*replace_to, zbx_time2str(event->clock));
2378 	}
2379 	else if (EVENT_SOURCE_TRIGGERS == event->source)
2380 	{
2381 		if (0 == strcmp(macro, MVAR_EVENT_ACK_HISTORY) || 0 == strcmp(macro, MVAR_EVENT_UPDATE_HISTORY))
2382 		{
2383 			get_event_update_history(event, replace_to, recipient_userid);
2384 		}
2385 		else if (0 == strcmp(macro, MVAR_EVENT_ACK_STATUS))
2386 		{
2387 			*replace_to = zbx_strdup(*replace_to, event->acknowledged ? "Yes" : "No");
2388 		}
2389 		else if (0 == strcmp(macro, MVAR_EVENT_TAGS))
2390 		{
2391 			get_event_tags(event, replace_to);
2392 		}
2393 		else if (0 == strcmp(macro, MVAR_EVENT_NSEVERITY))
2394 		{
2395 			*replace_to = zbx_dsprintf(*replace_to, "%d", (int)event->severity);
2396 		}
2397 		else if (0 == strcmp(macro, MVAR_EVENT_SEVERITY))
2398 		{
2399 			if (FAIL == get_trigger_severity_name(event->severity, replace_to))
2400 				*replace_to = zbx_strdup(*replace_to, "unknown");
2401 		}
2402 	}
2403 }
2404 
2405 /******************************************************************************
2406  *                                                                            *
2407  * Function: is_indexed_macro                                                 *
2408  *                                                                            *
2409  * Purpose: check if a token contains indexed macro                           *
2410  *                                                                            *
2411  ******************************************************************************/
is_indexed_macro(const char * str,const zbx_token_t * token)2412 static int	is_indexed_macro(const char *str, const zbx_token_t *token)
2413 {
2414 	const char	*p;
2415 
2416 	switch (token->type)
2417 	{
2418 		case ZBX_TOKEN_MACRO:
2419 			p = str + token->loc.r - 1;
2420 			break;
2421 		case ZBX_TOKEN_FUNC_MACRO:
2422 			p = str + token->data.func_macro.macro.r - 1;
2423 			break;
2424 		default:
2425 			THIS_SHOULD_NEVER_HAPPEN;
2426 			return FAIL;
2427 	}
2428 
2429 	return '1' <= *p && *p <= '9' ? 1 : 0;
2430 }
2431 
2432 /******************************************************************************
2433  *                                                                            *
2434  * Function: macro_in_list                                                    *
2435  *                                                                            *
2436  * Purpose: check if a macro in string is one of the list and extract index   *
2437  *                                                                            *
2438  * Parameters: str          - [IN] string containing potential macro          *
2439  *             strloc       - [IN] part of the string to check                *
2440  *             macros       - [IN] list of allowed macros (without indices)   *
2441  *             N_functionid - [OUT] index of the macro in string (if valid)   *
2442  *                                                                            *
2443  * Return value: unindexed macro from the allowed list or NULL                *
2444  *                                                                            *
2445  * Comments: example: N_functionid is untouched if function returns NULL, for *
2446  *           a valid unindexed macro N_function is 1.                         *
2447  *                                                                            *
2448  ******************************************************************************/
macro_in_list(const char * str,zbx_strloc_t strloc,const char ** macros,int * N_functionid)2449 static const char	*macro_in_list(const char *str, zbx_strloc_t strloc, const char **macros, int *N_functionid)
2450 {
2451 	const char	**macro, *m;
2452 	size_t		i;
2453 
2454 	for (macro = macros; NULL != *macro; macro++)
2455 	{
2456 		for (m = *macro, i = strloc.l; '\0' != *m && i <= strloc.r && str[i] == *m; m++, i++)
2457 			;
2458 
2459 		/* check whether macro has ended while strloc hasn't or vice-versa */
2460 		if (('\0' == *m && i <= strloc.r) || ('\0' != *m && i > strloc.r))
2461 			continue;
2462 
2463 		/* strloc either fully matches macro... */
2464 		if ('\0' == *m)
2465 		{
2466 			if (NULL != N_functionid)
2467 				*N_functionid = 1;
2468 
2469 			break;
2470 		}
2471 
2472 		/* ...or there is a mismatch, check if it's in a pre-last character and it's an index */
2473 		if (i == strloc.r - 1 && '1' <= str[i] && str[i] <= '9' && str[i + 1] == *m && '\0' == *(m + 1))
2474 		{
2475 			if (NULL != N_functionid)
2476 				*N_functionid = str[i] - '0';
2477 
2478 			break;
2479 		}
2480 	}
2481 
2482 	return *macro;
2483 }
2484 
2485 /******************************************************************************
2486  *                                                                            *
2487  * Function: get_trigger_function_value                                       *
2488  *                                                                            *
2489  * Purpose: trying to evaluate a trigger function                             *
2490  *                                                                            *
2491  * Parameters: expression - [IN] trigger expression, source of hostnames and  *
2492  *                            item keys for {HOST.HOST} and {ITEM.KEY} macros *
2493  *             replace_to - [OUT] evaluation result                           *
2494  *             data       - [IN] string containing simple macro               *
2495  *             macro      - [IN] simple macro token location in string        *
2496  *                                                                            *
2497  * Return value: SUCCEED - successfully evaluated or invalid macro(s) in host *
2498  *                           and/or item key positions (in the latter case    *
2499  *                           replace_to remains unchanged and simple macro    *
2500  *                           shouldn't be replaced with anything)             *
2501  *               FAIL    - evaluation failed and macro has to be replaced     *
2502  *                           with STR_UNKNOWN_VARIABLE ("*UNKNOWN*")          *
2503  *                                                                            *
2504  * Author: Alexander Vladishev                                                *
2505  *                                                                            *
2506  * Comments: example: " {Zabbix server:{ITEM.KEY1}.last(0)} " to " 1.34 "     *
2507  *                                                                            *
2508  ******************************************************************************/
get_trigger_function_value(const char * expression,char ** replace_to,char * data,const zbx_token_simple_macro_t * simple_macro)2509 static int	get_trigger_function_value(const char *expression, char **replace_to, char *data,
2510 		const zbx_token_simple_macro_t *simple_macro)
2511 {
2512 	char	*host = NULL, *key = NULL;
2513 	int	N_functionid, ret = FAIL;
2514 
2515 	if (NULL != macro_in_list(data, simple_macro->host, simple_host_macros, &N_functionid))
2516 	{
2517 		if (SUCCEED != DBget_trigger_value(expression, &host, N_functionid, ZBX_REQUEST_HOST_HOST))
2518 			goto out;
2519 	}
2520 
2521 	if (NULL != macro_in_list(data, simple_macro->key, simple_key_macros, &N_functionid))
2522 	{
2523 		if (SUCCEED != DBget_trigger_value(expression, &key, N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG))
2524 			goto out;
2525 	}
2526 
2527 	data[simple_macro->host.r + 1] = '\0';
2528 	data[simple_macro->key.r + 1] = '\0';
2529 	data[simple_macro->func_param.l] = '\0';
2530 	data[simple_macro->func_param.r] = '\0';
2531 
2532 	ret = evaluate_macro_function(replace_to, (NULL == host ? data + simple_macro->host.l : host),
2533 			(NULL == key ? data + simple_macro->key.l : key), data + simple_macro->func.l,
2534 			data + simple_macro->func_param.l + 1);
2535 
2536 	data[simple_macro->host.r + 1] = ':';
2537 	data[simple_macro->key.r + 1] = '.';
2538 	data[simple_macro->func_param.l] = '(';
2539 	data[simple_macro->func_param.r] = ')';
2540 out:
2541 	zbx_free(host);
2542 	zbx_free(key);
2543 
2544 	return ret;
2545 }
2546 
2547 /******************************************************************************
2548  *                                                                            *
2549  * Function: cache_trigger_hostids                                            *
2550  *                                                                            *
2551  * Purpose: cache host identifiers referenced by trigger expression           *
2552  *                                                                            *
2553  * Parameters: hostids             - [OUT] the host identifier cache          *
2554  *             expression          - [IN] the trigger expression              *
2555  *             recovery_expression - [IN] the trigger recovery expression     *
2556  *                                        (can be empty)                      *
2557  *                                                                            *
2558  ******************************************************************************/
cache_trigger_hostids(zbx_vector_uint64_t * hostids,const char * expression,const char * recovery_expression)2559 static void	cache_trigger_hostids(zbx_vector_uint64_t *hostids, const char *expression,
2560 		const char *recovery_expression)
2561 {
2562 	if (0 == hostids->values_num)
2563 	{
2564 		zbx_vector_uint64_t	functionids;
2565 
2566 		zbx_vector_uint64_create(&functionids);
2567 		get_functionids(&functionids, expression);
2568 		get_functionids(&functionids, recovery_expression);
2569 		DCget_hostids_by_functionids(&functionids, hostids);
2570 		zbx_vector_uint64_destroy(&functionids);
2571 	}
2572 }
2573 
2574 /******************************************************************************
2575  *                                                                            *
2576  * Function: cache_item_hostid                                                *
2577  *                                                                            *
2578  * Purpose: cache host identifier referenced by an item or a lld-rule         *
2579  *                                                                            *
2580  * Parameters: hostids - [OUT] the host identifier cache                      *
2581  *             itemid  - [IN]  the item identifier                            *
2582  *                                                                            *
2583  ******************************************************************************/
cache_item_hostid(zbx_vector_uint64_t * hostids,zbx_uint64_t itemid)2584 static void	cache_item_hostid(zbx_vector_uint64_t *hostids, zbx_uint64_t itemid)
2585 {
2586 	if (0 == hostids->values_num)
2587 	{
2588 		DC_ITEM	item;
2589 		int	errcode;
2590 
2591 		DCconfig_get_items_by_itemids(&item, &itemid, &errcode, 1);
2592 
2593 		if (SUCCEED == errcode)
2594 			zbx_vector_uint64_append(hostids, item.host.hostid);
2595 
2596 		DCconfig_clean_items(&item, &errcode, 1);
2597 	}
2598 }
2599 
2600 /******************************************************************************
2601  *                                                                            *
2602  * Function: wrap_negative_double_suffix                                      *
2603  *                                                                            *
2604  * Purpose: wrap a replacement string that represents a negative number in    *
2605  *          parentheses (for instance, turn "-123.456M" into "(-123.456M)")   *
2606  *                                                                            *
2607  * Parameters: replace_to       - [IN/OUT] replacement string                 *
2608  *             replace_to_alloc - [IN/OUT] number of allocated bytes          *
2609  *                                                                            *
2610  ******************************************************************************/
wrap_negative_double_suffix(char ** replace_to,size_t * replace_to_alloc)2611 static void	wrap_negative_double_suffix(char **replace_to, size_t *replace_to_alloc)
2612 {
2613 	size_t	replace_to_len;
2614 
2615 	if ('-' != (*replace_to)[0])
2616 		return;
2617 
2618 	replace_to_len = strlen(*replace_to);
2619 
2620 	if (NULL != replace_to_alloc && *replace_to_alloc >= replace_to_len + 3)
2621 	{
2622 		memmove(*replace_to + 1, *replace_to, replace_to_len);
2623 	}
2624 	else
2625 	{
2626 		char	*buffer;
2627 
2628 		if (NULL != replace_to_alloc)
2629 			*replace_to_alloc = replace_to_len + 3;
2630 
2631 		buffer = (char *)zbx_malloc(NULL, replace_to_len + 3);
2632 
2633 		memcpy(buffer + 1, *replace_to, replace_to_len);
2634 
2635 		zbx_free(*replace_to);
2636 		*replace_to = buffer;
2637 	}
2638 
2639 	(*replace_to)[0] = '(';
2640 	(*replace_to)[replace_to_len + 1] = ')';
2641 	(*replace_to)[replace_to_len + 2] = '\0';
2642 }
2643 
zbx_dobject_status2str(int st)2644 static const char	*zbx_dobject_status2str(int st)
2645 {
2646 	switch (st)
2647 	{
2648 		case DOBJECT_STATUS_UP:
2649 			return "UP";
2650 		case DOBJECT_STATUS_DOWN:
2651 			return "DOWN";
2652 		case DOBJECT_STATUS_DISCOVER:
2653 			return "DISCOVERED";
2654 		case DOBJECT_STATUS_LOST:
2655 			return "LOST";
2656 		default:
2657 			return "UNKNOWN";
2658 	}
2659 }
2660 
2661 /******************************************************************************
2662  *                                                                            *
2663  * Function: substitute_simple_macros                                         *
2664  *                                                                            *
2665  * Purpose: substitute simple macros in data string with real values          *
2666  *                                                                            *
2667  * Author: Eugene Grigorjev                                                   *
2668  *                                                                            *
2669  ******************************************************************************/
substitute_simple_macros(zbx_uint64_t * actionid,const DB_EVENT * event,const DB_EVENT * r_event,zbx_uint64_t * userid,const zbx_uint64_t * hostid,const DC_HOST * dc_host,const DC_ITEM * dc_item,DB_ALERT * alert,const DB_ACKNOWLEDGE * ack,char ** data,int macro_type,char * error,int maxerrlen)2670 int	substitute_simple_macros(zbx_uint64_t *actionid, const DB_EVENT *event, const DB_EVENT *r_event,
2671 		zbx_uint64_t *userid, const zbx_uint64_t *hostid, const DC_HOST *dc_host, const DC_ITEM *dc_item,
2672 		DB_ALERT *alert, const DB_ACKNOWLEDGE *ack, char **data, int macro_type, char *error, int maxerrlen)
2673 {
2674 	const char		*__function_name = "substitute_simple_macros";
2675 
2676 	char			c, *replace_to = NULL, sql[64];
2677 	const char		*m, *replace = NULL;
2678 	int			N_functionid, indexed_macro, require_numeric, require_address, ret, res = SUCCEED,
2679 				pos = 0, found,
2680 				raw_value;
2681 	size_t			data_alloc, data_len, replace_len;
2682 	DC_INTERFACE		interface;
2683 	zbx_vector_uint64_t	hostids;
2684 	zbx_token_t		token;
2685 	zbx_token_search_t	token_search;
2686 	char			*expression = NULL;
2687 
2688 	if (NULL == data || NULL == *data || '\0' == **data)
2689 	{
2690 		zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:EMPTY", __function_name);
2691 		return res;
2692 	}
2693 
2694 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
2695 
2696 	if (0 != (macro_type & MACRO_TYPE_TRIGGER_DESCRIPTION))
2697 		token_search = ZBX_TOKEN_SEARCH_REFERENCES;
2698 	else
2699 		token_search = ZBX_TOKEN_SEARCH_BASIC;
2700 
2701 	if (SUCCEED != zbx_token_find(*data, pos, &token, token_search))
2702 		return res;
2703 
2704 	zbx_vector_uint64_create(&hostids);
2705 
2706 	data_alloc = data_len = strlen(*data) + 1;
2707 
2708 	for (found = SUCCEED; SUCCEED == res && SUCCEED == found;
2709 			found = zbx_token_find(*data, pos, &token, token_search))
2710 	{
2711 		indexed_macro = 0;
2712 		require_numeric = 0;
2713 		require_address = 0;
2714 		N_functionid = 1;
2715 		raw_value = 0;
2716 		pos = token.loc.l;
2717 
2718 		switch (token.type)
2719 		{
2720 			case ZBX_TOKEN_OBJECTID:
2721 			case ZBX_TOKEN_LLD_MACRO:
2722 			case ZBX_TOKEN_LLD_FUNC_MACRO:
2723 				/* neither lld or {123123} macros are processed by this function, skip them */
2724 				pos = token.loc.r + 1;
2725 				continue;
2726 			case ZBX_TOKEN_MACRO:
2727 				if (0 == (indexed_macro = is_indexed_macro(*data, &token)))
2728 				{
2729 					/* Theoretically we could do m = macro_in_list() here as well to validate */
2730 					/* token and get unindexed macro equivalent, but it will be a double work */
2731 					/* since we will pass m through a lot of strcmp(m, MVAR_*) checks anyway, */
2732 					/* plus ex_macros is a long list. For now, we rely on this surgery. */
2733 					m = *data + token.loc.l;
2734 					c = (*data)[token.loc.r + 1];
2735 					(*data)[token.loc.r + 1] = '\0';
2736 				}
2737 				else if (NULL == (m = macro_in_list(*data, token.loc, ex_macros, &N_functionid)))
2738 				{
2739 					pos = token.loc.r + 1;
2740 					continue;
2741 				}
2742 				break;
2743 			case ZBX_TOKEN_FUNC_MACRO:
2744 				raw_value = 1;
2745 				indexed_macro = is_indexed_macro(*data, &token);
2746 				if (NULL == (m = macro_in_list(*data, token.data.func_macro.macro, mod_macros,
2747 						&N_functionid)))
2748 				{
2749 					/* Ignore functions with macros not supporting them, but do not skip the */
2750 					/* whole token, nested macro should be resolved in this case. */
2751 					pos++;
2752 					continue;
2753 				}
2754 				break;
2755 			case ZBX_TOKEN_USER_MACRO:
2756 				/* To avoid *data modification DCget_user_macro() should be replaced with a function */
2757 				/* that takes initial *data string and token.data.user_macro instead of m as params. */
2758 				m = *data + token.loc.l;
2759 				c = (*data)[token.loc.r + 1];
2760 				(*data)[token.loc.r + 1] = '\0';
2761 				break;
2762 			case ZBX_TOKEN_SIMPLE_MACRO:
2763 				if (0 == (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2764 							MACRO_TYPE_MESSAGE_ACK)) ||
2765 						EVENT_SOURCE_TRIGGERS != ((NULL != r_event) ? r_event : event)->source)
2766 				{
2767 					pos++;
2768 					continue;
2769 				}
2770 				/* These macros (and probably all other in the future) must be resolved using only */
2771 				/* information stored in token.data union. For now, force crash if they rely on m. */
2772 				m = NULL;
2773 				break;
2774 			case ZBX_TOKEN_REFERENCE:
2775 				/* These macros (and probably all other in the future) must be resolved using only */
2776 				/* information stored in token.data union. For now, force crash if they rely on m. */
2777 				m = NULL;
2778 				break;
2779 			default:
2780 				THIS_SHOULD_NEVER_HAPPEN;
2781 				res = FAIL;
2782 				continue;
2783 		}
2784 
2785 		ret = SUCCEED;
2786 
2787 		if (0 != (macro_type & (MACRO_TYPE_MESSAGE_NORMAL | MACRO_TYPE_MESSAGE_RECOVERY |
2788 				MACRO_TYPE_MESSAGE_ACK)))
2789 		{
2790 			const DB_EVENT	*c_event;
2791 
2792 			c_event = ((NULL != r_event) ? r_event : event);
2793 
2794 			if (EVENT_SOURCE_TRIGGERS == c_event->source)
2795 			{
2796 				if (ZBX_TOKEN_USER_MACRO == token.type)
2797 				{
2798 					cache_trigger_hostids(&hostids, c_event->trigger.expression,
2799 							c_event->trigger.recovery_expression);
2800 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
2801 					pos = token.loc.r;
2802 				}
2803 				else if (ZBX_TOKEN_SIMPLE_MACRO == token.type)
2804 				{
2805 					ret = get_trigger_function_value(c_event->trigger.expression, &replace_to,
2806 							*data, &token.data.simple_macro);
2807 				}
2808 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
2809 				{
2810 					ret = get_action_value(m, *actionid, &replace_to);
2811 				}
2812 				else if (0 == strcmp(m, MVAR_DATE))
2813 				{
2814 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
2815 				}
2816 				else if (0 == strcmp(m, MVAR_ESC_HISTORY))
2817 				{
2818 					get_escalation_history(*actionid, event, r_event, &replace_to, userid);
2819 				}
2820 				else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
2821 				{
2822 					if (NULL != r_event)
2823 						get_recovery_event_value(m, r_event, &replace_to);
2824 				}
2825 				else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
2826 				{
2827 					get_current_event_value(m, c_event, &replace_to);
2828 				}
2829 				else if (0 == strcmp(m, MVAR_EVENT_NAME))
2830 				{
2831 					replace_to = zbx_strdup(replace_to, event->name);
2832 				}
2833 				else if (0 == strcmp(m, MVAR_ACK_MESSAGE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_MESSAGE))
2834 				{
2835 					if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2836 						replace_to = zbx_strdup(replace_to, ack->message);
2837 				}
2838 				else if (0 == strcmp(m, MVAR_ACK_TIME) || 0 == strcmp(m, MVAR_EVENT_UPDATE_TIME))
2839 				{
2840 					if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2841 						replace_to = zbx_strdup(replace_to, zbx_time2str(ack->clock));
2842 				}
2843 				else if (0 == strcmp(m, MVAR_ACK_DATE) || 0 == strcmp(m, MVAR_EVENT_UPDATE_DATE))
2844 				{
2845 					if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2846 						replace_to = zbx_strdup(replace_to, zbx_date2str(ack->clock));
2847 				}
2848 				else if (0 == strcmp(m, MVAR_EVENT_UPDATE_ACTION))
2849 				{
2850 					if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
2851 					{
2852 						get_problem_update_actions(ack, ZBX_PROBLEM_UPDATE_ACKNOWLEDGE |
2853 								ZBX_PROBLEM_UPDATE_CLOSE | ZBX_PROBLEM_UPDATE_MESSAGE |
2854 								ZBX_PROBLEM_UPDATE_SEVERITY, &replace_to);
2855 					}
2856 				}
2857 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
2858 				{
2859 					get_event_value(m, event, &replace_to, userid);
2860 				}
2861 				else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
2862 				{
2863 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2864 							N_functionid, ZBX_REQUEST_HOST_HOST);
2865 				}
2866 				else if (0 == strcmp(m, MVAR_HOST_NAME))
2867 				{
2868 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2869 							N_functionid, ZBX_REQUEST_HOST_NAME);
2870 				}
2871 				else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
2872 				{
2873 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2874 							N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
2875 				}
2876 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
2877 				{
2878 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2879 							N_functionid, ZBX_REQUEST_HOST_IP);
2880 				}
2881 				else if (0 == strcmp(m, MVAR_HOST_DNS))
2882 				{
2883 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2884 							N_functionid, ZBX_REQUEST_HOST_DNS);
2885 				}
2886 				else if (0 == strcmp(m, MVAR_HOST_CONN))
2887 				{
2888 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2889 							N_functionid, ZBX_REQUEST_HOST_CONN);
2890 				}
2891 				else if (0 == strcmp(m, MVAR_HOST_PORT))
2892 				{
2893 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2894 							N_functionid, ZBX_REQUEST_HOST_PORT);
2895 				}
2896 				else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
2897 						0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
2898 				{
2899 					ret = get_host_inventory(m, c_event->trigger.expression, &replace_to,
2900 							N_functionid);
2901 				}
2902 				else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
2903 				{
2904 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2905 							N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
2906 				}
2907 				else if (0 == strcmp(m, MVAR_ITEM_ID))
2908 				{
2909 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2910 							N_functionid, ZBX_REQUEST_ITEM_ID);
2911 				}
2912 				else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
2913 				{
2914 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2915 							N_functionid, ZBX_REQUEST_ITEM_KEY);
2916 				}
2917 				else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
2918 				{
2919 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2920 							N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
2921 				}
2922 				else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
2923 				{
2924 					ret = DBitem_lastvalue(c_event->trigger.expression, &replace_to, N_functionid,
2925 							raw_value);
2926 				}
2927 				else if (0 == strcmp(m, MVAR_ITEM_LOG_AGE))
2928 				{
2929 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2930 							N_functionid, ZBX_REQUEST_ITEM_LOG_AGE, c_event->clock,
2931 							c_event->ns);
2932 				}
2933 				else if (0 == strcmp(m, MVAR_ITEM_LOG_DATE))
2934 				{
2935 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2936 							N_functionid, ZBX_REQUEST_ITEM_LOG_DATE, c_event->clock,
2937 							c_event->ns);
2938 				}
2939 				else if (0 == strcmp(m, MVAR_ITEM_LOG_EVENTID))
2940 				{
2941 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2942 							N_functionid, ZBX_REQUEST_ITEM_LOG_EVENTID, c_event->clock,
2943 							c_event->ns);
2944 				}
2945 				else if (0 == strcmp(m, MVAR_ITEM_LOG_NSEVERITY))
2946 				{
2947 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2948 							N_functionid, ZBX_REQUEST_ITEM_LOG_NSEVERITY, c_event->clock,
2949 							c_event->ns);
2950 				}
2951 				else if (0 == strcmp(m, MVAR_ITEM_LOG_SEVERITY))
2952 				{
2953 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2954 							N_functionid, ZBX_REQUEST_ITEM_LOG_SEVERITY, c_event->clock,
2955 							c_event->ns);
2956 				}
2957 				else if (0 == strcmp(m, MVAR_ITEM_LOG_SOURCE))
2958 				{
2959 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2960 							N_functionid, ZBX_REQUEST_ITEM_LOG_SOURCE, c_event->clock,
2961 							c_event->ns);
2962 				}
2963 				else if (0 == strcmp(m, MVAR_ITEM_LOG_TIME))
2964 				{
2965 					ret = get_history_log_value(c_event->trigger.expression, &replace_to,
2966 							N_functionid, ZBX_REQUEST_ITEM_LOG_TIME, c_event->clock,
2967 							c_event->ns);
2968 				}
2969 				else if (0 == strcmp(m, MVAR_ITEM_NAME))
2970 				{
2971 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2972 							N_functionid, ZBX_REQUEST_ITEM_NAME);
2973 				}
2974 				else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
2975 				{
2976 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2977 							N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
2978 				}
2979 				else if (0 == strcmp(m, MVAR_ITEM_VALUE))
2980 				{
2981 					ret = DBitem_value(c_event->trigger.expression, &replace_to, N_functionid,
2982 							c_event->clock, c_event->ns, raw_value);
2983 				}
2984 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
2985 				{
2986 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2987 							N_functionid, ZBX_REQUEST_PROXY_NAME);
2988 				}
2989 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
2990 				{
2991 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
2992 							N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
2993 				}
2994 				else if (0 == strcmp(m, MVAR_TIME))
2995 				{
2996 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
2997 				}
2998 				else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
2999 						0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3000 				{
3001 					replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3002 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3003 							NULL, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3004 							maxerrlen);
3005 				}
3006 				else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_ACK))
3007 				{
3008 					ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 1);
3009 				}
3010 				else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_ACK))
3011 				{
3012 					ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 1);
3013 				}
3014 				else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_PROBLEM_UNACK))
3015 				{
3016 					ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 1, 0);
3017 				}
3018 				else if (0 == strcmp(m, MVAR_TRIGGER_EVENTS_UNACK))
3019 				{
3020 					ret = DBget_trigger_event_count(c_event->objectid, &replace_to, 0, 0);
3021 				}
3022 				else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3023 				{
3024 					replace_to = zbx_strdup(replace_to, c_event->trigger.expression);
3025 					DCexpand_trigger_expression(&replace_to);
3026 				}
3027 				else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3028 				{
3029 					if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3030 					{
3031 						replace_to = zbx_strdup(replace_to,
3032 								c_event->trigger.recovery_expression);
3033 						DCexpand_trigger_expression(&replace_to);
3034 					}
3035 					else
3036 						replace_to = zbx_strdup(replace_to, "");
3037 				}
3038 				else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3039 				{
3040 					ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3041 				}
3042 				else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3043 				{
3044 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3045 				}
3046 				else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3047 				{
3048 					replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3049 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3050 							NULL, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3051 							maxerrlen);
3052 				}
3053 				else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3054 				{
3055 					replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3056 				}
3057 				else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3058 				{
3059 					replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3060 				}
3061 				else if (0 == strcmp(m, MVAR_TRIGGER_STATUS) || 0 == strcmp(m, MVAR_STATUS))
3062 				{
3063 					replace_to = zbx_strdup(replace_to,
3064 							zbx_trigger_value_string(c_event->trigger.value));
3065 				}
3066 				else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3067 				{
3068 					ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3069 				}
3070 				else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3071 				{
3072 					ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3073 				}
3074 				else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3075 				{
3076 					replace_to = zbx_strdup(replace_to, c_event->trigger.url);
3077 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3078 							NULL, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3079 				}
3080 				else if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
3081 				{
3082 					replace_to = zbx_dsprintf(replace_to, "%d", c_event->trigger.value);
3083 				}
3084 				else if (0 == strcmp(m, MVAR_USER_FULLNAME))
3085 				{
3086 					if (0 != (macro_type & MACRO_TYPE_MESSAGE_ACK) && NULL != ack)
3087 					{
3088 						const char	*user_name;
3089 
3090 						if (SUCCEED == zbx_check_user_permissions(&ack->userid, userid))
3091 							user_name = zbx_user_string(ack->userid);
3092 						else
3093 							user_name = "Inaccessible user";
3094 
3095 						replace_to = zbx_strdup(replace_to, user_name);
3096 					}
3097 				}
3098 			}
3099 			else if (EVENT_SOURCE_INTERNAL == c_event->source && EVENT_OBJECT_TRIGGER == c_event->object)
3100 			{
3101 				if (ZBX_TOKEN_USER_MACRO == token.type)
3102 				{
3103 					cache_trigger_hostids(&hostids, c_event->trigger.expression,
3104 							c_event->trigger.recovery_expression);
3105 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3106 					pos = token.loc.r;
3107 				}
3108 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3109 				{
3110 					ret = get_action_value(m, *actionid, &replace_to);
3111 				}
3112 				else if (0 == strcmp(m, MVAR_DATE))
3113 				{
3114 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3115 				}
3116 				else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3117 				{
3118 					get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3119 				}
3120 				else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3121 				{
3122 					if (NULL != r_event)
3123 						get_recovery_event_value(m, r_event, &replace_to);
3124 				}
3125 				else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3126 				{
3127 					get_current_event_value(m, c_event, &replace_to);
3128 				}
3129 				else if (0 == strcmp(m, MVAR_EVENT_NAME))
3130 				{
3131 					replace_to = zbx_strdup(replace_to, event->name);
3132 				}
3133 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3134 				{
3135 					get_event_value(m, event, &replace_to, userid);
3136 				}
3137 				else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3138 				{
3139 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3140 							N_functionid, ZBX_REQUEST_HOST_HOST);
3141 				}
3142 				else if (0 == strcmp(m, MVAR_HOST_NAME))
3143 				{
3144 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3145 							N_functionid, ZBX_REQUEST_HOST_NAME);
3146 				}
3147 				else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3148 				{
3149 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3150 							N_functionid, ZBX_REQUEST_HOST_DESCRIPTION);
3151 				}
3152 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3153 				{
3154 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3155 							N_functionid, ZBX_REQUEST_HOST_IP);
3156 				}
3157 				else if (0 == strcmp(m, MVAR_HOST_DNS))
3158 				{
3159 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3160 							N_functionid, ZBX_REQUEST_HOST_DNS);
3161 				}
3162 				else if (0 == strcmp(m, MVAR_HOST_CONN))
3163 				{
3164 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3165 							N_functionid, ZBX_REQUEST_HOST_CONN);
3166 				}
3167 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3168 				{
3169 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3170 							N_functionid, ZBX_REQUEST_HOST_PORT);
3171 				}
3172 				else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3173 						0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3174 				{
3175 					ret = get_host_inventory(m, c_event->trigger.expression, &replace_to,
3176 							N_functionid);
3177 				}
3178 				else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3179 				{
3180 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3181 							N_functionid, ZBX_REQUEST_ITEM_DESCRIPTION);
3182 				}
3183 				else if (0 == strcmp(m, MVAR_ITEM_ID))
3184 				{
3185 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3186 							N_functionid, ZBX_REQUEST_ITEM_ID);
3187 				}
3188 				else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3189 				{
3190 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3191 							N_functionid, ZBX_REQUEST_ITEM_KEY);
3192 				}
3193 				else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3194 				{
3195 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3196 							N_functionid, ZBX_REQUEST_ITEM_KEY_ORIG);
3197 				}
3198 				else if (0 == strcmp(m, MVAR_ITEM_NAME))
3199 				{
3200 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3201 							N_functionid, ZBX_REQUEST_ITEM_NAME);
3202 				}
3203 				else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3204 				{
3205 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3206 							N_functionid, ZBX_REQUEST_ITEM_NAME_ORIG);
3207 				}
3208 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
3209 				{
3210 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3211 							N_functionid, ZBX_REQUEST_PROXY_NAME);
3212 				}
3213 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3214 				{
3215 					ret = DBget_trigger_value(c_event->trigger.expression, &replace_to,
3216 							N_functionid, ZBX_REQUEST_PROXY_DESCRIPTION);
3217 				}
3218 				else if (0 == strcmp(m, MVAR_TIME))
3219 				{
3220 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3221 				}
3222 				else if (0 == strcmp(m, MVAR_TRIGGER_DESCRIPTION) ||
3223 						0 == strcmp(m, MVAR_TRIGGER_COMMENT))
3224 				{
3225 					replace_to = zbx_strdup(replace_to, c_event->trigger.comments);
3226 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3227 							NULL, &replace_to, MACRO_TYPE_TRIGGER_COMMENTS, error,
3228 							maxerrlen);
3229 				}
3230 				else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION))
3231 				{
3232 					replace_to = zbx_strdup(replace_to, c_event->trigger.expression);
3233 					DCexpand_trigger_expression(&replace_to);
3234 				}
3235 				else if (0 == strcmp(m, MVAR_TRIGGER_EXPRESSION_RECOVERY))
3236 				{
3237 					if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == c_event->trigger.recovery_mode)
3238 					{
3239 						replace_to = zbx_strdup(replace_to,
3240 								c_event->trigger.recovery_expression);
3241 						DCexpand_trigger_expression(&replace_to);
3242 					}
3243 					else
3244 						replace_to = zbx_strdup(replace_to, "");
3245 				}
3246 				else if (0 == strcmp(m, MVAR_TRIGGER_HOSTGROUP_NAME))
3247 				{
3248 					ret = DBget_trigger_hostgroup_name(c_event->objectid, userid, &replace_to);
3249 				}
3250 				else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3251 				{
3252 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3253 				}
3254 				else if (0 == strcmp(m, MVAR_TRIGGER_NAME))
3255 				{
3256 					replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3257 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3258 							NULL, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION, error,
3259 							maxerrlen);
3260 				}
3261 				else if (0 == strcmp(m, MVAR_TRIGGER_NAME_ORIG))
3262 				{
3263 					replace_to = zbx_strdup(replace_to, c_event->trigger.description);
3264 				}
3265 				else if (0 == strcmp(m, MVAR_TRIGGER_NSEVERITY))
3266 				{
3267 					replace_to = zbx_dsprintf(replace_to, "%d", (int)c_event->trigger.priority);
3268 				}
3269 				else if (0 == strcmp(m, MVAR_TRIGGER_SEVERITY))
3270 				{
3271 					ret = get_trigger_severity_name(c_event->trigger.priority, &replace_to);
3272 				}
3273 				else if (0 == strcmp(m, MVAR_TRIGGER_STATE))
3274 				{
3275 					replace_to = zbx_strdup(replace_to, zbx_trigger_state_string(c_event->value));
3276 				}
3277 				else if (0 == strcmp(m, MVAR_TRIGGER_TEMPLATE_NAME))
3278 				{
3279 					ret = DBget_trigger_template_name(c_event->objectid, userid, &replace_to);
3280 				}
3281 				else if (0 == strcmp(m, MVAR_TRIGGER_URL))
3282 				{
3283 					replace_to = zbx_strdup(replace_to, c_event->trigger.url);
3284 					substitute_simple_macros(NULL, c_event, NULL, NULL, NULL, NULL, NULL, NULL,
3285 							NULL, &replace_to, MACRO_TYPE_TRIGGER_URL, error, maxerrlen);
3286 				}
3287 			}
3288 			else if (0 == indexed_macro && EVENT_SOURCE_DISCOVERY == c_event->source)
3289 			{
3290 				if (ZBX_TOKEN_USER_MACRO == token.type)
3291 				{
3292 					DCget_user_macro(NULL, 0, m, &replace_to);
3293 					pos = token.loc.r;
3294 				}
3295 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3296 				{
3297 					ret = get_action_value(m, *actionid, &replace_to);
3298 				}
3299 				else if (0 == strcmp(m, MVAR_DATE))
3300 				{
3301 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3302 				}
3303 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3304 				{
3305 					get_event_value(m, event, &replace_to, userid);
3306 				}
3307 				else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_IPADDRESS))
3308 				{
3309 					ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.ip");
3310 				}
3311 				else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_DNS))
3312 				{
3313 					ret = DBget_dhost_value_by_event(c_event, &replace_to, "s.dns");
3314 				}
3315 				else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_STATUS))
3316 				{
3317 					if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3318 							"h.status")))
3319 					{
3320 						replace_to = zbx_strdup(replace_to,
3321 								zbx_dobject_status2str(atoi(replace_to)));
3322 					}
3323 				}
3324 				else if (0 == strcmp(m, MVAR_DISCOVERY_DEVICE_UPTIME))
3325 				{
3326 					zbx_snprintf(sql, sizeof(sql),
3327 							"case when h.status=%d then h.lastup else h.lastdown end",
3328 							DOBJECT_STATUS_UP);
3329 					if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to, sql)))
3330 					{
3331 						replace_to = zbx_strdup(replace_to,
3332 								zbx_age2str(time(NULL) - atoi(replace_to)));
3333 					}
3334 				}
3335 				else if (0 == strcmp(m, MVAR_DISCOVERY_RULE_NAME))
3336 				{
3337 					ret = DBget_drule_value_by_event(c_event, &replace_to, "name");
3338 				}
3339 				else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_NAME))
3340 				{
3341 					if (SUCCEED == (ret = DBget_dchecks_value_by_event(c_event, &replace_to,
3342 							"c.type")))
3343 					{
3344 						replace_to = zbx_strdup(replace_to,
3345 								zbx_dservice_type_string(atoi(replace_to)));
3346 					}
3347 				}
3348 				else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_PORT))
3349 				{
3350 					ret = DBget_dservice_value_by_event(c_event, &replace_to, "s.port");
3351 				}
3352 				else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_STATUS))
3353 				{
3354 					if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to,
3355 							"s.status")))
3356 					{
3357 						replace_to = zbx_strdup(replace_to,
3358 								zbx_dobject_status2str(atoi(replace_to)));
3359 					}
3360 				}
3361 				else if (0 == strcmp(m, MVAR_DISCOVERY_SERVICE_UPTIME))
3362 				{
3363 					zbx_snprintf(sql, sizeof(sql),
3364 							"case when s.status=%d then s.lastup else s.lastdown end",
3365 							DOBJECT_STATUS_UP);
3366 					if (SUCCEED == (ret = DBget_dservice_value_by_event(c_event, &replace_to, sql)))
3367 					{
3368 						replace_to = zbx_strdup(replace_to,
3369 								zbx_age2str(time(NULL) - atoi(replace_to)));
3370 					}
3371 				}
3372 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
3373 				{
3374 					if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3375 							"r.proxy_hostid")))
3376 					{
3377 						zbx_uint64_t	proxy_hostid;
3378 
3379 						ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3380 
3381 						if (0 == proxy_hostid)
3382 							replace_to = zbx_strdup(replace_to, "");
3383 						else
3384 							ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3385 					}
3386 				}
3387 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3388 				{
3389 					if (SUCCEED == (ret = DBget_dhost_value_by_event(c_event, &replace_to,
3390 							"r.proxy_hostid")))
3391 					{
3392 						zbx_uint64_t	proxy_hostid;
3393 
3394 						ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3395 
3396 						if (0 == proxy_hostid)
3397 						{
3398 							replace_to = zbx_strdup(replace_to, "");
3399 						}
3400 						else
3401 						{
3402 							ret = DBget_host_value(proxy_hostid, &replace_to,
3403 									"description");
3404 						}
3405 					}
3406 				}
3407 				else if (0 == strcmp(m, MVAR_TIME))
3408 				{
3409 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3410 				}
3411 			}
3412 			else if (0 == indexed_macro && EVENT_SOURCE_AUTOREGISTRATION == c_event->source)
3413 			{
3414 				if (ZBX_TOKEN_USER_MACRO == token.type)
3415 				{
3416 					DCget_user_macro(NULL, 0, m, &replace_to);
3417 					pos = token.loc.r;
3418 				}
3419 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3420 				{
3421 					ret = get_action_value(m, *actionid, &replace_to);
3422 				}
3423 				else if (0 == strcmp(m, MVAR_DATE))
3424 				{
3425 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3426 				}
3427 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3428 				{
3429 					get_event_value(m, event, &replace_to, userid);
3430 				}
3431 				else if (0 == strcmp(m, MVAR_HOST_METADATA))
3432 				{
3433 					ret = get_autoreg_value_by_event(c_event, &replace_to, "host_metadata");
3434 				}
3435 				else if (0 == strcmp(m, MVAR_HOST_HOST))
3436 				{
3437 					ret = get_autoreg_value_by_event(c_event, &replace_to, "host");
3438 				}
3439 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3440 				{
3441 					ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_ip");
3442 				}
3443 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3444 				{
3445 					ret = get_autoreg_value_by_event(c_event, &replace_to, "listen_port");
3446 				}
3447 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
3448 				{
3449 					if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3450 							"proxy_hostid")))
3451 					{
3452 						zbx_uint64_t	proxy_hostid;
3453 
3454 						ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3455 
3456 						if (0 == proxy_hostid)
3457 							replace_to = zbx_strdup(replace_to, "");
3458 						else
3459 							ret = DBget_host_value(proxy_hostid, &replace_to, "host");
3460 					}
3461 				}
3462 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3463 				{
3464 					if (SUCCEED == (ret = get_autoreg_value_by_event(c_event, &replace_to,
3465 							"proxy_hostid")))
3466 					{
3467 						zbx_uint64_t	proxy_hostid;
3468 
3469 						ZBX_DBROW2UINT64(proxy_hostid, replace_to);
3470 
3471 						if (0 == proxy_hostid)
3472 						{
3473 							replace_to = zbx_strdup(replace_to, "");
3474 						}
3475 						else
3476 						{
3477 							ret = DBget_host_value(proxy_hostid, &replace_to,
3478 									"description");
3479 						}
3480 					}
3481 				}
3482 				else if (0 == strcmp(m, MVAR_TIME))
3483 				{
3484 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3485 				}
3486 			}
3487 			else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3488 					EVENT_OBJECT_ITEM == c_event->object)
3489 			{
3490 				if (ZBX_TOKEN_USER_MACRO == token.type)
3491 				{
3492 					cache_item_hostid(&hostids, c_event->objectid);
3493 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3494 					pos = token.loc.r;
3495 				}
3496 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3497 				{
3498 					ret = get_action_value(m, *actionid, &replace_to);
3499 				}
3500 				else if (0 == strcmp(m, MVAR_DATE))
3501 				{
3502 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3503 				}
3504 				else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3505 				{
3506 					get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3507 				}
3508 				else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3509 				{
3510 					if (NULL != r_event)
3511 						get_recovery_event_value(m, r_event, &replace_to);
3512 				}
3513 				else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3514 				{
3515 					get_current_event_value(m, c_event, &replace_to);
3516 				}
3517 				else if (0 == strcmp(m, MVAR_EVENT_NAME))
3518 				{
3519 					replace_to = zbx_strdup(replace_to, event->name);
3520 				}
3521 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3522 				{
3523 					get_event_value(m, event, &replace_to, userid);
3524 				}
3525 				else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3526 				{
3527 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3528 				}
3529 				else if (0 == strcmp(m, MVAR_HOST_NAME))
3530 				{
3531 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3532 				}
3533 				else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3534 				{
3535 					ret = DBget_item_value(c_event->objectid, &replace_to,
3536 							ZBX_REQUEST_HOST_DESCRIPTION);
3537 				}
3538 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3539 				{
3540 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3541 				}
3542 				else if (0 == strcmp(m, MVAR_HOST_DNS))
3543 				{
3544 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3545 				}
3546 				else if (0 == strcmp(m, MVAR_HOST_CONN))
3547 				{
3548 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3549 				}
3550 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3551 				{
3552 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3553 				}
3554 				else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3555 						0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3556 				{
3557 					ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3558 				}
3559 				else if (0 == strcmp(m, MVAR_ITEM_DESCRIPTION))
3560 				{
3561 					ret = DBget_item_value(c_event->objectid, &replace_to,
3562 							ZBX_REQUEST_ITEM_DESCRIPTION);
3563 				}
3564 				else if (0 == strcmp(m, MVAR_ITEM_ID))
3565 				{
3566 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3567 				}
3568 				else if (0 == strcmp(m, MVAR_ITEM_KEY) || 0 == strcmp(m, MVAR_TRIGGER_KEY))
3569 				{
3570 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3571 				}
3572 				else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
3573 				{
3574 					ret = DBget_item_value(c_event->objectid, &replace_to,
3575 							ZBX_REQUEST_ITEM_KEY_ORIG);
3576 				}
3577 				else if (0 == strcmp(m, MVAR_ITEM_NAME))
3578 				{
3579 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3580 				}
3581 				else if (0 == strcmp(m, MVAR_ITEM_NAME_ORIG))
3582 				{
3583 					ret = DBget_item_value(c_event->objectid, &replace_to,
3584 							ZBX_REQUEST_ITEM_NAME_ORIG);
3585 				}
3586 				else if (0 == strcmp(m, MVAR_ITEM_STATE))
3587 				{
3588 					replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3589 				}
3590 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
3591 				{
3592 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3593 				}
3594 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3595 				{
3596 					ret = DBget_item_value(c_event->objectid, &replace_to,
3597 							ZBX_REQUEST_PROXY_DESCRIPTION);
3598 				}
3599 				else if (0 == strcmp(m, MVAR_TIME))
3600 				{
3601 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3602 				}
3603 			}
3604 			else if (0 == indexed_macro && EVENT_SOURCE_INTERNAL == c_event->source &&
3605 					EVENT_OBJECT_LLDRULE == c_event->object)
3606 			{
3607 				if (ZBX_TOKEN_USER_MACRO == token.type)
3608 				{
3609 					cache_item_hostid(&hostids, c_event->objectid);
3610 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3611 					pos = token.loc.r;
3612 				}
3613 				else if (0 == strncmp(m, MVAR_ACTION, ZBX_CONST_STRLEN(MVAR_ACTION)))
3614 				{
3615 					ret = get_action_value(m, *actionid, &replace_to);
3616 				}
3617 				else if (0 == strcmp(m, MVAR_DATE))
3618 				{
3619 					replace_to = zbx_strdup(replace_to, zbx_date2str(time(NULL)));
3620 				}
3621 				else if (0 == strcmp(m, MVAR_ESC_HISTORY))
3622 				{
3623 					get_escalation_history(*actionid, event, r_event, &replace_to, userid);
3624 				}
3625 				else if (0 == strncmp(m, MVAR_EVENT_RECOVERY, ZBX_CONST_STRLEN(MVAR_EVENT_RECOVERY)))
3626 				{
3627 					if (NULL != r_event)
3628 						get_recovery_event_value(m, r_event, &replace_to);
3629 				}
3630 				else if (0 == strcmp(m, MVAR_EVENT_STATUS) || 0 == strcmp(m, MVAR_EVENT_VALUE))
3631 				{
3632 					get_current_event_value(m, c_event, &replace_to);
3633 				}
3634 				else if (0 == strncmp(m, MVAR_EVENT, ZBX_CONST_STRLEN(MVAR_EVENT)))
3635 				{
3636 					get_event_value(m, event, &replace_to, userid);
3637 				}
3638 				else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3639 				{
3640 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_HOST);
3641 				}
3642 				else if (0 == strcmp(m, MVAR_HOST_NAME))
3643 				{
3644 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_NAME);
3645 				}
3646 				else if (0 == strcmp(m, MVAR_HOST_DESCRIPTION))
3647 				{
3648 					ret = DBget_item_value(c_event->objectid, &replace_to,
3649 							ZBX_REQUEST_HOST_DESCRIPTION);
3650 				}
3651 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3652 				{
3653 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_IP);
3654 				}
3655 				else if (0 == strcmp(m, MVAR_HOST_DNS))
3656 				{
3657 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_DNS);
3658 				}
3659 				else if (0 == strcmp(m, MVAR_HOST_CONN))
3660 				{
3661 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_CONN);
3662 				}
3663 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3664 				{
3665 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_HOST_PORT);
3666 				}
3667 				else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)) ||
3668 						0 == strncmp(m, MVAR_PROFILE, ZBX_CONST_STRLEN(MVAR_PROFILE)))
3669 				{
3670 					ret = get_host_inventory_by_itemid(m, c_event->objectid, &replace_to);
3671 				}
3672 				else if (0 == strcmp(m, MVAR_LLDRULE_DESCRIPTION))
3673 				{
3674 					ret = DBget_item_value(c_event->objectid, &replace_to,
3675 							ZBX_REQUEST_ITEM_DESCRIPTION);
3676 				}
3677 				else if (0 == strcmp(m, MVAR_LLDRULE_ID))
3678 				{
3679 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, c_event->objectid);
3680 				}
3681 				else if (0 == strcmp(m, MVAR_LLDRULE_KEY))
3682 				{
3683 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_KEY);
3684 				}
3685 				else if (0 == strcmp(m, MVAR_LLDRULE_KEY_ORIG))
3686 				{
3687 					ret = DBget_item_value(c_event->objectid, &replace_to,
3688 							ZBX_REQUEST_ITEM_KEY_ORIG);
3689 				}
3690 				else if (0 == strcmp(m, MVAR_LLDRULE_NAME))
3691 				{
3692 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_ITEM_NAME);
3693 				}
3694 				else if (0 == strcmp(m, MVAR_LLDRULE_NAME_ORIG))
3695 				{
3696 					ret = DBget_item_value(c_event->objectid, &replace_to,
3697 							ZBX_REQUEST_ITEM_NAME_ORIG);
3698 				}
3699 				else if (0 == strcmp(m, MVAR_LLDRULE_STATE))
3700 				{
3701 					replace_to = zbx_strdup(replace_to, zbx_item_state_string(c_event->value));
3702 				}
3703 				else if (0 == strcmp(m, MVAR_PROXY_NAME))
3704 				{
3705 					ret = DBget_item_value(c_event->objectid, &replace_to, ZBX_REQUEST_PROXY_NAME);
3706 				}
3707 				else if (0 == strcmp(m, MVAR_PROXY_DESCRIPTION))
3708 				{
3709 					ret = DBget_item_value(c_event->objectid, &replace_to,
3710 							ZBX_REQUEST_PROXY_DESCRIPTION);
3711 				}
3712 				else if (0 == strcmp(m, MVAR_TIME))
3713 				{
3714 					replace_to = zbx_strdup(replace_to, zbx_time2str(time(NULL)));
3715 				}
3716 			}
3717 		}
3718 		else if (0 != (macro_type & (MACRO_TYPE_TRIGGER_DESCRIPTION | MACRO_TYPE_TRIGGER_COMMENTS)))
3719 		{
3720 			if (EVENT_OBJECT_TRIGGER == event->object)
3721 			{
3722 				if (ZBX_TOKEN_USER_MACRO == token.type)
3723 				{
3724 					cache_trigger_hostids(&hostids, event->trigger.expression,
3725 							event->trigger.recovery_expression);
3726 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3727 					pos = token.loc.r;
3728 				}
3729 				else if (ZBX_TOKEN_REFERENCE == token.type)
3730 				{
3731 					/* try to expand trigger expression if it hasn't been done yet */
3732 					if (NULL == expression && NULL == (expression =
3733 							get_expanded_expression(event->trigger.expression)))
3734 					{
3735 						/* expansion failed, reference substitution is impossible */
3736 						token_search = ZBX_TOKEN_SEARCH_BASIC;
3737 						continue;
3738 					}
3739 
3740 					get_trigger_expression_constant(expression, &token.data.reference, &replace,
3741 							&replace_len);
3742 				}
3743 				else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3744 				{
3745 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3746 							ZBX_REQUEST_HOST_HOST);
3747 				}
3748 				else if (0 == strcmp(m, MVAR_HOST_NAME))
3749 				{
3750 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3751 							ZBX_REQUEST_HOST_NAME);
3752 				}
3753 				else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3754 				{
3755 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3756 							ZBX_REQUEST_HOST_IP);
3757 				}
3758 				else if (0 == strcmp(m, MVAR_HOST_DNS))
3759 				{
3760 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3761 							ZBX_REQUEST_HOST_DNS);
3762 				}
3763 				else if (0 == strcmp(m, MVAR_HOST_CONN))
3764 				{
3765 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3766 							ZBX_REQUEST_HOST_CONN);
3767 				}
3768 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3769 				{
3770 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3771 							ZBX_REQUEST_HOST_PORT);
3772 				}
3773 				else if (0 == strcmp(m, MVAR_ITEM_VALUE))
3774 				{
3775 					ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
3776 							event->clock, event->ns, raw_value);
3777 				}
3778 				else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
3779 				{
3780 					ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
3781 							raw_value);
3782 				}
3783 			}
3784 		}
3785 		else if (0 != (macro_type & MACRO_TYPE_TRIGGER_EXPRESSION))
3786 		{
3787 			if (EVENT_OBJECT_TRIGGER == event->object)
3788 			{
3789 				if (ZBX_TOKEN_USER_MACRO == token.type)
3790 				{
3791 					/* When processing trigger expressions the user macros are already expanded. */
3792 					/* An unexpanded user macro means either unknown macro or macro value        */
3793 					/* validation failure.                                                       */
3794 
3795 					if (NULL != error)
3796 					{
3797 						zbx_snprintf(error, maxerrlen, "Invalid macro '%.*s' value",
3798 								(int)(token.loc.r - token.loc.l + 1),
3799 								*data + token.loc.l);
3800 					}
3801 
3802 					res = FAIL;
3803 				}
3804 				else if (0 == strcmp(m, MVAR_TRIGGER_VALUE))
3805 					replace_to = zbx_dsprintf(replace_to, "%d", event->value);
3806 			}
3807 		}
3808 		else if (0 != (macro_type & MACRO_TYPE_TRIGGER_URL))
3809 		{
3810 			if (EVENT_OBJECT_TRIGGER == event->object)
3811 			{
3812 				if (ZBX_TOKEN_USER_MACRO == token.type)
3813 				{
3814 					cache_trigger_hostids(&hostids, event->trigger.expression,
3815 							event->trigger.recovery_expression);
3816 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
3817 					pos = token.loc.r;
3818 				}
3819 				else if (0 == strcmp(m, MVAR_HOST_ID))
3820 				{
3821 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3822 							ZBX_REQUEST_HOST_ID);
3823 				}
3824 				else if (0 == strcmp(m, MVAR_HOST_HOST))
3825 				{
3826 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3827 							ZBX_REQUEST_HOST_HOST);
3828 				}
3829 				else if (0 == strcmp(m, MVAR_HOST_NAME))
3830 				{
3831 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3832 							ZBX_REQUEST_HOST_NAME);
3833 				}
3834 				else if (0 == strcmp(m, MVAR_HOST_IP))
3835 				{
3836 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3837 							ZBX_REQUEST_HOST_IP);
3838 				}
3839 				else if (0 == strcmp(m, MVAR_HOST_DNS))
3840 				{
3841 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3842 							ZBX_REQUEST_HOST_DNS);
3843 				}
3844 				else if (0 == strcmp(m, MVAR_HOST_CONN))
3845 				{
3846 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3847 							ZBX_REQUEST_HOST_CONN);
3848 				}
3849 				else if (0 == strcmp(m, MVAR_HOST_PORT))
3850 				{
3851 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
3852 							ZBX_REQUEST_HOST_PORT);
3853 				}
3854 				else if (0 == strcmp(m, MVAR_TRIGGER_ID))
3855 				{
3856 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
3857 				}
3858 				else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
3859 				{
3860 					ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
3861 							raw_value);
3862 				}
3863 				else if (0 == strcmp(m, MVAR_ITEM_VALUE))
3864 				{
3865 					ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
3866 							event->clock, event->ns, raw_value);
3867 				}
3868 			}
3869 		}
3870 		else if (0 == indexed_macro &&
3871 				0 != (macro_type & (MACRO_TYPE_ITEM_KEY | MACRO_TYPE_PARAMS_FIELD |
3872 						MACRO_TYPE_LLD_FILTER | MACRO_TYPE_ALLOWED_HOSTS)))
3873 		{
3874 			if (ZBX_TOKEN_USER_MACRO == token.type)
3875 			{
3876 				DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
3877 				pos = token.loc.r;
3878 			}
3879 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3880 				replace_to = zbx_strdup(replace_to, dc_item->host.host);
3881 			else if (0 == strcmp(m, MVAR_HOST_NAME))
3882 				replace_to = zbx_strdup(replace_to, dc_item->host.name);
3883 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3884 			{
3885 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3886 				{
3887 					replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
3888 				}
3889 				else
3890 				{
3891 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3892 							ZBX_REQUEST_HOST_IP);
3893 				}
3894 			}
3895 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
3896 			{
3897 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3898 				{
3899 					replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
3900 				}
3901 				else
3902 				{
3903 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3904 							ZBX_REQUEST_HOST_DNS);
3905 				}
3906 			}
3907 			else if (0 == strcmp(m, MVAR_HOST_CONN))
3908 			{
3909 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
3910 				{
3911 					replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
3912 				}
3913 				else
3914 				{
3915 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
3916 							ZBX_REQUEST_HOST_CONN);
3917 				}
3918 			}
3919 		}
3920 		else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_INTERFACE_ADDR))
3921 		{
3922 			if (ZBX_TOKEN_USER_MACRO == token.type)
3923 			{
3924 				DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3925 				pos = token.loc.r;
3926 			}
3927 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3928 				replace_to = zbx_strdup(replace_to, dc_host->host);
3929 			else if (0 == strcmp(m, MVAR_HOST_NAME))
3930 				replace_to = zbx_strdup(replace_to, dc_host->name);
3931 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3932 			{
3933 				if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3934 						dc_host->hostid, INTERFACE_TYPE_AGENT)))
3935 				{
3936 					replace_to = zbx_strdup(replace_to, interface.ip_orig);
3937 				}
3938 			}
3939 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
3940 			{
3941 				if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3942 						dc_host->hostid, INTERFACE_TYPE_AGENT)))
3943 				{
3944 					replace_to = zbx_strdup(replace_to, interface.dns_orig);
3945 				}
3946 			}
3947 			else if (0 == strcmp(m, MVAR_HOST_CONN))
3948 			{
3949 				if (SUCCEED == (ret = DCconfig_get_interface_by_type(&interface,
3950 						dc_host->hostid, INTERFACE_TYPE_AGENT)))
3951 				{
3952 					replace_to = zbx_strdup(replace_to, interface.addr);
3953 				}
3954 			}
3955 		}
3956 		else if (0 != (macro_type & (MACRO_TYPE_COMMON | MACRO_TYPE_SNMP_OID)))
3957 		{
3958 			if (ZBX_TOKEN_USER_MACRO == token.type)
3959 			{
3960 				if (NULL != hostid)
3961 					DCget_user_macro(hostid, 1, m, &replace_to);
3962 				else
3963 					DCget_user_macro(NULL, 0, m, &replace_to);
3964 
3965 				pos = token.loc.r;
3966 			}
3967 		}
3968 		else if (0 != (macro_type & MACRO_TYPE_ITEM_EXPRESSION))
3969 		{
3970 			if (ZBX_TOKEN_USER_MACRO == token.type)
3971 			{
3972 				require_numeric = 1;
3973 				DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3974 				pos = token.loc.r;
3975 			}
3976 		}
3977 		else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_SCRIPT))
3978 		{
3979 			if (ZBX_TOKEN_USER_MACRO == token.type)
3980 			{
3981 				DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
3982 				pos = token.loc.r;
3983 			}
3984 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
3985 				replace_to = zbx_strdup(replace_to, dc_host->host);
3986 			else if (0 == strcmp(m, MVAR_HOST_NAME))
3987 				replace_to = zbx_strdup(replace_to, dc_host->name);
3988 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
3989 			{
3990 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
3991 					replace_to = zbx_strdup(replace_to, interface.ip_orig);
3992 				require_address = 1;
3993 			}
3994 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
3995 			{
3996 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
3997 					replace_to = zbx_strdup(replace_to, interface.dns_orig);
3998 				require_address = 1;
3999 			}
4000 			else if (0 == strcmp(m, MVAR_HOST_CONN))
4001 			{
4002 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4003 					replace_to = zbx_strdup(replace_to, interface.addr);
4004 				require_address = 1;
4005 			}
4006 		}
4007 		else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_HTTPTEST_FIELD))
4008 		{
4009 			if (ZBX_TOKEN_USER_MACRO == token.type)
4010 			{
4011 				DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4012 				pos = token.loc.r;
4013 			}
4014 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4015 				replace_to = zbx_strdup(replace_to, dc_host->host);
4016 			else if (0 == strcmp(m, MVAR_HOST_NAME))
4017 				replace_to = zbx_strdup(replace_to, dc_host->name);
4018 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4019 			{
4020 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4021 					replace_to = zbx_strdup(replace_to, interface.ip_orig);
4022 			}
4023 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
4024 			{
4025 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4026 					replace_to = zbx_strdup(replace_to, interface.dns_orig);
4027 			}
4028 			else if (0 == strcmp(m, MVAR_HOST_CONN))
4029 			{
4030 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4031 					replace_to = zbx_strdup(replace_to, interface.addr);
4032 			}
4033 		}
4034 		else if (0 == indexed_macro && (0 != (macro_type & (MACRO_TYPE_HTTP_RAW | MACRO_TYPE_HTTP_JSON |
4035 				MACRO_TYPE_HTTP_XML))))
4036 		{
4037 			if (ZBX_TOKEN_USER_MACRO == token.type)
4038 			{
4039 				DCget_user_macro(&dc_host->hostid, 1, m, &replace_to);
4040 				pos = token.loc.r;
4041 			}
4042 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4043 			{
4044 				replace_to = zbx_strdup(replace_to, dc_host->host);
4045 			}
4046 			else if (0 == strcmp(m, MVAR_HOST_NAME))
4047 			{
4048 				replace_to = zbx_strdup(replace_to, dc_host->name);
4049 			}
4050 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4051 			{
4052 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4053 					replace_to = zbx_strdup(replace_to, interface.ip_orig);
4054 			}
4055 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
4056 			{
4057 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4058 					replace_to = zbx_strdup(replace_to, interface.dns_orig);
4059 			}
4060 			else if (0 == strcmp(m, MVAR_HOST_CONN))
4061 			{
4062 				if (SUCCEED == (ret = DCconfig_get_interface(&interface, dc_host->hostid, 0)))
4063 					replace_to = zbx_strdup(replace_to, interface.addr);
4064 			}
4065 			else if (0 == strcmp(m, MVAR_ITEM_ID))
4066 			{
4067 				replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, dc_item->itemid);
4068 			}
4069 			else if (0 == strcmp(m, MVAR_ITEM_KEY))
4070 			{
4071 				replace_to = zbx_strdup(replace_to, dc_item->key);
4072 			}
4073 			else if (0 == strcmp(m, MVAR_ITEM_KEY_ORIG))
4074 			{
4075 				replace_to = zbx_strdup(replace_to, dc_item->key_orig);
4076 			}
4077 		}
4078 		else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_ALERT))
4079 		{
4080 			if (0 == strcmp(m, MVAR_ALERT_SENDTO))
4081 				replace_to = zbx_strdup(replace_to, alert->sendto);
4082 			else if (0 == strcmp(m, MVAR_ALERT_SUBJECT))
4083 				replace_to = zbx_strdup(replace_to, alert->subject);
4084 			else if (0 == strcmp(m, MVAR_ALERT_MESSAGE))
4085 				replace_to = zbx_strdup(replace_to, alert->message);
4086 		}
4087 		else if (0 == indexed_macro && 0 != (macro_type & MACRO_TYPE_JMX_ENDPOINT))
4088 		{
4089 			if (ZBX_TOKEN_USER_MACRO == token.type)
4090 			{
4091 				DCget_user_macro(&dc_item->host.hostid, 1, m, &replace_to);
4092 				pos = token.loc.r;
4093 			}
4094 			else if (0 == strcmp(m, MVAR_HOST_HOST) || 0 == strcmp(m, MVAR_HOSTNAME))
4095 				replace_to = zbx_strdup(replace_to, dc_item->host.host);
4096 			else if (0 == strcmp(m, MVAR_HOST_NAME))
4097 				replace_to = zbx_strdup(replace_to, dc_item->host.name);
4098 			else if (0 == strcmp(m, MVAR_HOST_IP) || 0 == strcmp(m, MVAR_IPADDRESS))
4099 			{
4100 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4101 				{
4102 					replace_to = zbx_strdup(replace_to, dc_item->interface.ip_orig);
4103 				}
4104 				else
4105 				{
4106 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4107 							ZBX_REQUEST_HOST_IP);
4108 				}
4109 			}
4110 			else if	(0 == strcmp(m, MVAR_HOST_DNS))
4111 			{
4112 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4113 				{
4114 					replace_to = zbx_strdup(replace_to, dc_item->interface.dns_orig);
4115 				}
4116 				else
4117 				{
4118 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4119 							ZBX_REQUEST_HOST_DNS);
4120 				}
4121 			}
4122 			else if (0 == strcmp(m, MVAR_HOST_CONN))
4123 			{
4124 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4125 				{
4126 					replace_to = zbx_strdup(replace_to, dc_item->interface.addr);
4127 				}
4128 				else
4129 				{
4130 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4131 							ZBX_REQUEST_HOST_CONN);
4132 				}
4133 			}
4134 			else if (0 == strcmp(m, MVAR_HOST_PORT))
4135 			{
4136 				if (INTERFACE_TYPE_UNKNOWN != dc_item->interface.type)
4137 				{
4138 					replace_to = zbx_dsprintf(replace_to, "%u", dc_item->interface.port);
4139 				}
4140 				else
4141 				{
4142 					ret = get_interface_value(dc_item->host.hostid, dc_item->itemid, &replace_to,
4143 							ZBX_REQUEST_HOST_PORT);
4144 				}
4145 			}
4146 		}
4147 		else if (macro_type & MACRO_TYPE_TRIGGER_TAG)
4148 		{
4149 			if (EVENT_SOURCE_TRIGGERS == event->source)
4150 			{
4151 				if (ZBX_TOKEN_USER_MACRO == token.type)
4152 				{
4153 					cache_trigger_hostids(&hostids, event->trigger.expression,
4154 							event->trigger.recovery_expression);
4155 					DCget_user_macro(hostids.values, hostids.values_num, m, &replace_to);
4156 					pos = token.loc.r;
4157 				}
4158 				else if (0 == strcmp(m, MVAR_HOST_ID))
4159 				{
4160 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4161 							ZBX_REQUEST_HOST_ID);
4162 				}
4163 				else if (0 == strcmp(m, MVAR_HOST_HOST))
4164 				{
4165 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4166 							ZBX_REQUEST_HOST_HOST);
4167 				}
4168 				else if (0 == strcmp(m, MVAR_HOST_NAME))
4169 				{
4170 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4171 							ZBX_REQUEST_HOST_NAME);
4172 				}
4173 				else if (0 == strcmp(m, MVAR_HOST_IP))
4174 				{
4175 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4176 							ZBX_REQUEST_HOST_IP);
4177 				}
4178 				else if (0 == strcmp(m, MVAR_HOST_DNS))
4179 				{
4180 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4181 							ZBX_REQUEST_HOST_DNS);
4182 				}
4183 				else if (0 == strcmp(m, MVAR_HOST_CONN))
4184 				{
4185 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4186 							ZBX_REQUEST_HOST_CONN);
4187 				}
4188 				else if (0 == strcmp(m, MVAR_HOST_PORT))
4189 				{
4190 					ret = DBget_trigger_value(event->trigger.expression, &replace_to, N_functionid,
4191 							ZBX_REQUEST_HOST_PORT);
4192 				}
4193 				else if (0 == strcmp(m, MVAR_ITEM_LASTVALUE))
4194 				{
4195 					ret = DBitem_lastvalue(event->trigger.expression, &replace_to, N_functionid,
4196 							raw_value);
4197 				}
4198 				else if (0 == strcmp(m, MVAR_ITEM_VALUE))
4199 				{
4200 					ret = DBitem_value(event->trigger.expression, &replace_to, N_functionid,
4201 							event->clock, event->ns, raw_value);
4202 				}
4203 				else if (0 == strncmp(m, MVAR_INVENTORY, ZBX_CONST_STRLEN(MVAR_INVENTORY)))
4204 				{
4205 					ret = get_host_inventory(m, event->trigger.expression, &replace_to,
4206 							N_functionid);
4207 				}
4208 				else if (0 == strcmp(m, MVAR_TRIGGER_ID))
4209 				{
4210 					replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64, event->objectid);
4211 				}
4212 			}
4213 		}
4214 
4215 		if (0 != (macro_type & MACRO_TYPE_HTTP_JSON) && NULL != replace_to)
4216 			zbx_json_escape(&replace_to);
4217 
4218 		if (0 != (macro_type & MACRO_TYPE_HTTP_XML) && NULL != replace_to)
4219 		{
4220 			char	*replace_to_esc;
4221 
4222 			replace_to_esc = xml_escape_dyn(replace_to);
4223 			zbx_free(replace_to);
4224 			replace_to = replace_to_esc;
4225 		}
4226 
4227 		if (ZBX_TOKEN_FUNC_MACRO == token.type && NULL != replace_to)
4228 		{
4229 			if (SUCCEED != (ret = zbx_calculate_macro_function(*data, &token.data.func_macro, &replace_to)))
4230 				zbx_free(replace_to);
4231 		}
4232 
4233 		if (NULL != replace_to)
4234 		{
4235 			if (1 == require_numeric)
4236 			{
4237 				if (SUCCEED == (res = is_double_suffix(replace_to, ZBX_FLAG_DOUBLE_SUFFIX)))
4238 				{
4239 					wrap_negative_double_suffix(&replace_to, NULL);
4240 				}
4241 				else if (NULL != error)
4242 				{
4243 					zbx_snprintf(error, maxerrlen, "Macro '%.*s' value is not numeric",
4244 							(int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4245 				}
4246 			}
4247 			else if (1 == require_address && NULL != strstr(replace_to, "{$"))
4248 			{
4249 				/* Macros should be already expanded. An unexpanded user macro means either unknown */
4250 				/* macro or macro value validation failure.                                         */
4251 				zbx_snprintf(error, maxerrlen, "Invalid macro '%.*s' value",
4252 						(int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4253 				res = FAIL;
4254 			}
4255 		}
4256 
4257 		if (FAIL == ret)
4258 		{
4259 			zabbix_log(LOG_LEVEL_DEBUG, "cannot resolve macro '%.*s'",
4260 					(int)(token.loc.r - token.loc.l + 1), *data + token.loc.l);
4261 			replace_to = zbx_strdup(replace_to, STR_UNKNOWN_VARIABLE);
4262 		}
4263 
4264 		if (ZBX_TOKEN_USER_MACRO == token.type || (ZBX_TOKEN_MACRO == token.type && 0 == indexed_macro))
4265 			(*data)[token.loc.r + 1] = c;
4266 
4267 		if (NULL != replace_to)
4268 		{
4269 			pos = token.loc.r;
4270 
4271 			pos += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token.loc.l,
4272 					token.loc.r - token.loc.l + 1, replace_to, strlen(replace_to));
4273 			zbx_free(replace_to);
4274 		}
4275 		else if (NULL != replace)
4276 		{
4277 			pos = token.loc.r;
4278 
4279 			pos += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token.loc.l,
4280 					token.loc.r - token.loc.l + 1, replace, replace_len);
4281 
4282 			replace = NULL;
4283 		}
4284 
4285 		pos++;
4286 	}
4287 
4288 	zbx_free(expression);
4289 	zbx_vector_uint64_destroy(&hostids);
4290 
4291 	zabbix_log(LOG_LEVEL_DEBUG, "End %s() data:'%s'", __function_name, *data);
4292 
4293 	return res;
4294 }
4295 
extract_expression_functionids(zbx_vector_uint64_t * functionids,const char * expression)4296 static int	extract_expression_functionids(zbx_vector_uint64_t *functionids, const char *expression)
4297 {
4298 	const char	*bl, *br;
4299 	zbx_uint64_t	functionid;
4300 
4301 	for (bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{'))
4302 	{
4303 		if (NULL == (br = strchr(bl, '}')))
4304 			break;
4305 
4306 		if (SUCCEED != is_uint64_n(bl + 1, br - bl - 1, &functionid))
4307 			break;
4308 
4309 		zbx_vector_uint64_append(functionids, functionid);
4310 
4311 		bl = br + 1;
4312 	}
4313 
4314 	return (NULL == bl ? SUCCEED : FAIL);
4315 }
4316 
zbx_extract_functionids(zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * triggers)4317 static void	zbx_extract_functionids(zbx_vector_uint64_t *functionids, zbx_vector_ptr_t *triggers)
4318 {
4319 	const char	*__function_name = "zbx_extract_functionids";
4320 
4321 	DC_TRIGGER	*tr;
4322 	int		i, values_num_save;
4323 
4324 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __function_name, triggers->values_num);
4325 
4326 	for (i = 0; i < triggers->values_num; i++)
4327 	{
4328 		const char	*error_expression = NULL;
4329 
4330 		tr = (DC_TRIGGER *)triggers->values[i];
4331 
4332 		if (NULL != tr->new_error)
4333 			continue;
4334 
4335 		values_num_save = functionids->values_num;
4336 
4337 		if (SUCCEED != extract_expression_functionids(functionids, tr->expression))
4338 		{
4339 			error_expression = tr->expression;
4340 		}
4341 		else if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode &&
4342 				SUCCEED != extract_expression_functionids(functionids, tr->recovery_expression))
4343 		{
4344 			error_expression = tr->recovery_expression;
4345 		}
4346 
4347 		if (NULL != error_expression)
4348 		{
4349 			tr->new_error = zbx_dsprintf(tr->new_error, "Invalid expression [%s]", error_expression);
4350 			tr->new_value = TRIGGER_VALUE_UNKNOWN;
4351 			functionids->values_num = values_num_save;
4352 		}
4353 	}
4354 
4355 	zbx_vector_uint64_sort(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4356 	zbx_vector_uint64_uniq(functionids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4357 
4358 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() functionids_num:%d", __function_name, functionids->values_num);
4359 }
4360 
4361 typedef struct
4362 {
4363 	DC_TRIGGER	*trigger;
4364 	int		start_index;
4365 	int		count;
4366 }
4367 zbx_trigger_func_position_t;
4368 
4369 /******************************************************************************
4370  *                                                                            *
4371  * Function: expand_trigger_macros                                            *
4372  *                                                                            *
4373  * Purpose: expand macros in a trigger expression                             *
4374  *                                                                            *
4375  * Parameters: event - The trigger event structure                            *
4376  *             trigger - The trigger where to expand macros in                *
4377  *                                                                            *
4378  * Author: Andrea Biscuola                                                    *
4379  *                                                                            *
4380  ******************************************************************************/
expand_trigger_macros(DB_EVENT * event,DC_TRIGGER * trigger,char * error,size_t maxerrlen)4381 static int	expand_trigger_macros(DB_EVENT *event, DC_TRIGGER *trigger, char *error, size_t maxerrlen)
4382 {
4383 	if (FAIL == substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4384 			&trigger->expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen))
4385 	{
4386 		return FAIL;
4387 	}
4388 
4389 	if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == trigger->recovery_mode)
4390 	{
4391 		if (FAIL == substitute_simple_macros(NULL, event, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
4392 				&trigger->recovery_expression, MACRO_TYPE_TRIGGER_EXPRESSION, error, maxerrlen))
4393 		{
4394 			return FAIL;
4395 		}
4396 	}
4397 
4398 	return SUCCEED;
4399 }
4400 
4401 /******************************************************************************
4402  *                                                                            *
4403  * Function: zbx_link_triggers_with_functions                                 *
4404  *                                                                            *
4405  * Purpose: triggers links with functions                                     *
4406  *                                                                            *
4407  * Parameters: triggers_func_pos - [IN/OUT] pointer to the list of triggers   *
4408  *                                 with functions position in functionids     *
4409  *                                 array                                      *
4410  *             functionids       - [IN/OUT] array of function IDs             *
4411  *             trigger_order     - [IN] array of triggers                     *
4412  *                                                                            *
4413  ******************************************************************************/
zbx_link_triggers_with_functions(zbx_vector_ptr_t * triggers_func_pos,zbx_vector_uint64_t * functionids,zbx_vector_ptr_t * trigger_order)4414 static void	zbx_link_triggers_with_functions(zbx_vector_ptr_t *triggers_func_pos, zbx_vector_uint64_t *functionids,
4415 		zbx_vector_ptr_t *trigger_order)
4416 {
4417 	const char		*__function_name = "zbx_link_triggers_with_functions";
4418 
4419 	zbx_vector_uint64_t	funcids;
4420 	DC_TRIGGER		*tr;
4421 	DB_EVENT		ev;
4422 	int			i;
4423 
4424 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() trigger_order_num:%d", __function_name, trigger_order->values_num);
4425 
4426 	zbx_vector_uint64_create(&funcids);
4427 	zbx_vector_uint64_reserve(&funcids, functionids->values_num);
4428 
4429 	ev.object = EVENT_OBJECT_TRIGGER;
4430 
4431 	for (i = 0; i < trigger_order->values_num; i++)
4432 	{
4433 		zbx_trigger_func_position_t	*tr_func_pos;
4434 
4435 		tr = (DC_TRIGGER *)trigger_order->values[i];
4436 
4437 		if (NULL != tr->new_error)
4438 			continue;
4439 
4440 		ev.value = tr->value;
4441 
4442 		expand_trigger_macros(&ev, tr, NULL, 0);
4443 
4444 		if (SUCCEED == extract_expression_functionids(&funcids, tr->expression))
4445 		{
4446 			tr_func_pos = (zbx_trigger_func_position_t *)zbx_malloc(NULL, sizeof(zbx_trigger_func_position_t));
4447 			tr_func_pos->trigger = tr;
4448 			tr_func_pos->start_index = functionids->values_num;
4449 			tr_func_pos->count = funcids.values_num;
4450 
4451 			zbx_vector_uint64_append_array(functionids, funcids.values, funcids.values_num);
4452 			zbx_vector_ptr_append(triggers_func_pos, tr_func_pos);
4453 		}
4454 
4455 		zbx_vector_uint64_clear(&funcids);
4456 	}
4457 
4458 	zbx_vector_uint64_destroy(&funcids);
4459 
4460 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() triggers_func_pos_num:%d", __function_name,
4461 			triggers_func_pos->values_num);
4462 }
4463 
4464 /******************************************************************************
4465  *                                                                            *
4466  * Function: zbx_determine_items_in_expressions                               *
4467  *                                                                            *
4468  * Purpose: mark triggers that use one of the items in problem expression     *
4469  *          with ZBX_DC_TRIGGER_PROBLEM_EXPRESSION flag                       *
4470  *                                                                            *
4471  * Parameters: trigger_order - [IN/OUT] pointer to the list of triggers       *
4472  *             itemids       - [IN] array of item IDs                         *
4473  *             item_num      - [IN] number of items                           *
4474  *                                                                            *
4475  ******************************************************************************/
zbx_determine_items_in_expressions(zbx_vector_ptr_t * trigger_order,const zbx_uint64_t * itemids,int item_num)4476 void	zbx_determine_items_in_expressions(zbx_vector_ptr_t *trigger_order, const zbx_uint64_t *itemids, int item_num)
4477 {
4478 	zbx_vector_ptr_t	triggers_func_pos;
4479 	zbx_vector_uint64_t	functionids, itemids_sorted;
4480 	DC_FUNCTION		*functions = NULL;
4481 	int			*errcodes = NULL, t, f;
4482 
4483 	zbx_vector_uint64_create(&itemids_sorted);
4484 	zbx_vector_uint64_append_array(&itemids_sorted, itemids, item_num);
4485 	zbx_vector_uint64_sort(&itemids_sorted, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4486 
4487 	zbx_vector_ptr_create(&triggers_func_pos);
4488 	zbx_vector_ptr_reserve(&triggers_func_pos, trigger_order->values_num);
4489 
4490 	zbx_vector_uint64_create(&functionids);
4491 	zbx_vector_uint64_reserve(&functionids, item_num);
4492 
4493 	zbx_link_triggers_with_functions(&triggers_func_pos, &functionids, trigger_order);
4494 
4495 	functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids.values_num);
4496 	errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids.values_num);
4497 
4498 	DCconfig_get_functions_by_functionids(functions, functionids.values, errcodes, functionids.values_num);
4499 
4500 	for (t = 0; t < triggers_func_pos.values_num; t++)
4501 	{
4502 		zbx_trigger_func_position_t	*func_pos = (zbx_trigger_func_position_t *)triggers_func_pos.values[t];
4503 
4504 		for (f = func_pos->start_index; f < func_pos->start_index + func_pos->count; f++)
4505 		{
4506 			if (FAIL != zbx_vector_uint64_bsearch(&itemids_sorted, functions[f].itemid,
4507 					ZBX_DEFAULT_UINT64_COMPARE_FUNC))
4508 			{
4509 				func_pos->trigger->flags |= ZBX_DC_TRIGGER_PROBLEM_EXPRESSION;
4510 				break;
4511 			}
4512 		}
4513 	}
4514 
4515 	DCconfig_clean_functions(functions, errcodes, functionids.values_num);
4516 	zbx_free(errcodes);
4517 	zbx_free(functions);
4518 
4519 	zbx_vector_ptr_clear_ext(&triggers_func_pos, zbx_ptr_free);
4520 	zbx_vector_ptr_destroy(&triggers_func_pos);
4521 
4522 	zbx_vector_uint64_clear(&functionids);
4523 	zbx_vector_uint64_destroy(&functionids);
4524 
4525 	zbx_vector_uint64_clear(&itemids_sorted);
4526 	zbx_vector_uint64_destroy(&itemids_sorted);
4527 }
4528 
4529 typedef struct
4530 {
4531 	/* input data */
4532 	zbx_uint64_t	itemid;
4533 	char		*function;
4534 	char		*parameter;
4535 	zbx_timespec_t	timespec;
4536 
4537 	/* output data */
4538 	char		*value;
4539 	char		*error;
4540 }
4541 zbx_func_t;
4542 
4543 typedef struct
4544 {
4545 	zbx_uint64_t	functionid;
4546 	zbx_func_t	*func;
4547 }
4548 zbx_ifunc_t;
4549 
func_hash_func(const void * data)4550 static zbx_hash_t	func_hash_func(const void *data)
4551 {
4552 	const zbx_func_t	*func = (const zbx_func_t *)data;
4553 	zbx_hash_t		hash;
4554 
4555 	hash = ZBX_DEFAULT_UINT64_HASH_FUNC(&func->itemid);
4556 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->function, strlen(func->function), hash);
4557 	hash = ZBX_DEFAULT_STRING_HASH_ALGO(func->parameter, strlen(func->parameter), hash);
4558 	hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.sec, sizeof(func->timespec.sec), hash);
4559 	hash = ZBX_DEFAULT_HASH_ALGO(&func->timespec.ns, sizeof(func->timespec.ns), hash);
4560 
4561 	return hash;
4562 }
4563 
func_compare_func(const void * d1,const void * d2)4564 static int	func_compare_func(const void *d1, const void *d2)
4565 {
4566 	const zbx_func_t	*func1 = (const zbx_func_t *)d1;
4567 	const zbx_func_t	*func2 = (const zbx_func_t *)d2;
4568 	int			ret;
4569 
4570 	ZBX_RETURN_IF_NOT_EQUAL(func1->itemid, func2->itemid);
4571 
4572 	if (0 != (ret = strcmp(func1->function, func2->function)))
4573 		return ret;
4574 
4575 	if (0 != (ret = strcmp(func1->parameter, func2->parameter)))
4576 		return ret;
4577 
4578 	ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.sec, func2->timespec.sec);
4579 	ZBX_RETURN_IF_NOT_EQUAL(func1->timespec.ns, func2->timespec.ns);
4580 
4581 	return 0;
4582 }
4583 
func_clean(void * ptr)4584 static void	func_clean(void *ptr)
4585 {
4586 	zbx_func_t	*func = (zbx_func_t *)ptr;
4587 
4588 	zbx_free(func->function);
4589 	zbx_free(func->parameter);
4590 	zbx_free(func->value);
4591 	zbx_free(func->error);
4592 }
4593 
4594 /******************************************************************************
4595  *                                                                            *
4596  * Function: zbx_populate_function_items                                      *
4597  *                                                                            *
4598  * Purpose: prepare hashset of functions to evaluate                          *
4599  *                                                                            *
4600  * Parameters: functionids - [IN] function identifiers                        *
4601  *             funcs       - [OUT] functions indexed by itemid, name,         *
4602  *                                 parameter, timestamp                       *
4603  *             ifuncs      - [OUT] function index by functionid               *
4604  *             trigger     - [IN] vector of triggers, sorted by triggerid     *
4605  *                                                                            *
4606  ******************************************************************************/
zbx_populate_function_items(const zbx_vector_uint64_t * functionids,zbx_hashset_t * funcs,zbx_hashset_t * ifuncs,const zbx_vector_ptr_t * triggers)4607 static void	zbx_populate_function_items(const zbx_vector_uint64_t *functionids, zbx_hashset_t *funcs,
4608 		zbx_hashset_t *ifuncs, const zbx_vector_ptr_t *triggers)
4609 {
4610 	const char	*__function_name = "zbx_populate_function_items";
4611 
4612 	int		i, j;
4613 	DC_TRIGGER	*tr;
4614 	DC_FUNCTION	*functions = NULL;
4615 	int		*errcodes = NULL;
4616 	zbx_ifunc_t	ifunc_local;
4617 	zbx_func_t	*func, func_local;
4618 
4619 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() functionids_num:%d", __function_name, functionids->values_num);
4620 
4621 	func_local.value = NULL;
4622 	func_local.error = NULL;
4623 
4624 	functions = (DC_FUNCTION *)zbx_malloc(functions, sizeof(DC_FUNCTION) * functionids->values_num);
4625 	errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * functionids->values_num);
4626 
4627 	DCconfig_get_functions_by_functionids(functions, functionids->values, errcodes, functionids->values_num);
4628 
4629 	for (i = 0; i < functionids->values_num; i++)
4630 	{
4631 		if (SUCCEED != errcodes[i])
4632 			continue;
4633 
4634 		func_local.itemid = functions[i].itemid;
4635 
4636 		if (FAIL != (j = zbx_vector_ptr_bsearch(triggers, &functions[i].triggerid,
4637 				ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
4638 		{
4639 			tr = (DC_TRIGGER *)triggers->values[j];
4640 			func_local.timespec = tr->timespec;
4641 		}
4642 		else
4643 		{
4644 			func_local.timespec.sec = 0;
4645 			func_local.timespec.ns = 0;
4646 		}
4647 
4648 		func_local.function = functions[i].function;
4649 		func_local.parameter = functions[i].parameter;
4650 
4651 		if (NULL == (func = (zbx_func_t *)zbx_hashset_search(funcs, &func_local)))
4652 		{
4653 			func = (zbx_func_t *)zbx_hashset_insert(funcs, &func_local, sizeof(func_local));
4654 			func->function = zbx_strdup(NULL, func_local.function);
4655 			func->parameter = zbx_strdup(NULL, func_local.parameter);
4656 		}
4657 
4658 		ifunc_local.functionid = functions[i].functionid;
4659 		ifunc_local.func = func;
4660 		zbx_hashset_insert(ifuncs, &ifunc_local, sizeof(ifunc_local));
4661 	}
4662 
4663 	DCconfig_clean_functions(functions, errcodes, functionids->values_num);
4664 
4665 	zbx_free(errcodes);
4666 	zbx_free(functions);
4667 
4668 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() ifuncs_num:%d", __function_name, ifuncs->num_data);
4669 }
4670 
zbx_evaluate_item_functions(zbx_hashset_t * funcs,zbx_vector_ptr_t * unknown_msgs)4671 static void	zbx_evaluate_item_functions(zbx_hashset_t *funcs, zbx_vector_ptr_t *unknown_msgs)
4672 {
4673 	const char	*__function_name = "zbx_evaluate_item_functions";
4674 
4675 	DC_ITEM			*items = NULL;
4676 	char			value[MAX_BUFFER_LEN], *error = NULL;
4677 	int			i;
4678 	zbx_func_t		*func;
4679 	zbx_vector_uint64_t	itemids;
4680 	int			*errcodes = NULL;
4681 	zbx_hashset_iter_t	iter;
4682 
4683 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() funcs_num:%d", __function_name, funcs->num_data);
4684 
4685 	zbx_vector_uint64_create(&itemids);
4686 	zbx_vector_uint64_reserve(&itemids, funcs->num_data);
4687 
4688 	zbx_hashset_iter_reset(funcs, &iter);
4689 	while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4690 		zbx_vector_uint64_append(&itemids, func->itemid);
4691 
4692 	zbx_vector_uint64_sort(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4693 	zbx_vector_uint64_uniq(&itemids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4694 
4695 	items = (DC_ITEM *)zbx_malloc(items, sizeof(DC_ITEM) * (size_t)itemids.values_num);
4696 	errcodes = (int *)zbx_malloc(errcodes, sizeof(int) * (size_t)itemids.values_num);
4697 
4698 	DCconfig_get_items_by_itemids(items, itemids.values, errcodes, itemids.values_num);
4699 
4700 	zbx_hashset_iter_reset(funcs, &iter);
4701 	while (NULL != (func = (zbx_func_t *)zbx_hashset_iter_next(&iter)))
4702 	{
4703 		int	ret_unknown = 0;	/* flag raised if current function evaluates to ZBX_UNKNOWN */
4704 		char	*unknown_msg;
4705 
4706 		i = zbx_vector_uint64_bsearch(&itemids, func->itemid, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4707 
4708 		if (SUCCEED != errcodes[i])
4709 		{
4710 			func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s(%s)\":"
4711 					" item does not exist.",
4712 					func->function, func->parameter);
4713 			continue;
4714 		}
4715 
4716 		/* do not evaluate if the item is disabled or belongs to a disabled host */
4717 
4718 		if (ITEM_STATUS_ACTIVE != items[i].status)
4719 		{
4720 			func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s:%s.%s(%s)\":"
4721 					" item is disabled.",
4722 					items[i].host.host, items[i].key_orig, func->function, func->parameter);
4723 			continue;
4724 		}
4725 
4726 		if (HOST_STATUS_MONITORED != items[i].host.status)
4727 		{
4728 			func->error = zbx_dsprintf(func->error, "Cannot evaluate function \"%s:%s.%s(%s)\":"
4729 					" item belongs to a disabled host.",
4730 					items[i].host.host, items[i].key_orig, func->function, func->parameter);
4731 			continue;
4732 		}
4733 
4734 		/* If the item is NOTSUPPORTED then evaluation is allowed for:   */
4735 		/*   - time-based functions and nodata(). Their values can be    */
4736 		/*     evaluated to regular numbers even for NOTSUPPORTED items. */
4737 		/*   - other functions. Result of evaluation is ZBX_UNKNOWN.     */
4738 
4739 		if (ITEM_STATE_NOTSUPPORTED == items[i].state && FAIL == evaluatable_for_notsupported(func->function))
4740 		{
4741 			/* compose and store 'unknown' message for future use */
4742 			unknown_msg = zbx_dsprintf(NULL,
4743 					"Cannot evaluate function \"%s:%s.%s(%s)\": item is not supported.",
4744 					items[i].host.host, items[i].key_orig, func->function, func->parameter);
4745 
4746 			zbx_free(func->error);
4747 			zbx_vector_ptr_append(unknown_msgs, unknown_msg);
4748 			ret_unknown = 1;
4749 		}
4750 
4751 		if (0 == ret_unknown && SUCCEED != evaluate_function(value, &items[i], func->function,
4752 				func->parameter, &func->timespec, &error))
4753 		{
4754 			/* compose and store error message for future use */
4755 			if (NULL != error)
4756 			{
4757 				unknown_msg = zbx_dsprintf(NULL,
4758 						"Cannot evaluate function \"%s:%s.%s(%s)\": %s.",
4759 						items[i].host.host, items[i].key_orig, func->function,
4760 						func->parameter, error);
4761 
4762 				zbx_free(func->error);
4763 				zbx_free(error);
4764 			}
4765 			else
4766 			{
4767 				unknown_msg = zbx_dsprintf(NULL,
4768 						"Cannot evaluate function \"%s:%s.%s(%s)\".",
4769 						items[i].host.host, items[i].key_orig,
4770 						func->function, func->parameter);
4771 
4772 				zbx_free(func->error);
4773 			}
4774 
4775 			zbx_vector_ptr_append(unknown_msgs, unknown_msg);
4776 			ret_unknown = 1;
4777 		}
4778 
4779 		if (0 == ret_unknown)
4780 		{
4781 			func->value = zbx_strdup(func->value, value);
4782 		}
4783 		else
4784 		{
4785 			/* write a special token of unknown value with 'unknown' message number, like */
4786 			/* ZBX_UNKNOWN0, ZBX_UNKNOWN1 etc. not wrapped in () */
4787 			func->value = zbx_dsprintf(func->value, ZBX_UNKNOWN_STR "%d",
4788 					unknown_msgs->values_num - 1);
4789 		}
4790 	}
4791 
4792 	DCconfig_clean_items(items, errcodes, itemids.values_num);
4793 	zbx_vector_uint64_destroy(&itemids);
4794 
4795 	zbx_free(errcodes);
4796 	zbx_free(items);
4797 
4798 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4799 }
4800 
substitute_expression_functions_results(zbx_hashset_t * ifuncs,char * expression,char ** out,size_t * out_alloc,char ** error)4801 static int	substitute_expression_functions_results(zbx_hashset_t *ifuncs, char *expression, char **out,
4802 		size_t *out_alloc, char **error)
4803 {
4804 	char			*br, *bl;
4805 	size_t			out_offset = 0;
4806 	zbx_uint64_t		functionid;
4807 	zbx_func_t		*func;
4808 	zbx_ifunc_t		*ifunc;
4809 
4810 	for (br = expression, bl = strchr(expression, '{'); NULL != bl; bl = strchr(bl, '{'))
4811 	{
4812 		*bl = '\0';
4813 		zbx_strcpy_alloc(out, out_alloc, &out_offset, br);
4814 		*bl = '{';
4815 
4816 		if (NULL == (br = strchr(bl, '}')))
4817 		{
4818 			*error = zbx_strdup(*error, "Invalid trigger expression");
4819 			return FAIL;
4820 		}
4821 
4822 		*br = '\0';
4823 
4824 		ZBX_STR2UINT64(functionid, bl + 1);
4825 
4826 		*br++ = '}';
4827 		bl = br;
4828 
4829 		if (NULL == (ifunc = (zbx_ifunc_t *)zbx_hashset_search(ifuncs, &functionid)))
4830 		{
4831 			*error = zbx_dsprintf(*error, "Cannot obtain function"
4832 					" and item for functionid: " ZBX_FS_UI64, functionid);
4833 			return FAIL;
4834 		}
4835 
4836 		func = ifunc->func;
4837 
4838 		if (NULL != func->error)
4839 		{
4840 			*error = zbx_strdup(*error, func->error);
4841 			return FAIL;
4842 		}
4843 
4844 		if (NULL == func->value)
4845 		{
4846 			*error = zbx_strdup(*error, "Unexpected error while processing a trigger expression");
4847 			return FAIL;
4848 		}
4849 
4850 		if (SUCCEED != is_double_suffix(func->value, ZBX_FLAG_DOUBLE_SUFFIX) || '-' == *func->value)
4851 		{
4852 			zbx_chrcpy_alloc(out, out_alloc, &out_offset, '(');
4853 			zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value);
4854 			zbx_chrcpy_alloc(out, out_alloc, &out_offset, ')');
4855 		}
4856 		else
4857 			zbx_strcpy_alloc(out, out_alloc, &out_offset, func->value);
4858 	}
4859 
4860 	zbx_strcpy_alloc(out, out_alloc, &out_offset, br);
4861 
4862 	return SUCCEED;
4863 }
4864 
zbx_substitute_functions_results(zbx_hashset_t * ifuncs,zbx_vector_ptr_t * triggers)4865 static void	zbx_substitute_functions_results(zbx_hashset_t *ifuncs, zbx_vector_ptr_t *triggers)
4866 {
4867 	const char		*__function_name = "zbx_substitute_functions_results";
4868 
4869 	DC_TRIGGER		*tr;
4870 	char			*out = NULL;
4871 	size_t			out_alloc = TRIGGER_EXPRESSION_LEN_MAX;
4872 	int			i;
4873 
4874 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() ifuncs_num:%d tr_num:%d",
4875 			__function_name, ifuncs->num_data, triggers->values_num);
4876 
4877 	out = (char *)zbx_malloc(out, out_alloc);
4878 
4879 	for (i = 0; i < triggers->values_num; i++)
4880 	{
4881 		tr = (DC_TRIGGER *)triggers->values[i];
4882 
4883 		if (NULL != tr->new_error)
4884 			continue;
4885 
4886 		if( SUCCEED != substitute_expression_functions_results(ifuncs, tr->expression, &out, &out_alloc,
4887 				&tr->new_error))
4888 		{
4889 			tr->new_value = TRIGGER_VALUE_UNKNOWN;
4890 			continue;
4891 		}
4892 
4893 		zabbix_log(LOG_LEVEL_DEBUG, "%s() expression[%d]:'%s' => '%s'", __function_name, i,
4894 				tr->expression, out);
4895 
4896 		tr->expression = zbx_strdup(tr->expression, out);
4897 
4898 		if (TRIGGER_RECOVERY_MODE_RECOVERY_EXPRESSION == tr->recovery_mode)
4899 		{
4900 			if (SUCCEED != substitute_expression_functions_results(ifuncs,
4901 					tr->recovery_expression, &out, &out_alloc, &tr->new_error))
4902 			{
4903 				tr->new_value = TRIGGER_VALUE_UNKNOWN;
4904 				continue;
4905 			}
4906 
4907 			zabbix_log(LOG_LEVEL_DEBUG, "%s() recovery_expression[%d]:'%s' => '%s'", __function_name, i,
4908 					tr->recovery_expression, out);
4909 
4910 			tr->recovery_expression = zbx_strdup(tr->recovery_expression, out);
4911 		}
4912 	}
4913 
4914 	zbx_free(out);
4915 
4916 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4917 }
4918 
4919 /******************************************************************************
4920  *                                                                            *
4921  * Function: substitute_functions                                             *
4922  *                                                                            *
4923  * Purpose: substitute expression functions with their values                 *
4924  *                                                                            *
4925  * Parameters: triggers - [IN] vector of DC_TRIGGGER pointers, sorted by      *
4926  *                             triggerids                                     *
4927  *             unknown_msgs - vector for storing messages for NOTSUPPORTED    *
4928  *                            items and failed functions                      *
4929  *                                                                            *
4930  * Author: Alexei Vladishev, Alexander Vladishev, Aleksandrs Saveljevs        *
4931  *                                                                            *
4932  * Comments: example: "({15}>10) or ({123}=1)" => "(26.416>10) or (0=1)"      *
4933  *                                                                            *
4934  ******************************************************************************/
substitute_functions(zbx_vector_ptr_t * triggers,zbx_vector_ptr_t * unknown_msgs)4935 static void	substitute_functions(zbx_vector_ptr_t *triggers, zbx_vector_ptr_t *unknown_msgs)
4936 {
4937 	const char		*__function_name = "substitute_functions";
4938 
4939 	zbx_vector_uint64_t	functionids;
4940 	zbx_hashset_t		ifuncs, funcs;
4941 
4942 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
4943 
4944 	zbx_vector_uint64_create(&functionids);
4945 	zbx_extract_functionids(&functionids, triggers);
4946 
4947 	if (0 == functionids.values_num)
4948 		goto empty;
4949 
4950 	zbx_hashset_create(&ifuncs, triggers->values_num, ZBX_DEFAULT_UINT64_HASH_FUNC,
4951 			ZBX_DEFAULT_UINT64_COMPARE_FUNC);
4952 
4953 	zbx_hashset_create_ext(&funcs, triggers->values_num, func_hash_func, func_compare_func, func_clean,
4954 				ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC, ZBX_DEFAULT_MEM_FREE_FUNC);
4955 
4956 	zbx_populate_function_items(&functionids, &funcs, &ifuncs, triggers);
4957 
4958 	if (0 != ifuncs.num_data)
4959 	{
4960 		zbx_evaluate_item_functions(&funcs, unknown_msgs);
4961 		zbx_substitute_functions_results(&ifuncs, triggers);
4962 	}
4963 
4964 	zbx_hashset_destroy(&ifuncs);
4965 	zbx_hashset_destroy(&funcs);
4966 empty:
4967 	zbx_vector_uint64_destroy(&functionids);
4968 
4969 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
4970 }
4971 
4972 /******************************************************************************
4973  *                                                                            *
4974  * Function: evaluate_expressions                                             *
4975  *                                                                            *
4976  * Purpose: evaluate trigger expressions                                      *
4977  *                                                                            *
4978  * Parameters: triggers - [IN] vector of DC_TRIGGGER pointers, sorted by      *
4979  *                             triggerids                                     *
4980  *                                                                            *
4981  * Author: Alexei Vladishev                                                   *
4982  *                                                                            *
4983  ******************************************************************************/
evaluate_expressions(zbx_vector_ptr_t * triggers)4984 void	evaluate_expressions(zbx_vector_ptr_t *triggers)
4985 {
4986 	const char	*__function_name = "evaluate_expressions";
4987 
4988 	DB_EVENT		event;
4989 	DC_TRIGGER		*tr;
4990 	int			i;
4991 	double			expr_result;
4992 	zbx_vector_ptr_t	unknown_msgs;	    /* pointers to messages about origins of 'unknown' values */
4993 	char			err[MAX_STRING_LEN];
4994 
4995 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() tr_num:%d", __function_name, triggers->values_num);
4996 
4997 	event.object = EVENT_OBJECT_TRIGGER;
4998 
4999 	for (i = 0; i < triggers->values_num; i++)
5000 	{
5001 		tr = (DC_TRIGGER *)triggers->values[i];
5002 
5003 		event.value = tr->value;
5004 
5005 		if (SUCCEED != expand_trigger_macros(&event, tr, err, sizeof(err)))
5006 		{
5007 			tr->new_error = zbx_dsprintf(tr->new_error, "Cannot evaluate expression: %s", err);
5008 			tr->new_value = TRIGGER_VALUE_UNKNOWN;
5009 		}
5010 	}
5011 
5012 	/* Assumption: most often there will be no NOTSUPPORTED items and function errors. */
5013 	/* Therefore initialize error messages vector but do not reserve any space. */
5014 	zbx_vector_ptr_create(&unknown_msgs);
5015 
5016 	substitute_functions(triggers, &unknown_msgs);
5017 
5018 	/* calculate new trigger values based on their recovery modes and expression evaluations */
5019 	for (i = 0; i < triggers->values_num; i++)
5020 	{
5021 		tr = (DC_TRIGGER *)triggers->values[i];
5022 
5023 		if (NULL != tr->new_error)
5024 			continue;
5025 
5026 		if (SUCCEED != evaluate(&expr_result, tr->expression, err, sizeof(err), &unknown_msgs))
5027 		{
5028 			tr->new_error = zbx_strdup(tr->new_error, err);
5029 			tr->new_value = TRIGGER_VALUE_UNKNOWN;
5030 			continue;
5031 		}
5032 
5033 		/* trigger expression evaluates to true, set PROBLEM value */
5034 		if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5035 		{
5036 			if (0 == (tr->flags & ZBX_DC_TRIGGER_PROBLEM_EXPRESSION))
5037 			{
5038 				/* trigger value should remain unchanged and no PROBLEM events should be generated if */
5039 				/* problem expression evaluates to true, but trigger recalculation was initiated by a */
5040 				/* time-based function or a new value of an item in recovery expression */
5041 				tr->new_value = TRIGGER_VALUE_NONE;
5042 			}
5043 			else
5044 				tr->new_value = TRIGGER_VALUE_PROBLEM;
5045 
5046 			continue;
5047 		}
5048 
5049 		/* otherwise try to recover trigger by setting OK value */
5050 		if (TRIGGER_VALUE_PROBLEM == tr->value && TRIGGER_RECOVERY_MODE_NONE != tr->recovery_mode)
5051 		{
5052 			if (TRIGGER_RECOVERY_MODE_EXPRESSION == tr->recovery_mode)
5053 			{
5054 				tr->new_value = TRIGGER_VALUE_OK;
5055 				continue;
5056 			}
5057 
5058 			/* processing recovery expression mode */
5059 			if (SUCCEED != evaluate(&expr_result, tr->recovery_expression, err, sizeof(err), &unknown_msgs))
5060 			{
5061 				tr->new_error = zbx_strdup(tr->new_error, err);
5062 				tr->new_value = TRIGGER_VALUE_UNKNOWN;
5063 				continue;
5064 			}
5065 
5066 			if (SUCCEED != zbx_double_compare(expr_result, 0.0))
5067 			{
5068 				tr->new_value = TRIGGER_VALUE_OK;
5069 				continue;
5070 			}
5071 		}
5072 
5073 		/* no changes, keep the old value */
5074 		tr->new_value = TRIGGER_VALUE_NONE;
5075 	}
5076 
5077 	zbx_vector_ptr_clear_ext(&unknown_msgs, zbx_ptr_free);
5078 	zbx_vector_ptr_destroy(&unknown_msgs);
5079 
5080 	if (SUCCEED == ZBX_CHECK_LOG_LEVEL(LOG_LEVEL_DEBUG))
5081 	{
5082 		for (i = 0; i < triggers->values_num; i++)
5083 		{
5084 			tr = (DC_TRIGGER *)triggers->values[i];
5085 
5086 			if (NULL != tr->new_error)
5087 			{
5088 				zabbix_log(LOG_LEVEL_DEBUG, "%s():expression [%s] cannot be evaluated: %s",
5089 						__function_name, tr->expression, tr->new_error);
5090 			}
5091 		}
5092 
5093 		zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
5094 	}
5095 }
5096 
5097 /******************************************************************************
5098  *                                                                            *
5099  * Function: process_simple_macro_token                                       *
5100  *                                                                            *
5101  * Purpose: trying to resolve the discovery macros in item key parameters     *
5102  *          in simple macros like {host:key[].func()}                         *
5103  *                                                                            *
5104  ******************************************************************************/
process_simple_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5105 static int	process_simple_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5106 		char *error, size_t max_error_len)
5107 {
5108 	char	*key = NULL, *replace_to = NULL, *dot, *params;
5109 	size_t	replace_to_offset = 0, replace_to_alloc = 128, lld_start, lld_end;
5110 	int	ret = FAIL;
5111 
5112 	if ('{' == (*data)[token->data.simple_macro.host.l] &&
5113 			NULL == macro_in_list(*data, token->data.simple_macro.host, simple_host_macros, NULL))
5114 	{
5115 		goto out;
5116 	}
5117 
5118 	replace_to = (char *)zbx_malloc(NULL, replace_to_alloc);
5119 
5120 	lld_start = token->data.simple_macro.key.l;
5121 	lld_end = token->data.simple_macro.func_param.r - 1;
5122 	dot = *data + token->data.simple_macro.key.r + 1;
5123 	params = *data + token->data.simple_macro.func_param.l + 1;
5124 
5125 	/* extract key and substitute macros */
5126 	*dot = '\0';
5127 	key = zbx_strdup(key, *data + token->data.simple_macro.key.l);
5128 	substitute_key_macros(&key, NULL, NULL, jp_row, MACRO_TYPE_ITEM_KEY, NULL, 0);
5129 	*dot = '.';
5130 
5131 	zbx_strcpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, key);
5132 	zbx_strncpy_alloc(&replace_to, &replace_to_alloc, &replace_to_offset, dot, params - dot);
5133 
5134 	/* substitute macros in function parameters */
5135 	if (SUCCEED != substitute_function_lld_param(params, *data + lld_end - params + 1, 0, &replace_to,
5136 			&replace_to_alloc, &replace_to_offset, jp_row, error, max_error_len))
5137 	{
5138 		goto out;
5139 	}
5140 
5141 	/* replace LLD part in original string and adjust token boundary */
5142 	zbx_replace_string(data, lld_start, &lld_end, replace_to);
5143 	token->loc.r += lld_end - (token->data.simple_macro.func_param.r - 1);
5144 
5145 	ret = SUCCEED;
5146 out:
5147 	zbx_free(replace_to);
5148 	zbx_free(key);
5149 
5150 	return ret;
5151 }
5152 
5153 /******************************************************************************
5154  *                                                                            *
5155  * Function: process_lld_macro_token                                          *
5156  *                                                                            *
5157  * Purpose: expand discovery macro in expression                              *
5158  *                                                                            *
5159  * Parameters: data      - [IN/OUT] the expression containing lld macro       *
5160  *             token     - [IN/OUT] the token with lld macro location data    *
5161  *             flags     - [IN] the flags passed to                           *
5162  *                                  subtitute_discovery_macros() function     *
5163  *             jp_row    - [IN] discovery data                                *
5164  *             error     - [OUT] should be not NULL if                        *
5165  *                               ZBX_MACRO_NUMERIC flag is set                *
5166  *             error_len - [IN] the size of error buffer                      *
5167  *                                                                            *
5168  * Return value: Always SUCCEED if numeric flag is not set, otherwise SUCCEED *
5169  *               if all discovery macros resolved to numeric values,          *
5170  *               otherwise FAIL with an error message.                        *
5171  *                                                                            *
5172  ******************************************************************************/
process_lld_macro_token(char ** data,zbx_token_t * token,int flags,const struct zbx_json_parse * jp_row,char * error,size_t error_len)5173 static int	process_lld_macro_token(char **data, zbx_token_t *token, int flags, const struct zbx_json_parse *jp_row,
5174 		char *error, size_t error_len)
5175 {
5176 	char	c, *replace_to = NULL;
5177 	int	ret = SUCCEED, l ,r;
5178 	size_t	replace_to_alloc = 0;
5179 
5180 	if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5181 	{
5182 		l = token->data.lld_func_macro.macro.l;
5183 		r = token->data.lld_func_macro.macro.r;
5184 	}
5185 	else
5186 	{
5187 		l = token->loc.l;
5188 		r = token->loc.r;
5189 	}
5190 
5191 	c = (*data)[r + 1];
5192 	(*data)[r + 1] = '\0';
5193 
5194 	if (SUCCEED != zbx_json_value_by_name_dyn(jp_row, *data + l, &replace_to, &replace_to_alloc, NULL))
5195 	{
5196 		zabbix_log(LOG_LEVEL_DEBUG, "cannot substitute macro \"%s\": not found in value set", *data + l);
5197 
5198 		if (0 != (flags & ZBX_TOKEN_NUMERIC))
5199 		{
5200 			zbx_snprintf(error, error_len, "no value for macro \"%s\"", *data + l);
5201 			ret = FAIL;
5202 		}
5203 
5204 		(*data)[r + 1] = c;
5205 		zbx_free(replace_to);
5206 
5207 		return ret;
5208 	}
5209 
5210 	(*data)[r + 1] = c;
5211 
5212 	if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
5213 	{
5214 		replace_to_alloc = 0;
5215 		if (SUCCEED != (zbx_calculate_macro_function(*data, &token->data.lld_func_macro, &replace_to)))
5216 		{
5217 			int	len = token->data.lld_func_macro.func.r - token->data.lld_func_macro.func.l + 1;
5218 
5219 			zabbix_log(LOG_LEVEL_DEBUG, "cannot execute function \"%.*s\"", len,
5220 					*data + token->data.lld_func_macro.func.l);
5221 
5222 			if (0 != (flags & ZBX_TOKEN_NUMERIC))
5223 			{
5224 				zbx_snprintf(error, error_len, "unable to execute function \"%.*s\"", len,
5225 						*data + token->data.lld_func_macro.func.l);
5226 				ret = FAIL;
5227 			}
5228 
5229 			zbx_free(replace_to);
5230 
5231 			return ret;
5232 		}
5233 	}
5234 
5235 	if (0 != (flags & ZBX_TOKEN_NUMERIC))
5236 	{
5237 		if (SUCCEED == is_double_suffix(replace_to, ZBX_FLAG_DOUBLE_SUFFIX))
5238 		{
5239 			wrap_negative_double_suffix(&replace_to, &replace_to_alloc);
5240 		}
5241 		else
5242 		{
5243 			zbx_free(replace_to);
5244 			zbx_snprintf(error, error_len, "not numeric value in macro \"%.*s\"",
5245 					(int)(token->loc.r - token->loc.l + 1), *data + token->loc.l);
5246 			return FAIL;
5247 		}
5248 	}
5249 	else if (0 != (flags & ZBX_TOKEN_JSON))
5250 	{
5251 		zbx_json_escape(&replace_to);
5252 	}
5253 	else if (0 != (flags & ZBX_TOKEN_XML))
5254 	{
5255 		char	*replace_to_esc;
5256 
5257 		replace_to_esc = xml_escape_dyn(replace_to);
5258 		zbx_free(replace_to);
5259 		replace_to = replace_to_esc;
5260 	}
5261 	else if (0 != (flags & ZBX_TOKEN_REGEXP))
5262 	{
5263 		zbx_regexp_escape(&replace_to);
5264 	}
5265 	else if (0 != (flags & ZBX_TOKEN_REGEXP_OUTPUT))
5266 	{
5267 		char	*replace_to_esc;
5268 
5269 		replace_to_esc = zbx_dyn_escape_string(replace_to, "\\");
5270 		zbx_free(replace_to);
5271 		replace_to = replace_to_esc;
5272 	}
5273 	else if (0 != (flags & ZBX_TOKEN_XPATH))
5274 	{
5275 		xml_escape_xpath(&replace_to);
5276 	}
5277 	else if (0 != (flags & ZBX_TOKEN_JSONPATH) && ZBX_TOKEN_LLD_MACRO == token->type)
5278 	{
5279 		char	*replace_to_esc;
5280 
5281 		replace_to_esc = zbx_dyn_escape_string(replace_to, "\\\"");
5282 		zbx_free(replace_to);
5283 		replace_to = replace_to_esc;
5284 	}
5285 
5286 	if (NULL != replace_to)
5287 	{
5288 		size_t	data_alloc, data_len;
5289 
5290 		data_alloc = data_len = strlen(*data) + 1;
5291 		token->loc.r += zbx_replace_mem_dyn(data, &data_alloc, &data_len, token->loc.l,
5292 				token->loc.r - token->loc.l + 1, replace_to, strlen(replace_to));
5293 		zbx_free(replace_to);
5294 	}
5295 
5296 	return SUCCEED;
5297 }
5298 
5299 /******************************************************************************
5300  *                                                                            *
5301  * Function: process_user_macro_token                                         *
5302  *                                                                            *
5303  * Purpose: expand discovery macro in user macro context                      *
5304  *                                                                            *
5305  * Parameters: data      - [IN/OUT] the expression containing lld macro       *
5306  *             token     - [IN/OUT] the token with user macro location data   *
5307  *             jp_row    - [IN] discovery data                                *
5308  *                                                                            *
5309  ******************************************************************************/
process_user_macro_token(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row)5310 static void	process_user_macro_token(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row)
5311 {
5312 	int			force_quote;
5313 	size_t			context_r;
5314 	char			*context, *context_esc;
5315 	zbx_token_user_macro_t	*macro = &token->data.user_macro;
5316 
5317 	/* user macro without context, nothing to replace */
5318 	if (0 == token->data.user_macro.context.l)
5319 		return;
5320 
5321 	force_quote = ('"' == (*data)[macro->context.l]);
5322 	context = zbx_user_macro_unquote_context_dyn(*data + macro->context.l, macro->context.r - macro->context.l + 1);
5323 
5324 	/* substitute_lld_macros() can't fail with ZBX_TOKEN_LLD_MACRO or ZBX_TOKEN_LLD_FUNC_MACRO flags set */
5325 	substitute_lld_macros(&context, jp_row, ZBX_TOKEN_LLD_MACRO | ZBX_TOKEN_LLD_FUNC_MACRO, NULL, 0);
5326 
5327 	context_esc = zbx_user_macro_quote_context_dyn(context, force_quote);
5328 
5329 	context_r = macro->context.r;
5330 	zbx_replace_string(data, macro->context.l, &context_r, context_esc);
5331 
5332 	token->loc.r += context_r - macro->context.r;
5333 
5334 	zbx_free(context_esc);
5335 	zbx_free(context);
5336 }
5337 
5338 /******************************************************************************
5339  *                                                                            *
5340  * Function: substitute_func_macro                                            *
5341  *                                                                            *
5342  * Purpose: substitute lld macros in function macro parameters                *
5343  *                                                                            *
5344  * Parameters: data   - [IN/OUT] pointer to a buffer                          *
5345  *             token  - [IN/OUT] the token with function macro location data  *
5346  *             jp_row - [IN] discovery data                                   *
5347  *             error  - [OUT] error message                                   *
5348  *             max_error_len - [IN] the size of error buffer                  *
5349  *                                                                            *
5350  * Return value: SUCCEED - the lld macros were resolved successfully          *
5351  *               FAIL - otherwise                                             *
5352  *                                                                            *
5353  ******************************************************************************/
substitute_func_macro(char ** data,zbx_token_t * token,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5354 static int	substitute_func_macro(char **data, zbx_token_t *token, const struct zbx_json_parse *jp_row,
5355 		char *error, size_t max_error_len)
5356 {
5357 	int	ret;
5358 	char	*exp = NULL;
5359 	size_t	exp_alloc = 0, exp_offset = 0;
5360 	size_t	par_l = token->data.func_macro.func_param.l, par_r = token->data.func_macro.func_param.r;
5361 
5362 	ret = substitute_function_lld_param(*data + par_l + 1, par_r - (par_l + 1), 0, &exp, &exp_alloc, &exp_offset,
5363 			jp_row, error, max_error_len);
5364 
5365 	if (SUCCEED == ret)
5366 	{
5367 		/* copy what is left including closing parenthesis and replace function parameters */
5368 		zbx_strncpy_alloc(&exp, &exp_alloc, &exp_offset, *data + par_r, token->loc.r - (par_r - 1));
5369 		zbx_replace_string(data, par_l + 1, &token->loc.r, exp);
5370 	}
5371 
5372 	zbx_free(exp);
5373 
5374 	return ret;
5375 }
5376 
5377 /******************************************************************************
5378  *                                                                            *
5379  * Function: substitute_lld_macros                                            *
5380  *                                                                            *
5381  * Parameters: data   - [IN/OUT] pointer to a buffer                          *
5382  *             jp_row - [IN] discovery data                                   *
5383  *             flags  - [IN] ZBX_MACRO_ANY - all LLD macros will be resolved  *
5384  *                            without validation of the value type            *
5385  *                           ZBX_MACRO_NUMERIC - values for LLD macros should *
5386  *                            be numeric                                      *
5387  *                           ZBX_MACRO_SIMPLE - LLD macros, located in the    *
5388  *                            item key parameters in simple macros will be    *
5389  *                            resolved considering quotes.                    *
5390  *                            Flag ZBX_MACRO_NUMERIC doesn't affect these     *
5391  *                            macros.                                         *
5392  *                           ZBX_MACRO_FUNC - function macros will be         *
5393  *                            skipped (lld macros inside function macros will *
5394  *                            be ignored) for macros specified in func_macros *
5395  *                            array                                           *
5396  *             error  - [OUT] should be not NULL if ZBX_MACRO_NUMERIC flag is *
5397  *                            set                                             *
5398  *             max_error_len - [IN] the size of error buffer                  *
5399  *                                                                            *
5400  * Return value: Always SUCCEED if numeric flag is not set, otherwise SUCCEED *
5401  *               if all discovery macros resolved to numeric values,          *
5402  *               otherwise FAIL with an error message.                        *
5403  *                                                                            *
5404  * Author: Alexander Vladishev                                                *
5405  *                                                                            *
5406  ******************************************************************************/
substitute_lld_macros(char ** data,const struct zbx_json_parse * jp_row,int flags,char * error,size_t max_error_len)5407 int	substitute_lld_macros(char **data, const struct zbx_json_parse *jp_row, int flags, char *error,
5408 		size_t max_error_len)
5409 {
5410 	const char	*__function_name = "substitute_lld_macros";
5411 
5412 	int		ret = SUCCEED, pos = 0;
5413 	zbx_token_t	token;
5414 
5415 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
5416 
5417 	while (SUCCEED == ret && SUCCEED == zbx_token_find(*data, pos, &token, ZBX_TOKEN_SEARCH_BASIC))
5418 	{
5419 		if (0 != (token.type & flags))
5420 		{
5421 			switch (token.type)
5422 			{
5423 				case ZBX_TOKEN_LLD_MACRO:
5424 				case ZBX_TOKEN_LLD_FUNC_MACRO:
5425 					ret = process_lld_macro_token(data, &token, flags, jp_row, error,
5426 							max_error_len);
5427 					pos = token.loc.r;
5428 					break;
5429 				case ZBX_TOKEN_USER_MACRO:
5430 					process_user_macro_token(data, &token, jp_row);
5431 					pos = token.loc.r;
5432 					break;
5433 				case ZBX_TOKEN_SIMPLE_MACRO:
5434 					process_simple_macro_token(data, &token, jp_row, error, max_error_len);
5435 					pos = token.loc.r;
5436 					break;
5437 				case ZBX_TOKEN_FUNC_MACRO:
5438 					if (NULL != macro_in_list(*data, token.data.func_macro.macro, mod_macros, NULL))
5439 					{
5440 						ret = substitute_func_macro(data, &token, jp_row, error, max_error_len);
5441 						pos = token.loc.r;
5442 					}
5443 					break;
5444 			}
5445 		}
5446 
5447 		pos++;
5448 	}
5449 
5450 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __function_name, zbx_result_string(ret), *data);
5451 
5452 	return ret;
5453 }
5454 
5455 typedef struct
5456 {
5457 	zbx_uint64_t			*hostid;
5458 	DC_ITEM				*dc_item;
5459 	const struct zbx_json_parse	*jp_row;
5460 	int				macro_type;
5461 }
5462 replace_key_param_data_t;
5463 
5464 /******************************************************************************
5465  *                                                                            *
5466  * Function: replace_key_param                                                *
5467  *                                                                            *
5468  * Comments: auxiliary function for substitute_key_macros()                   *
5469  *                                                                            *
5470  ******************************************************************************/
replace_key_param_cb(const char * data,int key_type,int level,int num,int quoted,void * cb_data,char ** param)5471 static int	replace_key_param_cb(const char *data, int key_type, int level, int num, int quoted, void *cb_data,
5472 			char **param)
5473 {
5474 	replace_key_param_data_t	*replace_key_param_data = (replace_key_param_data_t *)cb_data;
5475 	zbx_uint64_t			*hostid = replace_key_param_data->hostid;
5476 	DC_ITEM				*dc_item = replace_key_param_data->dc_item;
5477 	const struct zbx_json_parse	*jp_row = replace_key_param_data->jp_row;
5478 	int				macro_type = replace_key_param_data->macro_type, ret = SUCCEED;
5479 
5480 	ZBX_UNUSED(num);
5481 
5482 	if (ZBX_KEY_TYPE_ITEM == key_type && 0 == level)
5483 		return ret;
5484 
5485 	if (NULL == strchr(data, '{'))
5486 		return ret;
5487 
5488 	*param = zbx_strdup(NULL, data);
5489 
5490 	if (0 != level)
5491 		unquote_key_param(*param);
5492 
5493 	if (NULL == jp_row)
5494 		substitute_simple_macros(NULL, NULL, NULL, NULL, hostid, NULL, dc_item, NULL, NULL,
5495 				param, macro_type, NULL, 0);
5496 	else
5497 		substitute_lld_macros(param, jp_row, ZBX_MACRO_ANY, NULL, 0);
5498 
5499 	if (0 != level)
5500 	{
5501 		if (FAIL == (ret = quote_key_param(param, quoted)))
5502 			zbx_free(*param);
5503 	}
5504 
5505 	return ret;
5506 }
5507 
5508 /******************************************************************************
5509  *                                                                            *
5510  * Function: substitute_key_macros                                            *
5511  *                                                                            *
5512  * Purpose: safely substitutes macros in parameters of an item key and OID    *
5513  *                                                                            *
5514  * Example:  key                     | macro  | result            | return    *
5515  *          -------------------------+--------+-------------------+---------  *
5516  *           echo.sh[{$MACRO}]       | a      | echo.sh[a]        | SUCCEED   *
5517  *           echo.sh[{$MACRO}]       | a\     | echo.sh[a\]       | SUCCEED   *
5518  *           echo.sh["{$MACRO}"]     | a      | echo.sh["a"]      | SUCCEED   *
5519  *           echo.sh["{$MACRO}"]     | a\     | undefined         | FAIL      *
5520  *           echo.sh[{$MACRO}]       |  a     | echo.sh[" a"]     | SUCCEED   *
5521  *           echo.sh[{$MACRO}]       |  a\    | undefined         | FAIL      *
5522  *           echo.sh["{$MACRO}"]     |  a     | echo.sh[" a"]     | SUCCEED   *
5523  *           echo.sh["{$MACRO}"]     |  a\    | undefined         | FAIL      *
5524  *           echo.sh[{$MACRO}]       | "a"    | echo.sh["\"a\""]  | SUCCEED   *
5525  *           echo.sh[{$MACRO}]       | "a"\   | undefined         | FAIL      *
5526  *           echo.sh["{$MACRO}"]     | "a"    | echo.sh["\"a\""]  | SUCCEED   *
5527  *           echo.sh["{$MACRO}"]     | "a"\   | undefined         | FAIL      *
5528  *           echo.sh[{$MACRO}]       | a,b    | echo.sh["a,b"]    | SUCCEED   *
5529  *           echo.sh[{$MACRO}]       | a,b\   | undefined         | FAIL      *
5530  *           echo.sh["{$MACRO}"]     | a,b    | echo.sh["a,b"]    | SUCCEED   *
5531  *           echo.sh["{$MACRO}"]     | a,b\   | undefined         | FAIL      *
5532  *           echo.sh[{$MACRO}]       | a]     | echo.sh["a]"]     | SUCCEED   *
5533  *           echo.sh[{$MACRO}]       | a]\    | undefined         | FAIL      *
5534  *           echo.sh["{$MACRO}"]     | a]     | echo.sh["a]"]     | SUCCEED   *
5535  *           echo.sh["{$MACRO}"]     | a]\    | undefined         | FAIL      *
5536  *           echo.sh[{$MACRO}]       | [a     | echo.sh["a]"]     | SUCCEED   *
5537  *           echo.sh[{$MACRO}]       | [a\    | undefined         | FAIL      *
5538  *           echo.sh["{$MACRO}"]     | [a     | echo.sh["[a"]     | SUCCEED   *
5539  *           echo.sh["{$MACRO}"]     | [a\    | undefined         | FAIL      *
5540  *           ifInOctets.{#SNMPINDEX} | 1      | ifInOctets.1      | SUCCEED   *
5541  *                                                                            *
5542  ******************************************************************************/
substitute_key_macros(char ** data,zbx_uint64_t * hostid,DC_ITEM * dc_item,const struct zbx_json_parse * jp_row,int macro_type,char * error,size_t maxerrlen)5543 int	substitute_key_macros(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item, const struct zbx_json_parse *jp_row,
5544 		int macro_type, char *error, size_t maxerrlen)
5545 {
5546 	const char			*__function_name = "substitute_key_macros";
5547 	replace_key_param_data_t	replace_key_param_data;
5548 	int				key_type, ret;
5549 
5550 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, *data);
5551 
5552 	replace_key_param_data.hostid = hostid;
5553 	replace_key_param_data.dc_item = dc_item;
5554 	replace_key_param_data.jp_row = jp_row;
5555 	replace_key_param_data.macro_type = macro_type;
5556 
5557 	switch (macro_type)
5558 	{
5559 		case MACRO_TYPE_ITEM_KEY:
5560 			key_type = ZBX_KEY_TYPE_ITEM;
5561 			break;
5562 		case MACRO_TYPE_SNMP_OID:
5563 			key_type = ZBX_KEY_TYPE_OID;
5564 			break;
5565 		default:
5566 			THIS_SHOULD_NEVER_HAPPEN;
5567 			exit(EXIT_FAILURE);
5568 	}
5569 
5570 	ret = replace_key_params_dyn(data, key_type, replace_key_param_cb, &replace_key_param_data, error, maxerrlen);
5571 
5572 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s data:'%s'", __function_name, zbx_result_string(ret), *data);
5573 
5574 	return ret;
5575 }
5576 
5577 /******************************************************************************
5578  *                                                                            *
5579  * Function: substitute_function_lld_param                                    *
5580  *                                                                            *
5581  * Purpose: substitute lld macros in function parameters                      *
5582  *                                                                            *
5583  * Parameters: e            - [IN] the function parameter list without        *
5584  *                                 enclosing parentheses:                     *
5585  *                                       <p1>, <p2>, ...<pN>                  *
5586  *             len          - [IN] the length of function parameter list      *
5587  *             key_in_param - [IN] 1 - the first parameter must be host:key   *
5588  *                                 0 - otherwise                              *
5589  *             exp          - [IN/OUT] output buffer                          *
5590  *             exp_alloc    - [IN/OUT] the size of output buffer              *
5591  *             exp_offset   - [IN/OUT] the current position in output buffer  *
5592  *             jp_row - [IN] discovery data                                   *
5593  *             error  - [OUT] error message                                   *
5594  *             max_error_len - [IN] the size of error buffer                  *
5595  *                                                                            *
5596  * Return value: SUCCEED - the lld macros were resolved successfully          *
5597  *               FAIL - otherwise                                             *
5598  *                                                                            *
5599  ******************************************************************************/
substitute_function_lld_param(const char * e,size_t len,unsigned char key_in_param,char ** exp,size_t * exp_alloc,size_t * exp_offset,const struct zbx_json_parse * jp_row,char * error,size_t max_error_len)5600 int	substitute_function_lld_param(const char *e, size_t len, unsigned char key_in_param,
5601 		char **exp, size_t *exp_alloc, size_t *exp_offset, const struct zbx_json_parse *jp_row,
5602 		char *error, size_t max_error_len)
5603 {
5604 	const char	*__function_name = "substitute_function_lld_param";
5605 	int		ret = SUCCEED;
5606 	size_t		sep_pos;
5607 	char		*param = NULL;
5608 	const char	*p;
5609 
5610 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5611 
5612 	if (0 == len)
5613 	{
5614 		zbx_strcpy_alloc(exp, exp_alloc, exp_offset, "");
5615 		goto out;
5616 	}
5617 
5618 	for (p = e; p < len + e ; p += sep_pos + 1)
5619 	{
5620 		size_t	param_pos, param_len, rel_len = len - (p - e);
5621 		int	quoted;
5622 
5623 		zbx_function_param_parse(p, &param_pos, &param_len, &sep_pos);
5624 
5625 		/* copy what was before the parameter */
5626 		zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p, param_pos);
5627 
5628 		/* prepare the parameter (macro substitutions and quoting) */
5629 
5630 		zbx_free(param);
5631 		param = zbx_function_param_unquote_dyn(p + param_pos, param_len, &quoted);
5632 
5633 		if (1 == key_in_param && p == e)
5634 		{
5635 			char	*key = NULL, *host = NULL;
5636 
5637 			if (SUCCEED != parse_host_key(param, &host, &key) ||
5638 					SUCCEED != substitute_key_macros(&key, NULL, NULL, jp_row,
5639 							MACRO_TYPE_ITEM_KEY, NULL, 0))
5640 			{
5641 				zbx_snprintf(error, max_error_len, "Invalid first parameter \"%s\"", param);
5642 				zbx_free(host);
5643 				zbx_free(key);
5644 				ret = FAIL;
5645 				goto out;
5646 			}
5647 
5648 			zbx_free(param);
5649 			if (NULL != host)
5650 			{
5651 				param = zbx_dsprintf(NULL, "%s:%s", host, key);
5652 				zbx_free(host);
5653 				zbx_free(key);
5654 			}
5655 			else
5656 				param = key;
5657 		}
5658 		else
5659 			substitute_lld_macros(&param, jp_row, ZBX_MACRO_ANY, NULL, 0);
5660 
5661 		if (SUCCEED != zbx_function_param_quote(&param, quoted))
5662 		{
5663 			zbx_snprintf(error, max_error_len, "Cannot quote parameter \"%s\"", param);
5664 			ret = FAIL;
5665 			goto out;
5666 		}
5667 
5668 		/* copy the parameter */
5669 		zbx_strcpy_alloc(exp, exp_alloc, exp_offset, param);
5670 
5671 		/* copy what was after the parameter (including separator) */
5672 		if (sep_pos < rel_len)
5673 			zbx_strncpy_alloc(exp, exp_alloc, exp_offset, p + param_pos + param_len,
5674 					sep_pos - param_pos - param_len + 1);
5675 	}
5676 out:
5677 	zbx_free(param);
5678 
5679 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
5680 
5681 	return ret;
5682 }
5683 
5684 /******************************************************************************
5685  *                                                                            *
5686  * Function: substitute_macros_in_json_pairs                                  *
5687  *                                                                            *
5688  * Purpose: substitute LLD macros in JSON pairs                               *
5689  *                                                                            *
5690  * Parameters: data   -    [IN/OUT] pointer to a buffer that JSON pair        *
5691  *             jp_row -    [IN] discovery data for LLD macro substitution     *
5692  *             error  -    [OUT] reason for JSON pair parsing failure         *
5693  *             maxerrlen - [IN] the size of error buffer                      *
5694  *                                                                            *
5695  * Return value: SUCCEED or FAIL if cannot parse JSON pair                    *
5696  *                                                                            *
5697  ******************************************************************************/
substitute_macros_in_json_pairs(char ** data,const struct zbx_json_parse * jp_row,char * error,int maxerrlen)5698 int	substitute_macros_in_json_pairs(char **data, const struct zbx_json_parse *jp_row, char *error,
5699 		int maxerrlen)
5700 {
5701 	const char		*__function_name = "substitute_macros_in_json_pairs";
5702 	struct zbx_json_parse	jp_array, jp_object;
5703 	struct zbx_json		json;
5704 	const char		*member, *element = NULL;
5705 	char			name[MAX_STRING_LEN], value[MAX_STRING_LEN], *p_name = NULL, *p_value = NULL;
5706 	int			ret = SUCCEED;
5707 
5708 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5709 
5710 	if ('\0' == **data)
5711 		goto exit;
5712 
5713 	if (SUCCEED != zbx_json_open(*data, &jp_array))
5714 	{
5715 		zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
5716 		ret = FAIL;
5717 		goto exit;
5718 	}
5719 
5720 	if (NULL == (element = zbx_json_next(&jp_array, element)))
5721 	{
5722 		zbx_strlcpy(error, "cannot parse query fields: array is empty", maxerrlen);
5723 		ret = FAIL;
5724 		goto exit;
5725 	}
5726 
5727 	zbx_json_initarray(&json, ZBX_JSON_STAT_BUF_LEN);
5728 
5729 	do
5730 	{
5731 		if (SUCCEED != zbx_json_brackets_open(element, &jp_object) ||
5732 				NULL == (member = zbx_json_pair_next(&jp_object, NULL, name, sizeof(name))) ||
5733 				NULL == zbx_json_decodevalue(member, value, sizeof(value), NULL))
5734 		{
5735 			zbx_snprintf(error, maxerrlen, "cannot parse query fields: %s", zbx_json_strerror());
5736 			ret = FAIL;
5737 			goto clean;
5738 		}
5739 
5740 		p_name = zbx_strdup(NULL, name);
5741 		p_value = zbx_strdup(NULL, value);
5742 
5743 		substitute_lld_macros(&p_name, jp_row, ZBX_MACRO_ANY, NULL, 0);
5744 		substitute_lld_macros(&p_value, jp_row, ZBX_MACRO_ANY, NULL, 0);
5745 
5746 		zbx_json_addobject(&json, NULL);
5747 		zbx_json_addstring(&json, p_name, p_value, ZBX_JSON_TYPE_STRING);
5748 		zbx_json_close(&json);
5749 		zbx_free(p_name);
5750 		zbx_free(p_value);
5751 	}
5752 	while (NULL != (element = zbx_json_next(&jp_array, element)));
5753 
5754 	zbx_free(*data);
5755 	*data = zbx_strdup(NULL, json.buffer);
5756 clean:
5757 	zbx_json_free(&json);
5758 exit:
5759 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
5760 
5761 	return ret;
5762 }
5763 
5764 #ifdef HAVE_LIBXML2
5765 /******************************************************************************
5766  *                                                                            *
5767  * Function: substitute_macros_in_xml_elements                                *
5768  *                                                                            *
5769  * Comments: auxiliary function for substitute_macros_xml()                   *
5770  *                                                                            *
5771  ******************************************************************************/
substitute_macros_in_xml_elements(const DC_ITEM * item,const struct zbx_json_parse * jp_row,xmlNode * node)5772 static void	substitute_macros_in_xml_elements(const DC_ITEM *item, const struct zbx_json_parse *jp_row,
5773 		xmlNode *node)
5774 {
5775 	xmlChar	*value;
5776 	xmlAttr	*attr;
5777 	char	*value_tmp;
5778 
5779 	for (;NULL != node; node = node->next)
5780 	{
5781 		switch (node->type)
5782 		{
5783 			case XML_TEXT_NODE:
5784 				if (NULL == (value = xmlNodeGetContent(node)))
5785 					break;
5786 
5787 				value_tmp = zbx_strdup(NULL, (const char *)value);
5788 
5789 				if (NULL != item)
5790 				{
5791 					substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
5792 							NULL, &value_tmp, MACRO_TYPE_HTTP_XML, NULL, 0);
5793 				}
5794 				else
5795 					substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_XML, NULL, 0);
5796 
5797 				xmlNodeSetContent(node, (xmlChar *)value_tmp);
5798 
5799 				zbx_free(value_tmp);
5800 				xmlFree(value);
5801 				break;
5802 			case XML_CDATA_SECTION_NODE:
5803 				if (NULL == (value = xmlNodeGetContent(node)))
5804 					break;
5805 
5806 				value_tmp = zbx_strdup(NULL, (const char *)value);
5807 
5808 				if (NULL != item)
5809 				{
5810 					substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host, item, NULL,
5811 							NULL, &value_tmp, MACRO_TYPE_HTTP_RAW, NULL, 0);
5812 				}
5813 				else
5814 					substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_ANY, NULL, 0);
5815 
5816 				xmlNodeSetContent(node, (xmlChar *)value_tmp);
5817 
5818 				zbx_free(value_tmp);
5819 				xmlFree(value);
5820 				break;
5821 			case XML_ELEMENT_NODE:
5822 				for (attr = node->properties; NULL != attr; attr = attr->next)
5823 				{
5824 					if (NULL == attr->name || NULL == (value = xmlGetProp(node, attr->name)))
5825 						continue;
5826 
5827 					value_tmp = zbx_strdup(NULL, (const char *)value);
5828 
5829 					if (NULL != item)
5830 					{
5831 						substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, &item->host,
5832 								item, NULL, NULL, &value_tmp, MACRO_TYPE_HTTP_XML,
5833 								NULL, 0);
5834 					}
5835 					else
5836 						substitute_lld_macros(&value_tmp, jp_row, ZBX_MACRO_XML, NULL, 0);
5837 
5838 					xmlSetProp(node, attr->name, (xmlChar *)value_tmp);
5839 
5840 					zbx_free(value_tmp);
5841 					xmlFree(value);
5842 				}
5843 				break;
5844 			default:
5845 				break;
5846 		}
5847 
5848 		substitute_macros_in_xml_elements(item, jp_row, node->children);
5849 	}
5850 }
5851 #endif
5852 
5853 /******************************************************************************
5854  *                                                                            *
5855  * Function: substitute_macros_xml                                            *
5856  *                                                                            *
5857  * Purpose: substitute simple or LLD macros in XML text nodes, attributes of  *
5858  *          a node or in CDATA section, validate XML                          *
5859  *                                                                            *
5860  * Parameters: data   - [IN/OUT] pointer to a buffer that contains XML        *
5861  *             item   - [IN] item for simple macro substitution               *
5862  *             jp_row - [IN] discovery data for LLD macro substitution        *
5863  *             error  - [OUT] reason for XML parsing failure                  *
5864  *             maxerrlen - [IN] the size of error buffer                      *
5865  *                                                                            *
5866  * Return value: SUCCEED or FAIL if XML validation has failed                 *
5867  *                                                                            *
5868  ******************************************************************************/
substitute_macros_xml(char ** data,const DC_ITEM * item,const struct zbx_json_parse * jp_row,char * error,int maxerrlen)5869 int	substitute_macros_xml(char **data, const DC_ITEM *item, const struct zbx_json_parse *jp_row, char *error,
5870 		int maxerrlen)
5871 {
5872 #ifndef HAVE_LIBXML2
5873 	ZBX_UNUSED(data);
5874 	ZBX_UNUSED(item);
5875 	ZBX_UNUSED(jp_row);
5876 	zbx_snprintf(error, maxerrlen, "Support for XML was not compiled in");
5877 	return FAIL;
5878 #else
5879 	const char	*__function_name = "substitute_macros_xml";
5880 	xmlDoc		*doc;
5881 	xmlErrorPtr	pErr;
5882 	xmlNode		*root_element;
5883 	xmlChar		*mem;
5884 	int		size, ret = FAIL;
5885 
5886 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
5887 
5888 	if (NULL == (doc = xmlReadMemory(*data, strlen(*data), "noname.xml", NULL, 0)))
5889 	{
5890 		if (NULL != (pErr = xmlGetLastError()))
5891 			zbx_snprintf(error, maxerrlen, "Cannot parse XML value: %s", pErr->message);
5892 		else
5893 			zbx_snprintf(error, maxerrlen, "Cannot parse XML value");
5894 
5895 		goto exit;
5896 	}
5897 
5898 	if (NULL == (root_element = xmlDocGetRootElement(doc)))
5899 	{
5900 		zbx_snprintf(error, maxerrlen, "Cannot parse XML root");
5901 		goto clean;
5902 	}
5903 
5904 	substitute_macros_in_xml_elements(item, jp_row, root_element);
5905 	xmlDocDumpMemory(doc, &mem, &size);
5906 
5907 	if (NULL == mem)
5908 	{
5909 		if (NULL != (pErr = xmlGetLastError()))
5910 			zbx_snprintf(error, maxerrlen, "Cannot save XML: %s", pErr->message);
5911 		else
5912 			zbx_snprintf(error, maxerrlen, "Cannot save XML");
5913 
5914 		goto clean;
5915 	}
5916 
5917 	zbx_free(*data);
5918 	*data = zbx_malloc(NULL, size + 1);
5919 	memcpy(*data, (const char *)mem, size + 1);
5920 	xmlFree(mem);
5921 	ret = SUCCEED;
5922 clean:
5923 	xmlFreeDoc(doc);
5924 exit:
5925 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
5926 
5927 	return ret;
5928 #endif
5929 }
5930 
5931 #ifdef HAVE_LIBXML2
5932 /******************************************************************************
5933  *                                                                            *
5934  * Function: libxml_handle_error                                              *
5935  *                                                                            *
5936  * Purpose: libxml2 callback function for error handle                        *
5937  *                                                                            *
5938  * Parameters: user_data - [IN/OUT] the user context                          *
5939  *             err       - [IN] the libxml2 error message                     *
5940  *                                                                            *
5941  ******************************************************************************/
libxml_handle_error(void * user_data,xmlErrorPtr err)5942 static void	libxml_handle_error(void *user_data, xmlErrorPtr err)
5943 {
5944 	zbx_libxml_error_t	*err_ctx;
5945 
5946 	if (NULL == user_data)
5947 		return;
5948 
5949 	err_ctx = (zbx_libxml_error_t *)user_data;
5950 	zbx_strlcat(err_ctx->buf, err->message, err_ctx->len);
5951 
5952 	if (NULL != err->str1)
5953 		zbx_strlcat(err_ctx->buf, err->str1, err_ctx->len);
5954 
5955 	if (NULL != err->str2)
5956 		zbx_strlcat(err_ctx->buf, err->str2, err_ctx->len);
5957 
5958 	if (NULL != err->str3)
5959 		zbx_strlcat(err_ctx->buf, err->str3, err_ctx->len);
5960 }
5961 #endif
5962 
5963 /******************************************************************************
5964  *                                                                            *
5965  * Function: xml_xpath_check                                                  *
5966  *                                                                            *
5967  * Purpose: validate xpath string                                             *
5968  *                                                                            *
5969  * Parameters: xpath  - [IN] the xpath value                                  *
5970  *             error  - [OUT] the error message buffer                        *
5971  *             errlen - [IN] the size of error message buffer                 *
5972  *                                                                            *
5973  * Return value: SUCCEED - the xpath component was parsed successfully        *
5974  *               FAIL    - xpath parsing error                                *
5975  *                                                                            *
5976  ******************************************************************************/
xml_xpath_check(const char * xpath,char * error,size_t errlen)5977 int	xml_xpath_check(const char *xpath, char *error, size_t errlen)
5978 {
5979 #ifndef HAVE_LIBXML2
5980 	ZBX_UNUSED(xpath);
5981 	ZBX_UNUSED(error);
5982 	ZBX_UNUSED(errlen);
5983 	return FAIL;
5984 #else
5985 	zbx_libxml_error_t	err;
5986 	xmlXPathContextPtr	ctx;
5987 	xmlXPathCompExprPtr	p;
5988 
5989 	err.buf = error;
5990 	err.len = errlen;
5991 
5992 	ctx = xmlXPathNewContext(NULL);
5993 	xmlSetStructuredErrorFunc(&err, &libxml_handle_error);
5994 
5995 	p = xmlXPathCtxtCompile(ctx, (xmlChar *)xpath);
5996 	xmlSetStructuredErrorFunc(NULL, NULL);
5997 
5998 	if (NULL == p)
5999 	{
6000 		xmlXPathFreeContext(ctx);
6001 		return FAIL;
6002 	}
6003 
6004 	xmlXPathFreeCompExpr(p);
6005 	xmlXPathFreeContext(ctx);
6006 	return SUCCEED;
6007 #endif
6008 }
6009