1 /*****************************************************************************
2  *
3  * MACROS.C - Common macro functions for Nagios
4  *
5  * Copyright (c) 1999-2010 Ethan Galstad (egalstad@nagios.org)
6  * Last Modified: 08-06-2010
7  *
8  * License:
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  *****************************************************************************/
24 
25 #include "../include/macros.h"
26 #include "../include/config.h"
27 #include "../include/common.h"
28 #include "../include/objects.h"
29 #include "../include/statusdata.h"
30 #include "../include/comments.h"
31 #ifdef NSCORE
32 #include "../include/nagios.h"
33 #else
34 #include "../include/cgiutils.h"
35 #endif
36 
37 #ifdef NSCORE
38 extern int      use_large_installation_tweaks;
39 extern int      enable_environment_macros;
40 #endif
41 
42 extern char     *illegal_output_chars;
43 
44 extern contact		*contact_list;
45 extern contactgroup	*contactgroup_list;
46 extern host             *host_list;
47 extern hostgroup	*hostgroup_list;
48 extern service          *service_list;
49 extern servicegroup     *servicegroup_list;
50 extern command          *command_list;
51 extern timeperiod       *timeperiod_list;
52 
53 char *macro_x_names[MACRO_X_COUNT]; /* the macro names */
54 char *macro_user[MAX_USER_MACROS]; /* $USERx$ macros */
55 
56 struct macro_key_code {
57 	char *name; /* macro key name */
58 	int code;  /* numeric macro code, usable in case statements */
59 	int clean_options;
60 	char *value;
61 	};
62 
63 struct macro_key_code macro_keys[MACRO_X_COUNT];
64 
65 /*
66  * These point to their corresponding pointer arrays in global_macros
67  * AFTER macros have been initialized.
68  *
69  * They really only exist so that eventbroker modules that reference
70  * them won't need to be re-compiled, although modules that rely
71  * on their values after having run a certain command will require an
72  * update
73  */
74 char **macro_x = NULL;
75 
76 /*
77  * scoped to this file to prevent (unintentional) mischief,
78  * but see base/notifications.c for how to use it
79  */
80 static nagios_macros global_macros;
81 
82 
83 nagios_macros *get_global_macros(void) {
84 	return &global_macros;
85 	}
86 
87 /******************************************************************/
88 /************************ MACRO FUNCTIONS *************************/
89 /******************************************************************/
90 
91 /*
92  * locate a macro key based on its name by using a binary search
93  * over all keys. O(log(n)) complexity and a vast improvement over
94  * the previous linear scan
95  */
96 const struct macro_key_code *find_macro_key(const char *name) {
97 	unsigned int high, low = 0;
98 	int value;
99 	struct macro_key_code *key;
100 
101 	high = MACRO_X_COUNT;
102 	while(high - low > 0) {
103 		unsigned int mid = low + ((high - low) / 2);
104 		key = &macro_keys[mid];
105 		value = strcmp(name, key->name);
106 		if(value == 0) {
107 			return key;
108 			}
109 		if(value > 0)
110 			low = mid + 1;
111 		else
112 			high = mid;
113 		}
114 	return NULL;
115 	}
116 
117 
118 /*
119  * replace macros in notification commands with their values,
120  * the thread-safe version
121  */
122 int process_macros_r(nagios_macros *mac, char *input_buffer, char **output_buffer, int options) {
123 	char *temp_buffer = NULL;
124 	char *save_buffer = NULL;
125 	char *buf_ptr = NULL;
126 	char *delim_ptr = NULL;
127 	int in_macro = FALSE;
128 	int x = 0;
129 	char *selected_macro = NULL;
130 	char *original_macro = NULL;
131 	char *cleaned_macro = NULL;
132 	int clean_macro = FALSE;
133 	int found_macro_x = FALSE;
134 	int result = OK;
135 	int clean_options = 0;
136 	int free_macro = FALSE;
137 	int macro_options = 0;
138 
139 	log_debug_info(DEBUGL_FUNCTIONS, 0, "process_macros_r()\n");
140 
141 	if(output_buffer == NULL)
142 		return ERROR;
143 
144 	*output_buffer = (char *)strdup("");
145 
146 	if(input_buffer == NULL)
147 		return ERROR;
148 
149 	in_macro = FALSE;
150 
151 	log_debug_info(DEBUGL_MACROS, 1, "**** BEGIN MACRO PROCESSING ***********\n");
152 	log_debug_info(DEBUGL_MACROS, 1, "Processing: '%s'\n", input_buffer);
153 
154 	/* use a duplicate of original buffer, so we don't modify the original */
155 	save_buffer = buf_ptr = (input_buffer ? strdup(input_buffer) : NULL);
156 
157 	while(buf_ptr) {
158 
159 		/* save pointer to this working part of buffer */
160 		temp_buffer = buf_ptr;
161 
162 		/* find the next delimiter - terminate preceding string and advance buffer pointer for next run */
163 		if((delim_ptr = strchr(buf_ptr, '$'))) {
164 			delim_ptr[0] = '\x0';
165 			buf_ptr = (char *)delim_ptr + 1;
166 			}
167 		/* no delimiter found - we already have the last of the buffer */
168 		else
169 			buf_ptr = NULL;
170 
171 		log_debug_info(DEBUGL_MACROS, 2, "  Processing part: '%s'\n", temp_buffer);
172 
173 		selected_macro = NULL;
174 		found_macro_x = FALSE;
175 		clean_macro = FALSE;
176 
177 		/* we're in plain text... */
178 		if(in_macro == FALSE) {
179 
180 			/* add the plain text to the end of the already processed buffer */
181 			*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(temp_buffer) + 1);
182 			strcat(*output_buffer, temp_buffer);
183 
184 			log_debug_info(DEBUGL_MACROS, 2, "  Not currently in macro.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
185 			in_macro = TRUE;
186 			}
187 
188 		/* looks like we're in a macro, so process it... */
189 		else {
190 
191 			/* reset clean options */
192 			clean_options = 0;
193 
194 			/* grab the macro value */
195 			result = grab_macro_value_r(mac, temp_buffer, &selected_macro, &clean_options, &free_macro);
196 			log_debug_info(DEBUGL_MACROS, 2, "  Processed '%s', Clean Options: %d, Free: %d\n", temp_buffer, clean_options, free_macro);
197 
198 			/* an error occurred - we couldn't parse the macro, so continue on */
199 			if(result == ERROR) {
200 				log_debug_info(DEBUGL_MACROS, 0, " WARNING: An error occurred processing macro '%s'!\n", temp_buffer);
201 				if(free_macro == TRUE)
202 					my_free(selected_macro);
203 				}
204 
205 			/* we already have a macro... */
206 			if(result == OK)
207 				x = 0;
208 
209 			/* an escaped $ is done by specifying two $$ next to each other */
210 			else if(!strcmp(temp_buffer, "")) {
211 				log_debug_info(DEBUGL_MACROS, 2, "  Escaped $.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
212 				*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + 2);
213 				strcat(*output_buffer, "$");
214 				}
215 
216 			/* a non-macro, just some user-defined string between two $s */
217 			else {
218 				log_debug_info(DEBUGL_MACROS, 2, "  Non-macro.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
219 
220 				/* add the plain text to the end of the already processed buffer */
221 				*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(temp_buffer) + 3);
222 				strcat(*output_buffer, "$");
223 				strcat(*output_buffer, temp_buffer);
224 				strcat(*output_buffer, "$");
225 				}
226 
227 			/* insert macro */
228 			if(selected_macro != NULL) {
229 				log_debug_info(DEBUGL_MACROS, 2, "  Processed '%s', Clean Options: %d, Free: %d\n", temp_buffer, clean_options, free_macro);
230 
231 				/* include any cleaning options passed back to us */
232 				macro_options = (options | clean_options);
233 
234 				log_debug_info(DEBUGL_MACROS, 2, "  Cleaning options: global=%d, local=%d, effective=%d\n", options, clean_options, macro_options);
235 
236 				/* URL encode the macro if requested - this allocates new memory */
237 				if(macro_options & URL_ENCODE_MACRO_CHARS) {
238 					original_macro = selected_macro;
239 					selected_macro = get_url_encoded_string(selected_macro);
240 					if(free_macro == TRUE) {
241 						my_free(original_macro);
242 						}
243 					free_macro = TRUE;
244 					}
245 
246 				/* some macros are cleaned... */
247 				if(clean_macro == TRUE || ((macro_options & STRIP_ILLEGAL_MACRO_CHARS) || (macro_options & ESCAPE_MACRO_CHARS))) {
248 
249 					/* add the (cleaned) processed macro to the end of the already processed buffer */
250 					if(selected_macro != NULL && (cleaned_macro = clean_macro_chars(selected_macro, macro_options)) != NULL) {
251 						*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(cleaned_macro) + 1);
252 						strcat(*output_buffer, cleaned_macro);
253 
254 						log_debug_info(DEBUGL_MACROS, 2, "  Cleaned macro.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
255 						}
256 					}
257 
258 				/* others are not cleaned */
259 				else {
260 					/* add the processed macro to the end of the already processed buffer */
261 					if(selected_macro != NULL) {
262 						*output_buffer = (char *)realloc(*output_buffer, strlen(*output_buffer) + strlen(selected_macro) + 1);
263 						strcat(*output_buffer, selected_macro);
264 
265 						log_debug_info(DEBUGL_MACROS, 2, "  Uncleaned macro.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
266 						}
267 					}
268 
269 				/* free memory if necessary (if we URL encoded the macro or we were told to do so by grab_macro_value()) */
270 				if(free_macro == TRUE)
271 					my_free(selected_macro);
272 
273 				log_debug_info(DEBUGL_MACROS, 2, "  Just finished macro.  Running output (%lu): '%s'\n", (unsigned long)strlen(*output_buffer), *output_buffer);
274 				}
275 
276 			in_macro = FALSE;
277 			}
278 		}
279 
280 	/* free copy of input buffer */
281 	my_free(save_buffer);
282 
283 	log_debug_info(DEBUGL_MACROS, 1, "  Done.  Final output: '%s'\n", *output_buffer);
284 	log_debug_info(DEBUGL_MACROS, 1, "**** END MACRO PROCESSING *************\n");
285 
286 	return OK;
287 	}
288 
289 int process_macros(char *input_buffer, char **output_buffer, int options) {
290 	return process_macros_r(&global_macros, input_buffer, output_buffer, options);
291 	}
292 
293 /******************************************************************/
294 /********************** MACRO GRAB FUNCTIONS **********************/
295 /******************************************************************/
296 
297 /* grab macros that are specific to a particular host */
298 int grab_host_macros_r(nagios_macros *mac, host *hst) {
299 	/* clear host-related macros */
300 	clear_host_macros_r(mac);
301 	clear_hostgroup_macros_r(mac);
302 
303 	/* save pointer to host */
304 	mac->host_ptr = hst;
305 	mac->hostgroup_ptr = NULL;
306 
307 	if(hst == NULL)
308 		return ERROR;
309 
310 #ifdef NSCORE
311 	/* save pointer to host's first/primary hostgroup */
312 	if(hst->hostgroups_ptr)
313 		mac->hostgroup_ptr = (hostgroup *)hst->hostgroups_ptr->object_ptr;
314 #endif
315 
316 	return OK;
317 	}
318 
319 int grab_host_macros(host *hst) {
320 	return grab_host_macros_r(&global_macros, hst);
321 	}
322 
323 
324 /* grab hostgroup macros */
325 int grab_hostgroup_macros_r(nagios_macros *mac, hostgroup *hg) {
326 	/* clear hostgroup macros */
327 	clear_hostgroup_macros_r(mac);
328 
329 	/* save the hostgroup pointer for later */
330 	mac->hostgroup_ptr = hg;
331 
332 	if(hg == NULL)
333 		return ERROR;
334 
335 	return OK;
336 	}
337 
338 int grab_hostgroup_macros(hostgroup *hg) {
339 	return grab_hostgroup_macros_r(&global_macros, hg);
340 	}
341 
342 
343 /* grab macros that are specific to a particular service */
344 int grab_service_macros_r(nagios_macros *mac, service *svc) {
345 
346 	/* clear service-related macros */
347 	clear_service_macros_r(mac);
348 	clear_servicegroup_macros_r(mac);
349 
350 	/* save pointer for later */
351 	mac->service_ptr = svc;
352 	mac->servicegroup_ptr = NULL;
353 
354 	if(svc == NULL)
355 		return ERROR;
356 
357 #ifdef NSCORE
358 	/* save first/primary servicegroup pointer for later */
359 	if(svc->servicegroups_ptr)
360 		mac->servicegroup_ptr = (servicegroup *)svc->servicegroups_ptr->object_ptr;
361 #endif
362 
363 	return OK;
364 	}
365 
366 int grab_service_macros(service *svc) {
367 	return grab_service_macros_r(&global_macros, svc);
368 	}
369 
370 
371 /* grab macros that are specific to a particular servicegroup */
372 int grab_servicegroup_macros_r(nagios_macros *mac, servicegroup *sg) {
373 	/* clear servicegroup macros */
374 	clear_servicegroup_macros_r(mac);
375 
376 	/* save the pointer for later */
377 	mac->servicegroup_ptr = sg;
378 
379 	if(sg == NULL)
380 		return ERROR;
381 
382 	return OK;
383 	}
384 
385 int grab_servicegroup_macros(servicegroup *sg) {
386 	return grab_servicegroup_macros_r(&global_macros, sg);
387 	}
388 
389 
390 /* grab macros that are specific to a particular contact */
391 int grab_contact_macros_r(nagios_macros *mac, contact *cntct) {
392 	/* clear contact-related macros */
393 	clear_contact_macros_r(mac);
394 	clear_contactgroup_macros_r(mac);
395 
396 	/* save pointer to contact for later */
397 	mac->contact_ptr = cntct;
398 	mac->contactgroup_ptr = NULL;
399 
400 	if(cntct == NULL)
401 		return ERROR;
402 
403 #ifdef NSCORE
404 	/* save pointer to first/primary contactgroup for later */
405 	if(cntct->contactgroups_ptr)
406 		mac->contactgroup_ptr = (contactgroup *)cntct->contactgroups_ptr->object_ptr;
407 #endif
408 
409 	return OK;
410 	}
411 
412 int grab_contact_macros(contact *cntct) {
413 	return grab_contact_macros_r(&global_macros, cntct);
414 	}
415 
416 
417 /******************************************************************/
418 /******************* MACRO GENERATION FUNCTIONS *******************/
419 /******************************************************************/
420 
421 /* this is the big one */
422 int grab_macro_value_r(nagios_macros *mac, char *macro_buffer, char **output, int *clean_options, int *free_macro) {
423 	char *buf = NULL;
424 	char *ptr = NULL;
425 	char *macro_name = NULL;
426 	char *arg[2] = {NULL, NULL};
427 	contact *temp_contact = NULL;
428 	contactgroup *temp_contactgroup = NULL;
429 	contactsmember *temp_contactsmember = NULL;
430 	char *temp_buffer = NULL;
431 	int delimiter_len = 0;
432 	int x, result = OK;
433 	const struct macro_key_code *mkey;
434 
435 	/* for the early cases, this is the default */
436 	*free_macro = FALSE;
437 
438 	if(output == NULL)
439 		return ERROR;
440 
441 	/* clear the old macro value */
442 	my_free(*output);
443 
444 	if(macro_buffer == NULL || clean_options == NULL || free_macro == NULL)
445 		return ERROR;
446 
447 
448 	/*
449 	 * We handle argv and user macros first, since those are by far
450 	 * the most commonly accessed ones (3.4 and 1.005 per check,
451 	 * respectively). Since neither of them requires that we copy
452 	 * the original buffer, we can also get away with some less
453 	 * code for these simple cases.
454 	 */
455 	if(strstr(macro_buffer, "ARG") == macro_buffer) {
456 
457 		/* which arg do we want? */
458 		x = atoi(macro_buffer + 3);
459 
460 		if(x <= 0 || x > MAX_COMMAND_ARGUMENTS) {
461 			return ERROR;
462 			}
463 
464 		/* use a pre-computed macro value */
465 		*output = mac->argv[x - 1];
466 		return OK;
467 		}
468 
469 	if(strstr(macro_buffer, "USER") == macro_buffer) {
470 
471 		/* which macro do we want? */
472 		x = atoi(macro_buffer + 4);
473 
474 		if(x <= 0 || x > MAX_USER_MACROS) {
475 			return ERROR;
476 			}
477 
478 		/* use a pre-computed macro value */
479 		*output = macro_user[x - 1];
480 		return OK;
481 		}
482 
483 	/* most frequently used "x" macro gets a shortcut */
484 	if(mac->host_ptr && !strcmp(macro_buffer, "HOSTADDRESS")) {
485 		if(mac->host_ptr->address)
486 			*output = mac->host_ptr->address;
487 		return OK;
488 		}
489 
490 	/* work with a copy of the original buffer */
491 	if((buf = (char *)strdup(macro_buffer)) == NULL)
492 		return ERROR;
493 
494 	/* BY DEFAULT, TELL CALLER TO FREE MACRO BUFFER WHEN DONE */
495 	*free_macro = TRUE;
496 
497 	/* macro name is at start of buffer */
498 	macro_name = buf;
499 
500 	/* see if there's an argument - if so, this is most likely an on-demand macro */
501 	if((ptr = strchr(buf, ':'))) {
502 
503 		ptr[0] = '\x0';
504 		ptr++;
505 
506 		/* save the first argument - host name, hostgroup name, etc. */
507 		arg[0] = ptr;
508 
509 		/* try and find a second argument */
510 		if((ptr = strchr(ptr, ':'))) {
511 
512 			ptr[0] = '\x0';
513 			ptr++;
514 
515 			/* save second argument - service description or delimiter */
516 			arg[1] = ptr;
517 			}
518 		}
519 
520 	if((mkey = find_macro_key(macro_name))) {
521 		log_debug_info(DEBUGL_MACROS, 2, "  macros[%d] (%s) match.\n", mkey->code, macro_x_names[mkey->code]);
522 		if(mkey->clean_options) {
523 			*clean_options |= mkey->clean_options;
524 			log_debug_info(DEBUGL_MACROS, 2, "  New clean options: %d\n", *clean_options);
525 			}
526 
527 		/* get the macro value */
528 		result = grab_macrox_value_r(mac, mkey->code, arg[0], arg[1], output, free_macro);
529 		}
530 	/***** CONTACT ADDRESS MACROS *****/
531 	/* NOTE: the code below should be broken out into a separate function */
532 	else if(strstr(macro_name, "CONTACTADDRESS") == macro_name) {
533 
534 		/* which address do we want? */
535 		x = atoi(macro_name + 14) - 1;
536 
537 		/* regular macro */
538 		if(arg[0] == NULL) {
539 
540 			/* use the saved pointer */
541 			if((temp_contact = mac->contact_ptr) == NULL) {
542 				my_free(buf);
543 				return ERROR;
544 				}
545 
546 			/* get the macro value by reference, so no need to free() */
547 			*free_macro = FALSE;
548 			result = grab_contact_address_macro(x, temp_contact, output);
549 			}
550 
551 		/* on-demand macro */
552 		else {
553 
554 			/* on-demand contact macro with a contactgroup and a delimiter */
555 			if(arg[1] != NULL) {
556 
557 				if((temp_contactgroup = find_contactgroup(arg[0])) == NULL)
558 					return ERROR;
559 
560 				delimiter_len = strlen(arg[1]);
561 
562 				/* concatenate macro values for all contactgroup members */
563 				for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
564 
565 #ifdef NSCORE
566 					if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
567 						continue;
568 					if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL)
569 						continue;
570 #endif
571 
572 					/* get the macro value for this contact */
573 					grab_contact_address_macro(x, temp_contact, &temp_buffer);
574 
575 					if(temp_buffer == NULL)
576 						continue;
577 
578 					/* add macro value to already running macro */
579 					if(*output == NULL)
580 						*output = (char *)strdup(temp_buffer);
581 					else {
582 						if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
583 							continue;
584 						strcat(*output, arg[1]);
585 						strcat(*output, temp_buffer);
586 						}
587 					my_free(temp_buffer);
588 					}
589 				}
590 
591 			/* else on-demand contact macro */
592 			else {
593 
594 				/* find the contact */
595 				if((temp_contact = find_contact(arg[0])) == NULL) {
596 					my_free(buf);
597 					return ERROR;
598 					}
599 
600 				/* get the macro value */
601 				result = grab_contact_address_macro(x, temp_contact, output);
602 				}
603 			}
604 		}
605 
606 	/***** CUSTOM VARIABLE MACROS *****/
607 	else if(macro_name[0] == '_') {
608 
609 		/* get the macro value */
610 		result = grab_custom_macro_value_r(mac, macro_name, arg[0], arg[1], output);
611 		}
612 
613 	/* no macro matched... */
614 	else {
615 		log_debug_info(DEBUGL_MACROS, 0, " WARNING: Could not find a macro matching '%s'!\n", macro_name);
616 		result = ERROR;
617 		}
618 
619 	/* free memory */
620 	my_free(buf);
621 
622 	return result;
623 	}
624 
625 int grab_macro_value(char *macro_buffer, char **output, int *clean_options, int *free_macro) {
626 	return grab_macro_value_r(&global_macros, macro_buffer, output, clean_options, free_macro);
627 	}
628 
629 
630 int grab_macrox_value_r(nagios_macros *mac, int macro_type, char *arg1, char *arg2, char **output, int *free_macro) {
631 	host *temp_host = NULL;
632 	hostgroup *temp_hostgroup = NULL;
633 	hostsmember *temp_hostsmember = NULL;
634 	service *temp_service = NULL;
635 	servicegroup *temp_servicegroup = NULL;
636 	servicesmember *temp_servicesmember = NULL;
637 	contact *temp_contact = NULL;
638 	contactgroup *temp_contactgroup = NULL;
639 	contactsmember *temp_contactsmember = NULL;
640 	char *temp_buffer = NULL;
641 	int result = OK;
642 	int delimiter_len = 0;
643 	int free_sub_macro = FALSE;
644 #ifdef NSCORE
645 	register int x;
646 	int authorized = TRUE;
647 	int problem = TRUE;
648 	int hosts_up = 0;
649 	int hosts_down = 0;
650 	int hosts_unreachable = 0;
651 	int hosts_down_unhandled = 0;
652 	int hosts_unreachable_unhandled = 0;
653 	int host_problems = 0;
654 	int host_problems_unhandled = 0;
655 	int services_ok = 0;
656 	int services_warning = 0;
657 	int services_unknown = 0;
658 	int services_critical = 0;
659 	int services_warning_unhandled = 0;
660 	int services_unknown_unhandled = 0;
661 	int services_critical_unhandled = 0;
662 	int service_problems = 0;
663 	int service_problems_unhandled = 0;
664 #endif
665 
666 
667 	if(output == NULL || free_macro == NULL)
668 		return ERROR;
669 
670 	/* BY DEFAULT, TELL CALLER TO FREE MACRO BUFFER WHEN DONE */
671 	*free_macro = TRUE;
672 
673 	/* handle the macro */
674 	switch(macro_type) {
675 
676 			/***************/
677 			/* HOST MACROS */
678 			/***************/
679 		case MACRO_HOSTNAME:
680 		case MACRO_HOSTALIAS:
681 		case MACRO_HOSTADDRESS:
682 		case MACRO_LASTHOSTCHECK:
683 		case MACRO_LASTHOSTSTATECHANGE:
684 		case MACRO_HOSTOUTPUT:
685 		case MACRO_HOSTPERFDATA:
686 		case MACRO_HOSTSTATE:
687 		case MACRO_HOSTSTATEID:
688 		case MACRO_HOSTATTEMPT:
689 		case MACRO_HOSTEXECUTIONTIME:
690 		case MACRO_HOSTLATENCY:
691 		case MACRO_HOSTDURATION:
692 		case MACRO_HOSTDURATIONSEC:
693 		case MACRO_HOSTDOWNTIME:
694 		case MACRO_HOSTSTATETYPE:
695 		case MACRO_HOSTPERCENTCHANGE:
696 		case MACRO_HOSTACKAUTHOR:
697 		case MACRO_HOSTACKCOMMENT:
698 		case MACRO_LASTHOSTUP:
699 		case MACRO_LASTHOSTDOWN:
700 		case MACRO_LASTHOSTUNREACHABLE:
701 		case MACRO_HOSTCHECKCOMMAND:
702 		case MACRO_HOSTDISPLAYNAME:
703 		case MACRO_HOSTACTIONURL:
704 		case MACRO_HOSTNOTESURL:
705 		case MACRO_HOSTNOTES:
706 		case MACRO_HOSTCHECKTYPE:
707 		case MACRO_LONGHOSTOUTPUT:
708 		case MACRO_HOSTNOTIFICATIONNUMBER:
709 		case MACRO_HOSTNOTIFICATIONID:
710 		case MACRO_HOSTEVENTID:
711 		case MACRO_LASTHOSTEVENTID:
712 		case MACRO_HOSTGROUPNAMES:
713 		case MACRO_HOSTACKAUTHORNAME:
714 		case MACRO_HOSTACKAUTHORALIAS:
715 		case MACRO_MAXHOSTATTEMPTS:
716 		case MACRO_TOTALHOSTSERVICES:
717 		case MACRO_TOTALHOSTSERVICESOK:
718 		case MACRO_TOTALHOSTSERVICESWARNING:
719 		case MACRO_TOTALHOSTSERVICESUNKNOWN:
720 		case MACRO_TOTALHOSTSERVICESCRITICAL:
721 		case MACRO_HOSTPROBLEMID:
722 		case MACRO_LASTHOSTPROBLEMID:
723 		case MACRO_LASTHOSTSTATE:
724 		case MACRO_LASTHOSTSTATEID:
725 
726 			/* a standard host macro */
727 			if(arg2 == NULL) {
728 
729 				/* find the host for on-demand macros */
730 				if(arg1) {
731 					if((temp_host = find_host(arg1)) == NULL)
732 						return ERROR;
733 					}
734 
735 				/* else use saved host pointer */
736 				else if((temp_host = mac->host_ptr) == NULL)
737 					return ERROR;
738 
739 				/* get the host macro value */
740 				result = grab_standard_host_macro_r(mac, macro_type, temp_host, output, free_macro);
741 				}
742 
743 			/* a host macro with a hostgroup name and delimiter */
744 			else {
745 
746 				if((temp_hostgroup = find_hostgroup(arg1)) == NULL)
747 					return ERROR;
748 
749 				delimiter_len = strlen(arg2);
750 
751 				/* concatenate macro values for all hostgroup members */
752 				for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
753 
754 #ifdef NSCORE
755 					if((temp_host = temp_hostsmember->host_ptr) == NULL)
756 						continue;
757 #else
758 					if((temp_host = find_host(temp_hostsmember->host_name)) == NULL)
759 						continue;
760 #endif
761 
762 					/* get the macro value for this host */
763 					grab_standard_host_macro_r(mac, macro_type, temp_host, &temp_buffer, &free_sub_macro);
764 
765 					if(temp_buffer == NULL)
766 						continue;
767 
768 					/* add macro value to already running macro */
769 					if(*output == NULL)
770 						*output = (char *)strdup(temp_buffer);
771 					else {
772 						if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
773 							continue;
774 						strcat(*output, arg2);
775 						strcat(*output, temp_buffer);
776 						}
777 					if(free_sub_macro == TRUE)
778 						my_free(temp_buffer);
779 					}
780 				}
781 			break;
782 
783 			/********************/
784 			/* HOSTGROUP MACROS */
785 			/********************/
786 		case MACRO_HOSTGROUPNAME:
787 		case MACRO_HOSTGROUPALIAS:
788 		case MACRO_HOSTGROUPNOTES:
789 		case MACRO_HOSTGROUPNOTESURL:
790 		case MACRO_HOSTGROUPACTIONURL:
791 		case MACRO_HOSTGROUPMEMBERS:
792 
793 			/* a standard hostgroup macro */
794 			/* use the saved hostgroup pointer */
795 			if(arg1 == NULL) {
796 				if((temp_hostgroup = mac->hostgroup_ptr) == NULL)
797 					return ERROR;
798 				}
799 
800 			/* else find the hostgroup for on-demand macros */
801 			else {
802 				if((temp_hostgroup = find_hostgroup(arg1)) == NULL)
803 					return ERROR;
804 				}
805 
806 			/* get the hostgroup macro value */
807 			result = grab_standard_hostgroup_macro_r(mac, macro_type, temp_hostgroup, output);
808 			break;
809 
810 			/******************/
811 			/* SERVICE MACROS */
812 			/******************/
813 		case MACRO_SERVICEDESC:
814 		case MACRO_SERVICESTATE:
815 		case MACRO_SERVICESTATEID:
816 		case MACRO_SERVICEATTEMPT:
817 		case MACRO_LASTSERVICECHECK:
818 		case MACRO_LASTSERVICESTATECHANGE:
819 		case MACRO_SERVICEOUTPUT:
820 		case MACRO_SERVICEPERFDATA:
821 		case MACRO_SERVICEEXECUTIONTIME:
822 		case MACRO_SERVICELATENCY:
823 		case MACRO_SERVICEDURATION:
824 		case MACRO_SERVICEDURATIONSEC:
825 		case MACRO_SERVICEDOWNTIME:
826 		case MACRO_SERVICESTATETYPE:
827 		case MACRO_SERVICEPERCENTCHANGE:
828 		case MACRO_SERVICEACKAUTHOR:
829 		case MACRO_SERVICEACKCOMMENT:
830 		case MACRO_LASTSERVICEOK:
831 		case MACRO_LASTSERVICEWARNING:
832 		case MACRO_LASTSERVICEUNKNOWN:
833 		case MACRO_LASTSERVICECRITICAL:
834 		case MACRO_SERVICECHECKCOMMAND:
835 		case MACRO_SERVICEDISPLAYNAME:
836 		case MACRO_SERVICEACTIONURL:
837 		case MACRO_SERVICENOTESURL:
838 		case MACRO_SERVICENOTES:
839 		case MACRO_SERVICECHECKTYPE:
840 		case MACRO_LONGSERVICEOUTPUT:
841 		case MACRO_SERVICENOTIFICATIONNUMBER:
842 		case MACRO_SERVICENOTIFICATIONID:
843 		case MACRO_SERVICEEVENTID:
844 		case MACRO_LASTSERVICEEVENTID:
845 		case MACRO_SERVICEGROUPNAMES:
846 		case MACRO_SERVICEACKAUTHORNAME:
847 		case MACRO_SERVICEACKAUTHORALIAS:
848 		case MACRO_MAXSERVICEATTEMPTS:
849 		case MACRO_SERVICEISVOLATILE:
850 		case MACRO_SERVICEPROBLEMID:
851 		case MACRO_LASTSERVICEPROBLEMID:
852 		case MACRO_LASTSERVICESTATE:
853 		case MACRO_LASTSERVICESTATEID:
854 
855 			/* use saved service pointer */
856 			if(arg1 == NULL && arg2 == NULL) {
857 
858 				if((temp_service = mac->service_ptr) == NULL)
859 					return ERROR;
860 
861 				result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro);
862 				}
863 
864 			/* else and ondemand macro... */
865 			else {
866 
867 				/* if first arg is blank, it means use the current host name */
868 				if(arg1 == NULL || arg1[0] == '\x0') {
869 
870 					if(mac->host_ptr == NULL)
871 						return ERROR;
872 
873 					if((temp_service = find_service(mac->host_ptr->name, arg2))) {
874 
875 						/* get the service macro value */
876 						result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro);
877 						}
878 					}
879 
880 				/* on-demand macro with both host and service name */
881 				else if((temp_service = find_service(arg1, arg2))) {
882 
883 					/* get the service macro value */
884 					result = grab_standard_service_macro_r(mac, macro_type, temp_service, output, free_macro);
885 					}
886 
887 				/* else we have a service macro with a servicegroup name and a delimiter... */
888 				else if(arg1 && arg2) {
889 
890 					if((temp_servicegroup = find_servicegroup(arg1)) == NULL)
891 						return ERROR;
892 
893 					delimiter_len = strlen(arg2);
894 
895 					/* concatenate macro values for all servicegroup members */
896 					for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
897 
898 #ifdef NSCORE
899 						if((temp_service = temp_servicesmember->service_ptr) == NULL)
900 							continue;
901 #else
902 						if((temp_service = find_service(temp_servicesmember->host_name, temp_servicesmember->service_description)) == NULL)
903 							continue;
904 #endif
905 
906 						/* get the macro value for this service */
907 						grab_standard_service_macro_r(mac, macro_type, temp_service, &temp_buffer, &free_sub_macro);
908 
909 						if(temp_buffer == NULL)
910 							continue;
911 
912 						/* add macro value to already running macro */
913 						if(*output == NULL)
914 							*output = (char *)strdup(temp_buffer);
915 						else {
916 							if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
917 								continue;
918 							strcat(*output, arg2);
919 							strcat(*output, temp_buffer);
920 							}
921 						if(free_sub_macro == TRUE)
922 							my_free(temp_buffer);
923 						}
924 					}
925 				else
926 					return ERROR;
927 				}
928 			break;
929 
930 			/***********************/
931 			/* SERVICEGROUP MACROS */
932 			/***********************/
933 		case MACRO_SERVICEGROUPNAME:
934 		case MACRO_SERVICEGROUPALIAS:
935 		case MACRO_SERVICEGROUPNOTES:
936 		case MACRO_SERVICEGROUPNOTESURL:
937 		case MACRO_SERVICEGROUPACTIONURL:
938 		case MACRO_SERVICEGROUPMEMBERS:
939 			/* a standard servicegroup macro */
940 			/* use the saved servicegroup pointer */
941 			if(arg1 == NULL) {
942 				if((temp_servicegroup = mac->servicegroup_ptr) == NULL)
943 					return ERROR;
944 				}
945 
946 			/* else find the servicegroup for on-demand macros */
947 			else {
948 				if((temp_servicegroup = find_servicegroup(arg1)) == NULL)
949 					return ERROR;
950 				}
951 
952 			/* get the servicegroup macro value */
953 			result = grab_standard_servicegroup_macro_r(mac, macro_type, temp_servicegroup, output);
954 			break;
955 
956 			/******************/
957 			/* CONTACT MACROS */
958 			/******************/
959 		case MACRO_CONTACTNAME:
960 		case MACRO_CONTACTALIAS:
961 		case MACRO_CONTACTEMAIL:
962 		case MACRO_CONTACTPAGER:
963 		case MACRO_CONTACTGROUPNAMES:
964 			/* a standard contact macro */
965 			if(arg2 == NULL) {
966 
967 				/* find the contact for on-demand macros */
968 				if(arg1) {
969 					if((temp_contact = find_contact(arg1)) == NULL)
970 						return ERROR;
971 					}
972 
973 				/* else use saved contact pointer */
974 				else if((temp_contact = mac->contact_ptr) == NULL)
975 					return ERROR;
976 
977 				/* get the contact macro value */
978 				result = grab_standard_contact_macro_r(mac, macro_type, temp_contact, output);
979 				}
980 
981 			/* a contact macro with a contactgroup name and delimiter */
982 			else {
983 
984 				if((temp_contactgroup = find_contactgroup(arg1)) == NULL)
985 					return ERROR;
986 
987 				delimiter_len = strlen(arg2);
988 
989 				/* concatenate macro values for all contactgroup members */
990 				for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
991 
992 #ifdef NSCORE
993 					if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
994 						continue;
995 #else
996 					if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL)
997 						continue;
998 #endif
999 
1000 					/* get the macro value for this contact */
1001 					grab_standard_contact_macro_r(mac, macro_type, temp_contact, &temp_buffer);
1002 
1003 					if(temp_buffer == NULL)
1004 						continue;
1005 
1006 					/* add macro value to already running macro */
1007 					if(*output == NULL)
1008 						*output = (char *)strdup(temp_buffer);
1009 					else {
1010 						if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
1011 							continue;
1012 						strcat(*output, arg2);
1013 						strcat(*output, temp_buffer);
1014 						}
1015 					my_free(temp_buffer);
1016 					}
1017 				}
1018 			break;
1019 
1020 			/***********************/
1021 			/* CONTACTGROUP MACROS */
1022 			/***********************/
1023 		case MACRO_CONTACTGROUPNAME:
1024 		case MACRO_CONTACTGROUPALIAS:
1025 		case MACRO_CONTACTGROUPMEMBERS:
1026 			/* a standard contactgroup macro */
1027 			/* use the saved contactgroup pointer */
1028 			if(arg1 == NULL) {
1029 				if((temp_contactgroup = mac->contactgroup_ptr) == NULL)
1030 					return ERROR;
1031 				}
1032 
1033 			/* else find the contactgroup for on-demand macros */
1034 			else {
1035 				if((temp_contactgroup = find_contactgroup(arg1)) == NULL)
1036 					return ERROR;
1037 				}
1038 
1039 			/* get the contactgroup macro value */
1040 			result = grab_standard_contactgroup_macro(macro_type, temp_contactgroup, output);
1041 			break;
1042 
1043 			/***********************/
1044 			/* NOTIFICATION MACROS */
1045 			/***********************/
1046 		case MACRO_NOTIFICATIONTYPE:
1047 		case MACRO_NOTIFICATIONNUMBER:
1048 		case MACRO_NOTIFICATIONRECIPIENTS:
1049 		case MACRO_NOTIFICATIONISESCALATED:
1050 		case MACRO_NOTIFICATIONAUTHOR:
1051 		case MACRO_NOTIFICATIONAUTHORNAME:
1052 		case MACRO_NOTIFICATIONAUTHORALIAS:
1053 		case MACRO_NOTIFICATIONCOMMENT:
1054 
1055 			/* notification macros have already been pre-computed */
1056 			*output = mac->x[macro_type];
1057 			*free_macro = FALSE;
1058 			break;
1059 
1060 			/********************/
1061 			/* DATE/TIME MACROS */
1062 			/********************/
1063 		case MACRO_LONGDATETIME:
1064 		case MACRO_SHORTDATETIME:
1065 		case MACRO_DATE:
1066 		case MACRO_TIME:
1067 		case MACRO_TIMET:
1068 		case MACRO_ISVALIDTIME:
1069 		case MACRO_NEXTVALIDTIME:
1070 
1071 			/* calculate macros */
1072 			result = grab_datetime_macro_r(mac, macro_type, arg1, arg2, output);
1073 			break;
1074 
1075 			/*****************/
1076 			/* STATIC MACROS */
1077 			/*****************/
1078 		case MACRO_ADMINEMAIL:
1079 		case MACRO_ADMINPAGER:
1080 		case MACRO_MAINCONFIGFILE:
1081 		case MACRO_STATUSDATAFILE:
1082 		case MACRO_RETENTIONDATAFILE:
1083 		case MACRO_OBJECTCACHEFILE:
1084 		case MACRO_TEMPFILE:
1085 		case MACRO_LOGFILE:
1086 		case MACRO_RESOURCEFILE:
1087 		case MACRO_COMMANDFILE:
1088 		case MACRO_HOSTPERFDATAFILE:
1089 		case MACRO_SERVICEPERFDATAFILE:
1090 		case MACRO_PROCESSSTARTTIME:
1091 		case MACRO_TEMPPATH:
1092 		case MACRO_EVENTSTARTTIME:
1093 
1094 			/* no need to do any more work - these are already precomputed for us */
1095 			*output = global_macros.x[macro_type];
1096 			*free_macro = FALSE;
1097 			break;
1098 
1099 			/******************/
1100 			/* SUMMARY MACROS */
1101 			/******************/
1102 		case MACRO_TOTALHOSTSUP:
1103 		case MACRO_TOTALHOSTSDOWN:
1104 		case MACRO_TOTALHOSTSUNREACHABLE:
1105 		case MACRO_TOTALHOSTSDOWNUNHANDLED:
1106 		case MACRO_TOTALHOSTSUNREACHABLEUNHANDLED:
1107 		case MACRO_TOTALHOSTPROBLEMS:
1108 		case MACRO_TOTALHOSTPROBLEMSUNHANDLED:
1109 		case MACRO_TOTALSERVICESOK:
1110 		case MACRO_TOTALSERVICESWARNING:
1111 		case MACRO_TOTALSERVICESCRITICAL:
1112 		case MACRO_TOTALSERVICESUNKNOWN:
1113 		case MACRO_TOTALSERVICESWARNINGUNHANDLED:
1114 		case MACRO_TOTALSERVICESCRITICALUNHANDLED:
1115 		case MACRO_TOTALSERVICESUNKNOWNUNHANDLED:
1116 		case MACRO_TOTALSERVICEPROBLEMS:
1117 		case MACRO_TOTALSERVICEPROBLEMSUNHANDLED:
1118 
1119 #ifdef NSCORE
1120 			/* generate summary macros if needed */
1121 			if(mac->x[MACRO_TOTALHOSTSUP] == NULL) {
1122 
1123 				/* get host totals */
1124 				for(temp_host = host_list; temp_host != NULL; temp_host = temp_host->next) {
1125 
1126 					/* filter totals based on contact if necessary */
1127 					if(mac->contact_ptr != NULL)
1128 						authorized = is_contact_for_host(temp_host, mac->contact_ptr);
1129 
1130 					if(authorized == TRUE) {
1131 						problem = TRUE;
1132 
1133 						if(temp_host->current_state == HOST_UP && temp_host->has_been_checked == TRUE)
1134 							hosts_up++;
1135 						else if(temp_host->current_state == HOST_DOWN) {
1136 							if(temp_host->scheduled_downtime_depth > 0)
1137 								problem = FALSE;
1138 							if(temp_host->problem_has_been_acknowledged == TRUE)
1139 								problem = FALSE;
1140 							if(temp_host->checks_enabled == FALSE)
1141 								problem = FALSE;
1142 							if(problem == TRUE)
1143 								hosts_down_unhandled++;
1144 							hosts_down++;
1145 							}
1146 						else if(temp_host->current_state == HOST_UNREACHABLE) {
1147 							if(temp_host->scheduled_downtime_depth > 0)
1148 								problem = FALSE;
1149 							if(temp_host->problem_has_been_acknowledged == TRUE)
1150 								problem = FALSE;
1151 							if(temp_host->checks_enabled == FALSE)
1152 								problem = FALSE;
1153 							if(problem == TRUE)
1154 								hosts_down_unhandled++;
1155 							hosts_unreachable++;
1156 							}
1157 						}
1158 					}
1159 
1160 				host_problems = hosts_down + hosts_unreachable;
1161 				host_problems_unhandled = hosts_down_unhandled + hosts_unreachable_unhandled;
1162 
1163 				/* get service totals */
1164 				for(temp_service = service_list; temp_service != NULL; temp_service = temp_service->next) {
1165 
1166 					/* filter totals based on contact if necessary */
1167 					if(mac->contact_ptr != NULL)
1168 						authorized = is_contact_for_service(temp_service, mac->contact_ptr);
1169 
1170 					if(authorized == TRUE) {
1171 						problem = TRUE;
1172 
1173 						if(temp_service->current_state == STATE_OK && temp_service->has_been_checked == TRUE)
1174 							services_ok++;
1175 						else if(temp_service->current_state == STATE_WARNING) {
1176 							temp_host = find_host(temp_service->host_name);
1177 							if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE))
1178 								problem = FALSE;
1179 							if(temp_service->scheduled_downtime_depth > 0)
1180 								problem = FALSE;
1181 							if(temp_service->problem_has_been_acknowledged == TRUE)
1182 								problem = FALSE;
1183 							if(temp_service->checks_enabled == FALSE)
1184 								problem = FALSE;
1185 							if(problem == TRUE)
1186 								services_warning_unhandled++;
1187 							services_warning++;
1188 							}
1189 						else if(temp_service->current_state == STATE_UNKNOWN) {
1190 							temp_host = find_host(temp_service->host_name);
1191 							if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE))
1192 								problem = FALSE;
1193 							if(temp_service->scheduled_downtime_depth > 0)
1194 								problem = FALSE;
1195 							if(temp_service->problem_has_been_acknowledged == TRUE)
1196 								problem = FALSE;
1197 							if(temp_service->checks_enabled == FALSE)
1198 								problem = FALSE;
1199 							if(problem == TRUE)
1200 								services_unknown_unhandled++;
1201 							services_unknown++;
1202 							}
1203 						else if(temp_service->current_state == STATE_CRITICAL) {
1204 							temp_host = find_host(temp_service->host_name);
1205 							if(temp_host != NULL && (temp_host->current_state == HOST_DOWN || temp_host->current_state == HOST_UNREACHABLE))
1206 								problem = FALSE;
1207 							if(temp_service->scheduled_downtime_depth > 0)
1208 								problem = FALSE;
1209 							if(temp_service->problem_has_been_acknowledged == TRUE)
1210 								problem = FALSE;
1211 							if(temp_service->checks_enabled == FALSE)
1212 								problem = FALSE;
1213 							if(problem == TRUE)
1214 								services_critical_unhandled++;
1215 							services_critical++;
1216 							}
1217 						}
1218 					}
1219 
1220 				service_problems = services_warning + services_critical + services_unknown;
1221 				service_problems_unhandled = services_warning_unhandled + services_critical_unhandled + services_unknown_unhandled;
1222 
1223 				/* these macros are time-intensive to compute, and will likely be used together, so save them all for future use */
1224 				for(x = MACRO_TOTALHOSTSUP; x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED; x++)
1225 					my_free(mac->x[x]);
1226 				asprintf(&mac->x[MACRO_TOTALHOSTSUP], "%d", hosts_up);
1227 				asprintf(&mac->x[MACRO_TOTALHOSTSDOWN], "%d", hosts_down);
1228 				asprintf(&mac->x[MACRO_TOTALHOSTSUNREACHABLE], "%d", hosts_unreachable);
1229 				asprintf(&mac->x[MACRO_TOTALHOSTSDOWNUNHANDLED], "%d", hosts_down_unhandled);
1230 				asprintf(&mac->x[MACRO_TOTALHOSTSUNREACHABLEUNHANDLED], "%d", hosts_unreachable_unhandled);
1231 				asprintf(&mac->x[MACRO_TOTALHOSTPROBLEMS], "%d", host_problems);
1232 				asprintf(&mac->x[MACRO_TOTALHOSTPROBLEMSUNHANDLED], "%d", host_problems_unhandled);
1233 				asprintf(&mac->x[MACRO_TOTALSERVICESOK], "%d", services_ok);
1234 				asprintf(&mac->x[MACRO_TOTALSERVICESWARNING], "%d", services_warning);
1235 				asprintf(&mac->x[MACRO_TOTALSERVICESCRITICAL], "%d", services_critical);
1236 				asprintf(&mac->x[MACRO_TOTALSERVICESUNKNOWN], "%d", services_unknown);
1237 				asprintf(&mac->x[MACRO_TOTALSERVICESWARNINGUNHANDLED], "%d", services_warning_unhandled);
1238 				asprintf(&mac->x[MACRO_TOTALSERVICESCRITICALUNHANDLED], "%d", services_critical_unhandled);
1239 				asprintf(&mac->x[MACRO_TOTALSERVICESUNKNOWNUNHANDLED], "%d", services_unknown_unhandled);
1240 				asprintf(&mac->x[MACRO_TOTALSERVICEPROBLEMS], "%d", service_problems);
1241 				asprintf(&mac->x[MACRO_TOTALSERVICEPROBLEMSUNHANDLED], "%d", service_problems_unhandled);
1242 				}
1243 
1244 			/* return only the macro the user requested */
1245 			*output = mac->x[macro_type];
1246 
1247 			/* tell caller to NOT free memory when done */
1248 			*free_macro = FALSE;
1249 #endif
1250 			break;
1251 
1252 		default:
1253 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED MACRO #%d! THIS IS A BUG!\n", macro_type);
1254 			return ERROR;
1255 			break;
1256 		}
1257 
1258 	return result;
1259 	}
1260 
1261 int grab_macrox_value(int macro_type, char *arg1, char *arg2, char **output, int *free_macro) {
1262 	return grab_macrox_value_r(&global_macros, macro_type, arg1, arg2, output, free_macro);
1263 	}
1264 
1265 
1266 /* calculates the value of a custom macro */
1267 int grab_custom_macro_value_r(nagios_macros *mac, char *macro_name, char *arg1, char *arg2, char **output) {
1268 	host *temp_host = NULL;
1269 	hostgroup *temp_hostgroup = NULL;
1270 	hostsmember *temp_hostsmember = NULL;
1271 	service *temp_service = NULL;
1272 	servicegroup *temp_servicegroup = NULL;
1273 	servicesmember *temp_servicesmember = NULL;
1274 	contact *temp_contact = NULL;
1275 	contactgroup *temp_contactgroup = NULL;
1276 	contactsmember *temp_contactsmember = NULL;
1277 	int delimiter_len = 0;
1278 	char *temp_buffer = NULL;
1279 	int result = OK;
1280 
1281 	if(macro_name == NULL || output == NULL)
1282 		return ERROR;
1283 
1284 	/***** CUSTOM HOST MACRO *****/
1285 	if(strstr(macro_name, "_HOST") == macro_name) {
1286 
1287 		/* a standard host macro */
1288 		if(arg2 == NULL) {
1289 
1290 			/* find the host for on-demand macros */
1291 			if(arg1) {
1292 				if((temp_host = find_host(arg1)) == NULL)
1293 					return ERROR;
1294 				}
1295 
1296 			/* else use saved host pointer */
1297 			else if((temp_host = mac->host_ptr) == NULL)
1298 				return ERROR;
1299 
1300 			/* get the host macro value */
1301 			result = grab_custom_object_macro_r(mac, macro_name + 5, temp_host->custom_variables, output);
1302 			}
1303 
1304 		/* a host macro with a hostgroup name and delimiter */
1305 		else {
1306 			if((temp_hostgroup = find_hostgroup(arg1)) == NULL)
1307 				return ERROR;
1308 
1309 			delimiter_len = strlen(arg2);
1310 
1311 			/* concatenate macro values for all hostgroup members */
1312 			for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
1313 
1314 #ifdef NSCORE
1315 				if((temp_host = temp_hostsmember->host_ptr) == NULL)
1316 					continue;
1317 #else
1318 				if((temp_host = find_host(temp_hostsmember->host_name)) == NULL)
1319 					continue;
1320 #endif
1321 
1322 				/* get the macro value for this host */
1323 				grab_custom_macro_value_r(mac, macro_name, temp_host->name, NULL, &temp_buffer);
1324 
1325 				if(temp_buffer == NULL)
1326 					continue;
1327 
1328 				/* add macro value to already running macro */
1329 				if(*output == NULL)
1330 					*output = (char *)strdup(temp_buffer);
1331 				else {
1332 					if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
1333 						continue;
1334 					strcat(*output, arg2);
1335 					strcat(*output, temp_buffer);
1336 					}
1337 				my_free(temp_buffer);
1338 				}
1339 			}
1340 		}
1341 
1342 	/***** CUSTOM SERVICE MACRO *****/
1343 	else if(strstr(macro_name, "_SERVICE") == macro_name) {
1344 
1345 		/* use saved service pointer */
1346 		if(arg1 == NULL && arg2 == NULL) {
1347 
1348 			if((temp_service = mac->service_ptr) == NULL)
1349 				return ERROR;
1350 
1351 			/* get the service macro value */
1352 			result = grab_custom_object_macro_r(mac, macro_name + 8, temp_service->custom_variables, output);
1353 			}
1354 
1355 		/* else and ondemand macro... */
1356 		else {
1357 
1358 			/* if first arg is blank, it means use the current host name */
1359 			if(mac->host_ptr == NULL)
1360 				return ERROR;
1361 			if((temp_service = find_service((mac->host_ptr) ? mac->host_ptr->name : NULL, arg2))) {
1362 
1363 				/* get the service macro value */
1364 				result = grab_custom_object_macro_r(mac, macro_name + 8, temp_service->custom_variables, output);
1365 				}
1366 
1367 			/* else we have a service macro with a servicegroup name and a delimiter... */
1368 			else {
1369 
1370 				if((temp_servicegroup = find_servicegroup(arg1)) == NULL)
1371 					return ERROR;
1372 
1373 				delimiter_len = strlen(arg2);
1374 
1375 				/* concatenate macro values for all servicegroup members */
1376 				for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
1377 
1378 #ifdef NSCORE
1379 					if((temp_service = temp_servicesmember->service_ptr) == NULL)
1380 						continue;
1381 #else
1382 					if((temp_service = find_service(temp_servicesmember->host_name, temp_servicesmember->service_description)) == NULL)
1383 						continue;
1384 #endif
1385 
1386 					/* get the macro value for this service */
1387 					grab_custom_macro_value_r(mac, macro_name, temp_service->host_name, temp_service->description, &temp_buffer);
1388 
1389 					if(temp_buffer == NULL)
1390 						continue;
1391 
1392 					/* add macro value to already running macro */
1393 					if(*output == NULL)
1394 						*output = (char *)strdup(temp_buffer);
1395 					else {
1396 						if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
1397 							continue;
1398 						strcat(*output, arg2);
1399 						strcat(*output, temp_buffer);
1400 						}
1401 					my_free(temp_buffer);
1402 					}
1403 				}
1404 			}
1405 		}
1406 
1407 	/***** CUSTOM CONTACT VARIABLE *****/
1408 	else if(strstr(macro_name, "_CONTACT") == macro_name) {
1409 
1410 		/* a standard contact macro */
1411 		if(arg2 == NULL) {
1412 
1413 			/* find the contact for on-demand macros */
1414 			if(arg1) {
1415 				if((temp_contact = find_contact(arg1)) == NULL)
1416 					return ERROR;
1417 				}
1418 
1419 			/* else use saved contact pointer */
1420 			else if((temp_contact = mac->contact_ptr) == NULL)
1421 				return ERROR;
1422 
1423 			/* get the contact macro value */
1424 			result = grab_custom_object_macro_r(mac, macro_name + 8, temp_contact->custom_variables, output);
1425 			}
1426 
1427 		/* a contact macro with a contactgroup name and delimiter */
1428 		else {
1429 
1430 			if((temp_contactgroup = find_contactgroup(arg1)) == NULL)
1431 				return ERROR;
1432 
1433 			delimiter_len = strlen(arg2);
1434 
1435 			/* concatenate macro values for all contactgroup members */
1436 			for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
1437 
1438 #ifdef NSCORE
1439 				if((temp_contact = temp_contactsmember->contact_ptr) == NULL)
1440 					continue;
1441 #else
1442 				if((temp_contact = find_contact(temp_contactsmember->contact_name)) == NULL)
1443 					continue;
1444 #endif
1445 
1446 				/* get the macro value for this contact */
1447 				grab_custom_macro_value_r(mac, macro_name, temp_contact->name, NULL, &temp_buffer);
1448 
1449 				if(temp_buffer == NULL)
1450 					continue;
1451 
1452 				/* add macro value to already running macro */
1453 				if(*output == NULL)
1454 					*output = (char *)strdup(temp_buffer);
1455 				else {
1456 					if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_buffer) + delimiter_len + 1)) == NULL)
1457 						continue;
1458 					strcat(*output, arg2);
1459 					strcat(*output, temp_buffer);
1460 					}
1461 				my_free(temp_buffer);
1462 				}
1463 			}
1464 		}
1465 
1466 	else
1467 		return ERROR;
1468 
1469 	return result;
1470 	}
1471 
1472 int grab_custom_macro_value(char *macro_name, char *arg1, char *arg2, char **output) {
1473 	return grab_custom_macro_value_r(&global_macros, macro_name, arg1, arg2, output);
1474 	}
1475 
1476 
1477 /* calculates a date/time macro */
1478 int grab_datetime_macro_r(nagios_macros *mac, int macro_type, char *arg1, char *arg2, char **output) {
1479 	time_t current_time = 0L;
1480 	timeperiod *temp_timeperiod = NULL;
1481 	time_t test_time = 0L;
1482 #ifdef NSCORE
1483 	time_t next_valid_time = 0L;
1484 #endif
1485 
1486 	if(output == NULL)
1487 		return ERROR;
1488 
1489 	/* get the current time */
1490 	time(&current_time);
1491 
1492 	/* parse args, do prep work */
1493 	switch(macro_type) {
1494 
1495 		case MACRO_ISVALIDTIME:
1496 		case MACRO_NEXTVALIDTIME:
1497 
1498 			/* find the timeperiod */
1499 			if((temp_timeperiod = find_timeperiod(arg1)) == NULL)
1500 				return ERROR;
1501 
1502 			/* what timestamp should we use? */
1503 			if(arg2)
1504 				test_time = (time_t)strtoul(arg2, NULL, 0);
1505 			else
1506 				test_time = current_time;
1507 			break;
1508 
1509 		default:
1510 			break;
1511 		}
1512 
1513 	/* calculate the value */
1514 	switch(macro_type) {
1515 
1516 		case MACRO_LONGDATETIME:
1517 			if(*output == NULL)
1518 				*output = (char *)malloc(MAX_DATETIME_LENGTH);
1519 			if(*output)
1520 				get_datetime_string(&current_time, *output, MAX_DATETIME_LENGTH, LONG_DATE_TIME);
1521 			break;
1522 
1523 		case MACRO_SHORTDATETIME:
1524 			if(*output == NULL)
1525 				*output = (char *)malloc(MAX_DATETIME_LENGTH);
1526 			if(*output)
1527 				get_datetime_string(&current_time, *output, MAX_DATETIME_LENGTH, SHORT_DATE_TIME);
1528 			break;
1529 
1530 		case MACRO_DATE:
1531 			if(*output == NULL)
1532 				*output = (char *)malloc(MAX_DATETIME_LENGTH);
1533 			if(*output)
1534 				get_datetime_string(&current_time, *output, MAX_DATETIME_LENGTH, SHORT_DATE);
1535 			break;
1536 
1537 		case MACRO_TIME:
1538 			if(*output == NULL)
1539 				*output = (char *)malloc(MAX_DATETIME_LENGTH);
1540 			if(*output)
1541 				get_datetime_string(&current_time, *output, MAX_DATETIME_LENGTH, SHORT_TIME);
1542 			break;
1543 
1544 		case MACRO_TIMET:
1545 			asprintf(output, "%lu", (unsigned long)current_time);
1546 			break;
1547 
1548 #ifdef NSCORE
1549 		case MACRO_ISVALIDTIME:
1550 			asprintf(output, "%d", (check_time_against_period(test_time, temp_timeperiod) == OK) ? 1 : 0);
1551 			break;
1552 
1553 		case MACRO_NEXTVALIDTIME:
1554 			get_next_valid_time(test_time, &next_valid_time, temp_timeperiod);
1555 			if(next_valid_time == test_time && check_time_against_period(test_time, temp_timeperiod) == ERROR)
1556 				next_valid_time = (time_t)0L;
1557 			asprintf(output, "%lu", (unsigned long)next_valid_time);
1558 			break;
1559 #endif
1560 
1561 		default:
1562 			return ERROR;
1563 			break;
1564 		}
1565 
1566 	return OK;
1567 	}
1568 
1569 int grab_datetime_macro(int macro_type, char *arg1, char *arg2, char **output) {
1570 	return grab_datetime_macro_r(&global_macros, macro_type, arg1, arg2, output);
1571 	}
1572 
1573 
1574 /* calculates a host macro */
1575 int grab_standard_host_macro_r(nagios_macros *mac, int macro_type, host *temp_host, char **output, int *free_macro) {
1576 	char *temp_buffer = NULL;
1577 #ifdef NSCORE
1578 	hostgroup *temp_hostgroup = NULL;
1579 	servicesmember *temp_servicesmember = NULL;
1580 	service *temp_service = NULL;
1581 	objectlist *temp_objectlist = NULL;
1582 	time_t current_time = 0L;
1583 	unsigned long duration = 0L;
1584 	int days = 0;
1585 	int hours = 0;
1586 	int minutes = 0;
1587 	int seconds = 0;
1588 	char *buf1 = NULL;
1589 	char *buf2 = NULL;
1590 	int total_host_services = 0;
1591 	int total_host_services_ok = 0;
1592 	int total_host_services_warning = 0;
1593 	int total_host_services_unknown = 0;
1594 	int total_host_services_critical = 0;
1595 #endif
1596 
1597 	if(temp_host == NULL || output == NULL || free_macro == NULL)
1598 		return ERROR;
1599 
1600 	/* BY DEFAULT TELL CALLER TO FREE MACRO BUFFER WHEN DONE */
1601 	*free_macro = TRUE;
1602 
1603 	/* get the macro */
1604 	switch(macro_type) {
1605 
1606 		case MACRO_HOSTNAME:
1607 			*output = (char *)strdup(temp_host->name);
1608 			break;
1609 		case MACRO_HOSTDISPLAYNAME:
1610 			if(temp_host->display_name)
1611 				*output = (char *)strdup(temp_host->display_name);
1612 			break;
1613 		case MACRO_HOSTALIAS:
1614 			*output = (char *)strdup(temp_host->alias);
1615 			break;
1616 		case MACRO_HOSTADDRESS:
1617 			*output = (char *)strdup(temp_host->address);
1618 			break;
1619 #ifdef NSCORE
1620 		case MACRO_HOSTSTATE:
1621 			if(temp_host->current_state == HOST_DOWN)
1622 				*output = (char *)strdup("DOWN");
1623 			else if(temp_host->current_state == HOST_UNREACHABLE)
1624 				*output = (char *)strdup("UNREACHABLE");
1625 			else
1626 				*output = (char *)strdup("UP");
1627 			break;
1628 		case MACRO_HOSTSTATEID:
1629 			asprintf(output, "%d", temp_host->current_state);
1630 			break;
1631 		case MACRO_LASTHOSTSTATE:
1632 			if(temp_host->last_state == HOST_DOWN)
1633 				*output = (char *)strdup("DOWN");
1634 			else if(temp_host->last_state == HOST_UNREACHABLE)
1635 				*output = (char *)strdup("UNREACHABLE");
1636 			else
1637 				*output = (char *)strdup("UP");
1638 			break;
1639 		case MACRO_LASTHOSTSTATEID:
1640 			asprintf(output, "%d", temp_host->last_state);
1641 			break;
1642 		case MACRO_HOSTCHECKTYPE:
1643 			asprintf(output, "%s", (temp_host->check_type == HOST_CHECK_PASSIVE) ? "PASSIVE" : "ACTIVE");
1644 			break;
1645 		case MACRO_HOSTSTATETYPE:
1646 			asprintf(output, "%s", (temp_host->state_type == HARD_STATE) ? "HARD" : "SOFT");
1647 			break;
1648 		case MACRO_HOSTOUTPUT:
1649 			if(temp_host->plugin_output)
1650 				*output = (char *)strdup(temp_host->plugin_output);
1651 			break;
1652 		case MACRO_LONGHOSTOUTPUT:
1653 			if(temp_host->long_plugin_output)
1654 				*output = (char *)strdup(temp_host->long_plugin_output);
1655 			break;
1656 		case MACRO_HOSTPERFDATA:
1657 			if(temp_host->perf_data)
1658 				*output = (char *)strdup(temp_host->perf_data);
1659 			break;
1660 #endif
1661 		case MACRO_HOSTCHECKCOMMAND:
1662 			if(temp_host->host_check_command)
1663 				*output = (char *)strdup(temp_host->host_check_command);
1664 			break;
1665 #ifdef NSCORE
1666 		case MACRO_HOSTATTEMPT:
1667 			asprintf(output, "%d", temp_host->current_attempt);
1668 			break;
1669 		case MACRO_MAXHOSTATTEMPTS:
1670 			asprintf(output, "%d", temp_host->max_attempts);
1671 			break;
1672 		case MACRO_HOSTDOWNTIME:
1673 			asprintf(output, "%d", temp_host->scheduled_downtime_depth);
1674 			break;
1675 		case MACRO_HOSTPERCENTCHANGE:
1676 			asprintf(output, "%.2f", temp_host->percent_state_change);
1677 			break;
1678 		case MACRO_HOSTDURATIONSEC:
1679 		case MACRO_HOSTDURATION:
1680 			time(&current_time);
1681 			duration = (unsigned long)(current_time - temp_host->last_state_change);
1682 
1683 			if(macro_type == MACRO_HOSTDURATIONSEC)
1684 				asprintf(output, "%lu", duration);
1685 			else {
1686 
1687 				days = duration / 86400;
1688 				duration -= (days * 86400);
1689 				hours = duration / 3600;
1690 				duration -= (hours * 3600);
1691 				minutes = duration / 60;
1692 				duration -= (minutes * 60);
1693 				seconds = duration;
1694 				asprintf(output, "%dd %dh %dm %ds", days, hours, minutes, seconds);
1695 				}
1696 			break;
1697 		case MACRO_HOSTEXECUTIONTIME:
1698 			asprintf(output, "%.3f", temp_host->execution_time);
1699 			break;
1700 		case MACRO_HOSTLATENCY:
1701 			asprintf(output, "%.3f", temp_host->latency);
1702 			break;
1703 		case MACRO_LASTHOSTCHECK:
1704 			asprintf(output, "%lu", (unsigned long)temp_host->last_check);
1705 			break;
1706 		case MACRO_LASTHOSTSTATECHANGE:
1707 			asprintf(output, "%lu", (unsigned long)temp_host->last_state_change);
1708 			break;
1709 		case MACRO_LASTHOSTUP:
1710 			asprintf(output, "%lu", (unsigned long)temp_host->last_time_up);
1711 			break;
1712 		case MACRO_LASTHOSTDOWN:
1713 			asprintf(output, "%lu", (unsigned long)temp_host->last_time_down);
1714 			break;
1715 		case MACRO_LASTHOSTUNREACHABLE:
1716 			asprintf(output, "%lu", (unsigned long)temp_host->last_time_unreachable);
1717 			break;
1718 		case MACRO_HOSTNOTIFICATIONNUMBER:
1719 			asprintf(output, "%d", temp_host->current_notification_number);
1720 			break;
1721 		case MACRO_HOSTNOTIFICATIONID:
1722 			asprintf(output, "%lu", temp_host->current_notification_id);
1723 			break;
1724 		case MACRO_HOSTEVENTID:
1725 			asprintf(output, "%lu", temp_host->current_event_id);
1726 			break;
1727 		case MACRO_LASTHOSTEVENTID:
1728 			asprintf(output, "%lu", temp_host->last_event_id);
1729 			break;
1730 		case MACRO_HOSTPROBLEMID:
1731 			asprintf(output, "%lu", temp_host->current_problem_id);
1732 			break;
1733 		case MACRO_LASTHOSTPROBLEMID:
1734 			asprintf(output, "%lu", temp_host->last_problem_id);
1735 			break;
1736 #endif
1737 		case MACRO_HOSTACTIONURL:
1738 			if(temp_host->action_url)
1739 				*output = (char *)strdup(temp_host->action_url);
1740 			break;
1741 		case MACRO_HOSTNOTESURL:
1742 			if(temp_host->notes_url)
1743 				*output = (char *)strdup(temp_host->notes_url);
1744 			break;
1745 		case MACRO_HOSTNOTES:
1746 			if(temp_host->notes)
1747 				*output = (char *)strdup(temp_host->notes);
1748 			break;
1749 #ifdef NSCORE
1750 		case MACRO_HOSTGROUPNAMES:
1751 			/* find all hostgroups this host is associated with */
1752 			for(temp_objectlist = temp_host->hostgroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) {
1753 
1754 				if((temp_hostgroup = (hostgroup *)temp_objectlist->object_ptr) == NULL)
1755 					continue;
1756 
1757 				asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_hostgroup->group_name);
1758 				my_free(buf2);
1759 				buf2 = buf1;
1760 				}
1761 			if(buf2) {
1762 				*output = (char *)strdup(buf2);
1763 				my_free(buf2);
1764 				}
1765 			break;
1766 		case MACRO_TOTALHOSTSERVICES:
1767 		case MACRO_TOTALHOSTSERVICESOK:
1768 		case MACRO_TOTALHOSTSERVICESWARNING:
1769 		case MACRO_TOTALHOSTSERVICESUNKNOWN:
1770 		case MACRO_TOTALHOSTSERVICESCRITICAL:
1771 
1772 			/* generate host service summary macros (if they haven't already been computed) */
1773 			if(mac->x[MACRO_TOTALHOSTSERVICES] == NULL) {
1774 
1775 				for(temp_servicesmember = temp_host->services; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
1776 					if((temp_service = temp_servicesmember->service_ptr) == NULL)
1777 						continue;
1778 
1779 					total_host_services++;
1780 
1781 					switch(temp_service->current_state) {
1782 						case STATE_OK:
1783 							total_host_services_ok++;
1784 							break;
1785 						case STATE_WARNING:
1786 							total_host_services_warning++;
1787 							break;
1788 						case STATE_UNKNOWN:
1789 							total_host_services_unknown++;
1790 							break;
1791 						case STATE_CRITICAL:
1792 							total_host_services_critical++;
1793 							break;
1794 						default:
1795 							break;
1796 						}
1797 					}
1798 
1799 				/* these macros are time-intensive to compute, and will likely be used together, so save them all for future use */
1800 				my_free(mac->x[MACRO_TOTALHOSTSERVICES]);
1801 				asprintf(&mac->x[MACRO_TOTALHOSTSERVICES], "%d", total_host_services);
1802 				my_free(mac->x[MACRO_TOTALHOSTSERVICESOK]);
1803 				asprintf(&mac->x[MACRO_TOTALHOSTSERVICESOK], "%d", total_host_services_ok);
1804 				my_free(mac->x[MACRO_TOTALHOSTSERVICESWARNING]);
1805 				asprintf(&mac->x[MACRO_TOTALHOSTSERVICESWARNING], "%d", total_host_services_warning);
1806 				my_free(mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN]);
1807 				asprintf(&mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN], "%d", total_host_services_unknown);
1808 				my_free(mac->x[MACRO_TOTALHOSTSERVICESCRITICAL]);
1809 				asprintf(&mac->x[MACRO_TOTALHOSTSERVICESCRITICAL], "%d", total_host_services_critical);
1810 				}
1811 
1812 			/* return only the macro the user requested */
1813 			*output = mac->x[macro_type];
1814 
1815 			/* tell caller to NOT free memory when done */
1816 			*free_macro = FALSE;
1817 			break;
1818 #endif
1819 			/***************/
1820 			/* MISC MACROS */
1821 			/***************/
1822 		case MACRO_HOSTACKAUTHOR:
1823 		case MACRO_HOSTACKAUTHORNAME:
1824 		case MACRO_HOSTACKAUTHORALIAS:
1825 		case MACRO_HOSTACKCOMMENT:
1826 			/* no need to do any more work - these are already precomputed elsewhere */
1827 			/* NOTE: these macros won't work as on-demand macros */
1828 			*output = mac->x[macro_type];
1829 			*free_macro = FALSE;
1830 			break;
1831 
1832 		default:
1833 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED HOST MACRO #%d! THIS IS A BUG!\n", macro_type);
1834 			return ERROR;
1835 			break;
1836 		}
1837 
1838 	/* post-processing */
1839 	/* notes, notes URL and action URL macros may themselves contain macros, so process them... */
1840 	switch(macro_type) {
1841 		case MACRO_HOSTACTIONURL:
1842 		case MACRO_HOSTNOTESURL:
1843 			process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS);
1844 			my_free(*output);
1845 			*output = temp_buffer;
1846 			break;
1847 		case MACRO_HOSTNOTES:
1848 			process_macros_r(mac, *output, &temp_buffer, 0);
1849 			my_free(*output);
1850 			*output = temp_buffer;
1851 			break;
1852 		default:
1853 			break;
1854 		}
1855 
1856 	return OK;
1857 	}
1858 
1859 int grab_standard_host_macro(int macro_type, host *temp_host, char **output, int *free_macro) {
1860 	return grab_standard_host_macro_r(&global_macros, macro_type, temp_host, output, free_macro);
1861 	}
1862 
1863 
1864 /* computes a hostgroup macro */
1865 int grab_standard_hostgroup_macro_r(nagios_macros *mac, int macro_type, hostgroup *temp_hostgroup, char **output) {
1866 	hostsmember *temp_hostsmember = NULL;
1867 	char *temp_buffer = NULL;
1868 	unsigned int	temp_len = 0;
1869 	unsigned int	init_len = 0;
1870 
1871 	if(temp_hostgroup == NULL || output == NULL)
1872 		return ERROR;
1873 
1874 	/* get the macro value */
1875 	switch(macro_type) {
1876 		case MACRO_HOSTGROUPNAME:
1877 			*output = (char *)strdup(temp_hostgroup->group_name);
1878 			break;
1879 		case MACRO_HOSTGROUPALIAS:
1880 			if(temp_hostgroup->alias)
1881 				*output = (char *)strdup(temp_hostgroup->alias);
1882 			break;
1883 		case MACRO_HOSTGROUPMEMBERS:
1884 			/* make the calculations for total string length */
1885 			for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
1886 				if(temp_hostsmember->host_name == NULL)
1887 					continue;
1888 				if(temp_len == 0) {
1889 					temp_len += strlen(temp_hostsmember->host_name) + 1;
1890 					}
1891 				else {
1892 					temp_len += strlen(temp_hostsmember->host_name) + 2;
1893 					}
1894 				}
1895 			/* allocate or reallocate the memory buffer */
1896 			if(*output == NULL) {
1897 				*output = (char *)malloc(temp_len);
1898 				}
1899 			else {
1900 				init_len = strlen(*output);
1901 				temp_len += init_len;
1902 				*output = (char *)realloc(*output, temp_len);
1903 				}
1904 			/* now fill in the string with the member names */
1905 			for(temp_hostsmember = temp_hostgroup->members; temp_hostsmember != NULL; temp_hostsmember = temp_hostsmember->next) {
1906 				if(temp_hostsmember->host_name == NULL)
1907 					continue;
1908 				temp_buffer = *output + init_len;
1909 				if(init_len == 0) {  /* If our buffer didn't contain anything, we just need to write "%s,%s" */
1910 					init_len += sprintf(temp_buffer, "%s", temp_hostsmember->host_name);
1911 					}
1912 				else {
1913 					init_len += sprintf(temp_buffer, ",%s", temp_hostsmember->host_name);
1914 					}
1915 				}
1916 			break;
1917 		case MACRO_HOSTGROUPACTIONURL:
1918 			if(temp_hostgroup->action_url)
1919 				*output = (char *)strdup(temp_hostgroup->action_url);
1920 			break;
1921 		case MACRO_HOSTGROUPNOTESURL:
1922 			if(temp_hostgroup->notes_url)
1923 				*output = (char *)strdup(temp_hostgroup->notes_url);
1924 			break;
1925 		case MACRO_HOSTGROUPNOTES:
1926 			if(temp_hostgroup->notes)
1927 				*output = (char *)strdup(temp_hostgroup->notes);
1928 			break;
1929 		default:
1930 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED HOSTGROUP MACRO #%d! THIS IS A BUG!\n", macro_type);
1931 			return ERROR;
1932 			break;
1933 		}
1934 
1935 	/* post-processing */
1936 	/* notes, notes URL and action URL macros may themselves contain macros, so process them... */
1937 	switch(macro_type) {
1938 		case MACRO_HOSTGROUPACTIONURL:
1939 		case MACRO_HOSTGROUPNOTESURL:
1940 			process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS);
1941 			my_free(*output);
1942 			*output = temp_buffer;
1943 			break;
1944 		case MACRO_HOSTGROUPNOTES:
1945 			process_macros_r(mac, *output, &temp_buffer, 0);
1946 			my_free(*output);
1947 			*output = temp_buffer;
1948 			break;
1949 		default:
1950 			break;
1951 		}
1952 
1953 	return OK;
1954 	}
1955 
1956 int grab_standard_hostgroup_macro(int macro_type, hostgroup *temp_hostgroup, char **output) {
1957 	return grab_standard_hostgroup_macro_r(&global_macros, macro_type, temp_hostgroup, output);
1958 	}
1959 
1960 
1961 /* computes a service macro */
1962 int grab_standard_service_macro_r(nagios_macros *mac, int macro_type, service *temp_service, char **output, int *free_macro) {
1963 	char *temp_buffer = NULL;
1964 #ifdef NSCORE
1965 	servicegroup *temp_servicegroup = NULL;
1966 	objectlist *temp_objectlist = NULL;
1967 	time_t current_time = 0L;
1968 	unsigned long duration = 0L;
1969 	int days = 0;
1970 	int hours = 0;
1971 	int minutes = 0;
1972 	int seconds = 0;
1973 	char *buf1 = NULL;
1974 	char *buf2 = NULL;
1975 #endif
1976 
1977 	if(temp_service == NULL || output == NULL)
1978 		return ERROR;
1979 
1980 	/* BY DEFAULT TELL CALLER TO FREE MACRO BUFFER WHEN DONE */
1981 	*free_macro = TRUE;
1982 
1983 	/* get the macro value */
1984 	switch(macro_type) {
1985 		case MACRO_SERVICEDESC:
1986 			*output = (char *)strdup(temp_service->description);
1987 			break;
1988 		case MACRO_SERVICEDISPLAYNAME:
1989 			if(temp_service->display_name)
1990 				*output = (char *)strdup(temp_service->display_name);
1991 			break;
1992 #ifdef NSCORE
1993 		case MACRO_SERVICEOUTPUT:
1994 			if(temp_service->plugin_output)
1995 				*output = (char *)strdup(temp_service->plugin_output);
1996 			break;
1997 		case MACRO_LONGSERVICEOUTPUT:
1998 			if(temp_service->long_plugin_output)
1999 				*output = (char *)strdup(temp_service->long_plugin_output);
2000 			break;
2001 		case MACRO_SERVICEPERFDATA:
2002 			if(temp_service->perf_data)
2003 				*output = (char *)strdup(temp_service->perf_data);
2004 			break;
2005 #endif
2006 		case MACRO_SERVICECHECKCOMMAND:
2007 			if(temp_service->service_check_command)
2008 				*output = (char *)strdup(temp_service->service_check_command);
2009 			break;
2010 #ifdef NSCORE
2011 		case MACRO_SERVICECHECKTYPE:
2012 			*output = (char *)strdup((temp_service->check_type == SERVICE_CHECK_PASSIVE) ? "PASSIVE" : "ACTIVE");
2013 			break;
2014 		case MACRO_SERVICESTATETYPE:
2015 			*output = (char *)strdup((temp_service->state_type == HARD_STATE) ? "HARD" : "SOFT");
2016 			break;
2017 		case MACRO_SERVICESTATE:
2018 			if(temp_service->current_state == STATE_OK)
2019 				*output = (char *)strdup("OK");
2020 			else if(temp_service->current_state == STATE_WARNING)
2021 				*output = (char *)strdup("WARNING");
2022 			else if(temp_service->current_state == STATE_CRITICAL)
2023 				*output = (char *)strdup("CRITICAL");
2024 			else
2025 				*output = (char *)strdup("UNKNOWN");
2026 			break;
2027 		case MACRO_SERVICESTATEID:
2028 			asprintf(output, "%d", temp_service->current_state);
2029 			break;
2030 		case MACRO_LASTSERVICESTATE:
2031 			if(temp_service->last_state == STATE_OK)
2032 				*output = (char *)strdup("OK");
2033 			else if(temp_service->last_state == STATE_WARNING)
2034 				*output = (char *)strdup("WARNING");
2035 			else if(temp_service->last_state == STATE_CRITICAL)
2036 				*output = (char *)strdup("CRITICAL");
2037 			else
2038 				*output = (char *)strdup("UNKNOWN");
2039 			break;
2040 		case MACRO_LASTSERVICESTATEID:
2041 			asprintf(output, "%d", temp_service->last_state);
2042 			break;
2043 #endif
2044 		case MACRO_SERVICEISVOLATILE:
2045 			asprintf(output, "%d", temp_service->is_volatile);
2046 			break;
2047 #ifdef NSCORE
2048 		case MACRO_SERVICEATTEMPT:
2049 			asprintf(output, "%d", temp_service->current_attempt);
2050 			break;
2051 		case MACRO_MAXSERVICEATTEMPTS:
2052 			asprintf(output, "%d", temp_service->max_attempts);
2053 			break;
2054 		case MACRO_SERVICEEXECUTIONTIME:
2055 			asprintf(output, "%.3f", temp_service->execution_time);
2056 			break;
2057 		case MACRO_SERVICELATENCY:
2058 			asprintf(output, "%.3f", temp_service->latency);
2059 			break;
2060 		case MACRO_LASTSERVICECHECK:
2061 			asprintf(output, "%lu", (unsigned long)temp_service->last_check);
2062 			break;
2063 		case MACRO_LASTSERVICESTATECHANGE:
2064 			asprintf(output, "%lu", (unsigned long)temp_service->last_state_change);
2065 			break;
2066 		case MACRO_LASTSERVICEOK:
2067 			asprintf(output, "%lu", (unsigned long)temp_service->last_time_ok);
2068 			break;
2069 		case MACRO_LASTSERVICEWARNING:
2070 			asprintf(output, "%lu", (unsigned long)temp_service->last_time_warning);
2071 			break;
2072 		case MACRO_LASTSERVICEUNKNOWN:
2073 			asprintf(output, "%lu", (unsigned long)temp_service->last_time_unknown);
2074 			break;
2075 		case MACRO_LASTSERVICECRITICAL:
2076 			asprintf(output, "%lu", (unsigned long)temp_service->last_time_critical);
2077 			break;
2078 		case MACRO_SERVICEDOWNTIME:
2079 			asprintf(output, "%d", temp_service->scheduled_downtime_depth);
2080 			break;
2081 		case MACRO_SERVICEPERCENTCHANGE:
2082 			asprintf(output, "%.2f", temp_service->percent_state_change);
2083 			break;
2084 		case MACRO_SERVICEDURATIONSEC:
2085 		case MACRO_SERVICEDURATION:
2086 
2087 			time(&current_time);
2088 			duration = (unsigned long)(current_time - temp_service->last_state_change);
2089 
2090 			/* get the state duration in seconds */
2091 			if(macro_type == MACRO_SERVICEDURATIONSEC)
2092 				asprintf(output, "%lu", duration);
2093 
2094 			/* get the state duration */
2095 			else {
2096 				days = duration / 86400;
2097 				duration -= (days * 86400);
2098 				hours = duration / 3600;
2099 				duration -= (hours * 3600);
2100 				minutes = duration / 60;
2101 				duration -= (minutes * 60);
2102 				seconds = duration;
2103 				asprintf(output, "%dd %dh %dm %ds", days, hours, minutes, seconds);
2104 				}
2105 			break;
2106 		case MACRO_SERVICENOTIFICATIONNUMBER:
2107 			asprintf(output, "%d", temp_service->current_notification_number);
2108 			break;
2109 		case MACRO_SERVICENOTIFICATIONID:
2110 			asprintf(output, "%lu", temp_service->current_notification_id);
2111 			break;
2112 		case MACRO_SERVICEEVENTID:
2113 			asprintf(output, "%lu", temp_service->current_event_id);
2114 			break;
2115 		case MACRO_LASTSERVICEEVENTID:
2116 			asprintf(output, "%lu", temp_service->last_event_id);
2117 			break;
2118 		case MACRO_SERVICEPROBLEMID:
2119 			asprintf(output, "%lu", temp_service->current_problem_id);
2120 			break;
2121 		case MACRO_LASTSERVICEPROBLEMID:
2122 			asprintf(output, "%lu", temp_service->last_problem_id);
2123 			break;
2124 #endif
2125 		case MACRO_SERVICEACTIONURL:
2126 			if(temp_service->action_url)
2127 				*output = (char *)strdup(temp_service->action_url);
2128 			break;
2129 		case MACRO_SERVICENOTESURL:
2130 			if(temp_service->notes_url)
2131 				*output = (char *)strdup(temp_service->notes_url);
2132 			break;
2133 		case MACRO_SERVICENOTES:
2134 			if(temp_service->notes)
2135 				*output = (char *)strdup(temp_service->notes);
2136 			break;
2137 #ifdef NSCORE
2138 		case MACRO_SERVICEGROUPNAMES:
2139 			/* find all servicegroups this service is associated with */
2140 			for(temp_objectlist = temp_service->servicegroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) {
2141 
2142 				if((temp_servicegroup = (servicegroup *)temp_objectlist->object_ptr) == NULL)
2143 					continue;
2144 
2145 				asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_servicegroup->group_name);
2146 				my_free(buf2);
2147 				buf2 = buf1;
2148 				}
2149 			if(buf2) {
2150 				*output = (char *)strdup(buf2);
2151 				my_free(buf2);
2152 				}
2153 			break;
2154 #endif
2155 			/***************/
2156 			/* MISC MACROS */
2157 			/***************/
2158 		case MACRO_SERVICEACKAUTHOR:
2159 		case MACRO_SERVICEACKAUTHORNAME:
2160 		case MACRO_SERVICEACKAUTHORALIAS:
2161 		case MACRO_SERVICEACKCOMMENT:
2162 			/* no need to do any more work - these are already precomputed elsewhere */
2163 			/* NOTE: these macros won't work as on-demand macros */
2164 			*output = mac->x[macro_type];
2165 			*free_macro = FALSE;
2166 			break;
2167 
2168 		default:
2169 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED SERVICE MACRO #%d! THIS IS A BUG!\n", macro_type);
2170 			return ERROR;
2171 			break;
2172 		}
2173 
2174 	/* post-processing */
2175 	/* notes, notes URL and action URL macros may themselves contain macros, so process them... */
2176 	switch(macro_type) {
2177 		case MACRO_SERVICEACTIONURL:
2178 		case MACRO_SERVICENOTESURL:
2179 			process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS);
2180 			my_free(*output);
2181 			*output = temp_buffer;
2182 			break;
2183 		case MACRO_SERVICENOTES:
2184 			process_macros_r(mac, *output, &temp_buffer, 0);
2185 			my_free(*output);
2186 			*output = temp_buffer;
2187 			break;
2188 		default:
2189 			break;
2190 		}
2191 
2192 	return OK;
2193 	}
2194 
2195 int grab_standard_service_macro(int macro_type, service *temp_service, char **output, int *free_macro) {
2196 	return grab_standard_service_macro_r(&global_macros, macro_type, temp_service, output, free_macro);
2197 	}
2198 
2199 
2200 /* computes a servicegroup macro */
2201 int grab_standard_servicegroup_macro_r(nagios_macros *mac, int macro_type, servicegroup *temp_servicegroup, char **output) {
2202 	servicesmember *temp_servicesmember = NULL;
2203 	char *temp_buffer = NULL;
2204 	unsigned int	temp_len = 0;
2205 	unsigned int	init_len = 0;
2206 
2207 	if(temp_servicegroup == NULL || output == NULL)
2208 		return ERROR;
2209 
2210 	/* get the macro value */
2211 	switch(macro_type) {
2212 		case MACRO_SERVICEGROUPNAME:
2213 			*output = (char *)strdup(temp_servicegroup->group_name);
2214 			break;
2215 		case MACRO_SERVICEGROUPALIAS:
2216 			if(temp_servicegroup->alias)
2217 				*output = (char *)strdup(temp_servicegroup->alias);
2218 			break;
2219 		case MACRO_SERVICEGROUPMEMBERS:
2220 			/* make the calculations for total string length */
2221 			for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
2222 				if(temp_servicesmember->host_name == NULL || temp_servicesmember->service_description == NULL)
2223 					continue;
2224 				if(temp_len == 0) {
2225 					temp_len += strlen(temp_servicesmember->host_name) + strlen(temp_servicesmember->service_description) + 2;
2226 					}
2227 				else {
2228 					temp_len += strlen(temp_servicesmember->host_name) + strlen(temp_servicesmember->service_description) + 3;
2229 					}
2230 				}
2231 			/* allocate or reallocate the memory buffer */
2232 			if(*output == NULL) {
2233 				*output = (char *)malloc(temp_len);
2234 				}
2235 			else {
2236 				init_len = strlen(*output);
2237 				temp_len += init_len;
2238 				*output = (char *)realloc(*output, temp_len);
2239 				}
2240 			/* now fill in the string with the group members */
2241 			for(temp_servicesmember = temp_servicegroup->members; temp_servicesmember != NULL; temp_servicesmember = temp_servicesmember->next) {
2242 				if(temp_servicesmember->host_name == NULL || temp_servicesmember->service_description == NULL)
2243 					continue;
2244 				temp_buffer = *output + init_len;
2245 				if(init_len == 0) {  /* If our buffer didn't contain anything, we just need to write "%s,%s" */
2246 					init_len += sprintf(temp_buffer, "%s,%s", temp_servicesmember->host_name, temp_servicesmember->service_description);
2247 					}
2248 				else {   /* Now we need to write ",%s,%s" */
2249 					init_len += sprintf(temp_buffer, ",%s,%s", temp_servicesmember->host_name, temp_servicesmember->service_description);
2250 					}
2251 				}
2252 			break;
2253 		case MACRO_SERVICEGROUPACTIONURL:
2254 			if(temp_servicegroup->action_url)
2255 				*output = (char *)strdup(temp_servicegroup->action_url);
2256 			break;
2257 		case MACRO_SERVICEGROUPNOTESURL:
2258 			if(temp_servicegroup->notes_url)
2259 				*output = (char *)strdup(temp_servicegroup->notes_url);
2260 			break;
2261 		case MACRO_SERVICEGROUPNOTES:
2262 			if(temp_servicegroup->notes)
2263 				*output = (char *)strdup(temp_servicegroup->notes);
2264 			break;
2265 		default:
2266 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED SERVICEGROUP MACRO #%d! THIS IS A BUG!\n", macro_type);
2267 			return ERROR;
2268 		}
2269 
2270 	/* post-processing */
2271 	/* notes, notes URL and action URL macros may themselves contain macros, so process them... */
2272 	switch(macro_type) {
2273 		case MACRO_SERVICEGROUPACTIONURL:
2274 		case MACRO_SERVICEGROUPNOTESURL:
2275 			process_macros_r(mac, *output, &temp_buffer, URL_ENCODE_MACRO_CHARS);
2276 			my_free(*output);
2277 			*output = temp_buffer;
2278 			break;
2279 		case MACRO_SERVICEGROUPNOTES:
2280 			process_macros_r(mac, *output, &temp_buffer, 0);
2281 			my_free(*output);
2282 			*output = temp_buffer;
2283 			break;
2284 		default:
2285 			break;
2286 		}
2287 
2288 	return OK;
2289 	}
2290 
2291 int grab_standard_servicegroup_macro(int macro_type, servicegroup *temp_servicegroup, char **output) {
2292 	return grab_standard_servicegroup_macro_r(&global_macros, macro_type, temp_servicegroup, output);
2293 	}
2294 
2295 
2296 /* computes a contact macro */
2297 int grab_standard_contact_macro_r(nagios_macros *mac, int macro_type, contact *temp_contact, char **output) {
2298 #ifdef NSCORE
2299 	contactgroup *temp_contactgroup = NULL;
2300 	objectlist *temp_objectlist = NULL;
2301 	char *buf1 = NULL;
2302 	char *buf2 = NULL;
2303 #endif
2304 
2305 	if(temp_contact == NULL || output == NULL)
2306 		return ERROR;
2307 
2308 	/* get the macro value */
2309 	switch(macro_type) {
2310 		case MACRO_CONTACTNAME:
2311 			*output = (char *)strdup(temp_contact->name);
2312 			break;
2313 		case MACRO_CONTACTALIAS:
2314 			*output = (char *)strdup(temp_contact->alias);
2315 			break;
2316 		case MACRO_CONTACTEMAIL:
2317 			if(temp_contact->email)
2318 				*output = (char *)strdup(temp_contact->email);
2319 			break;
2320 		case MACRO_CONTACTPAGER:
2321 			if(temp_contact->pager)
2322 				*output = (char *)strdup(temp_contact->pager);
2323 			break;
2324 #ifdef NSCORE
2325 		case MACRO_CONTACTGROUPNAMES:
2326 			/* get the contactgroup names */
2327 			/* find all contactgroups this contact is a member of */
2328 			for(temp_objectlist = temp_contact->contactgroups_ptr; temp_objectlist != NULL; temp_objectlist = temp_objectlist->next) {
2329 
2330 				if((temp_contactgroup = (contactgroup *)temp_objectlist->object_ptr) == NULL)
2331 					continue;
2332 
2333 				asprintf(&buf1, "%s%s%s", (buf2) ? buf2 : "", (buf2) ? "," : "", temp_contactgroup->group_name);
2334 				my_free(buf2);
2335 				buf2 = buf1;
2336 				}
2337 			if(buf2) {
2338 				*output = (char *)strdup(buf2);
2339 				my_free(buf2);
2340 				}
2341 			break;
2342 #endif
2343 		default:
2344 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED CONTACT MACRO #%d! THIS IS A BUG!\n", macro_type);
2345 			return ERROR;
2346 		}
2347 
2348 	return OK;
2349 	}
2350 
2351 int grab_standard_contact_macro(int macro_type, contact *temp_contact, char **output) {
2352 	return grab_standard_contact_macro_r(&global_macros, macro_type, temp_contact, output);
2353 	}
2354 
2355 
2356 /* computes a contact address macro */
2357 int grab_contact_address_macro(int macro_num, contact *temp_contact, char **output) {
2358 	if(macro_num < 0 || macro_num >= MAX_CONTACT_ADDRESSES)
2359 		return ERROR;
2360 
2361 	if(temp_contact == NULL || output == NULL)
2362 		return ERROR;
2363 
2364 	/* get the macro */
2365 	if(temp_contact->address[macro_num])
2366 		*output = temp_contact->address[macro_num];
2367 
2368 	return OK;
2369 	}
2370 
2371 
2372 
2373 /* computes a contactgroup macro */
2374 int grab_standard_contactgroup_macro(int macro_type, contactgroup *temp_contactgroup, char **output) {
2375 	contactsmember *temp_contactsmember = NULL;
2376 
2377 	if(temp_contactgroup == NULL || output == NULL)
2378 		return ERROR;
2379 
2380 	/* get the macro value */
2381 	switch(macro_type) {
2382 		case MACRO_CONTACTGROUPNAME:
2383 			*output = (char *)strdup(temp_contactgroup->group_name);
2384 			break;
2385 		case MACRO_CONTACTGROUPALIAS:
2386 			if(temp_contactgroup->alias)
2387 				*output = (char *)strdup(temp_contactgroup->alias);
2388 			break;
2389 		case MACRO_CONTACTGROUPMEMBERS:
2390 			/* get the member list */
2391 			for(temp_contactsmember = temp_contactgroup->members; temp_contactsmember != NULL; temp_contactsmember = temp_contactsmember->next) {
2392 				if(temp_contactsmember->contact_name == NULL)
2393 					continue;
2394 				if(*output == NULL)
2395 					*output = (char *)strdup(temp_contactsmember->contact_name);
2396 				else if((*output = (char *)realloc(*output, strlen(*output) + strlen(temp_contactsmember->contact_name) + 2))) {
2397 					strcat(*output, ",");
2398 					strcat(*output, temp_contactsmember->contact_name);
2399 					}
2400 				}
2401 			break;
2402 		default:
2403 			log_debug_info(DEBUGL_MACROS, 0, "UNHANDLED CONTACTGROUP MACRO #%d! THIS IS A BUG!\n", macro_type);
2404 			return ERROR;
2405 		}
2406 
2407 	return OK;
2408 	}
2409 
2410 
2411 /* computes a custom object macro */
2412 int grab_custom_object_macro_r(nagios_macros *mac, char *macro_name, customvariablesmember *vars, char **output) {
2413 	customvariablesmember *temp_customvariablesmember = NULL;
2414 	int result = ERROR;
2415 
2416 	if(macro_name == NULL || vars == NULL || output == NULL)
2417 		return ERROR;
2418 
2419 	/* get the custom variable */
2420 	for(temp_customvariablesmember = vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
2421 
2422 		if(temp_customvariablesmember->variable_name == NULL)
2423 			continue;
2424 
2425 		if(!strcmp(macro_name, temp_customvariablesmember->variable_name)) {
2426 			if(temp_customvariablesmember->variable_value)
2427 				*output = (char *)strdup(temp_customvariablesmember->variable_value);
2428 			result = OK;
2429 			break;
2430 			}
2431 		}
2432 
2433 	return result;
2434 	}
2435 
2436 int grab_custom_object_macro(char *macro_name, customvariablesmember *vars, char **output) {
2437 	return grab_custom_object_macro_r(&global_macros, macro_name, vars, output);
2438 	}
2439 
2440 
2441 /******************************************************************/
2442 /********************* MACRO STRING FUNCTIONS *********************/
2443 /******************************************************************/
2444 
2445 /* cleans illegal characters in macros before output */
2446 char *clean_macro_chars(char *macro, int options) {
2447 	register int x = 0;
2448 	register int y = 0;
2449 	register int z = 0;
2450 	register int ch = 0;
2451 	register int len = 0;
2452 	register int illegal_char = 0;
2453 
2454 	if(macro == NULL)
2455 		return "";
2456 
2457 	len = (int)strlen(macro);
2458 
2459 	/* strip illegal characters out of macro */
2460 	if(options & STRIP_ILLEGAL_MACRO_CHARS) {
2461 
2462 		for(y = 0, x = 0; x < len; x++) {
2463 
2464 			/*ch=(int)macro[x];*/
2465 			/* allow non-ASCII characters (Japanese, etc) */
2466 			ch = macro[x] & 0xff;
2467 
2468 			/* illegal ASCII characters */
2469 			if(ch < 32 || ch == 127)
2470 				continue;
2471 
2472 			/* illegal user-specified characters */
2473 			illegal_char = FALSE;
2474 			if(illegal_output_chars != NULL) {
2475 				for(z = 0; illegal_output_chars[z] != '\x0'; z++) {
2476 					if(ch == (int)illegal_output_chars[z]) {
2477 						illegal_char = TRUE;
2478 						break;
2479 						}
2480 					}
2481 				}
2482 
2483 			if(illegal_char == FALSE)
2484 				macro[y++] = macro[x];
2485 			}
2486 
2487 		macro[y++] = '\x0';
2488 		}
2489 
2490 #ifdef ON_HOLD_FOR_NOW
2491 	/* escape nasty character in macro */
2492 	if(options & ESCAPE_MACRO_CHARS) {
2493 		}
2494 #endif
2495 
2496 	return macro;
2497 	}
2498 
2499 
2500 
2501 /* encodes a string in proper URL format */
2502 char *get_url_encoded_string(char *input) {
2503 	register int x = 0;
2504 	register int y = 0;
2505 	char *encoded_url_string = NULL;
2506 	char temp_expansion[6] = "";
2507 
2508 
2509 	/* bail if no input */
2510 	if(input == NULL)
2511 		return NULL;
2512 
2513 	/* allocate enough memory to escape all characters if necessary */
2514 	if((encoded_url_string = (char *)malloc((strlen(input) * 3) + 1)) == NULL)
2515 		return NULL;
2516 
2517 	/* check/encode all characters */
2518 	for(x = 0, y = 0; input[x] != (char)'\x0'; x++) {
2519 
2520 		/* alpha-numeric characters and a few other characters don't get encoded */
2521 		if(((char)input[x] >= '0' && (char)input[x] <= '9') || ((char)input[x] >= 'A' && (char)input[x] <= 'Z') || ((char)input[x] >= (char)'a' && (char)input[x] <= (char)'z') || (char)input[x] == (char)'.' || (char)input[x] == (char)'-' || (char)input[x] == (char)'_' || (char)input[x] == (char)':' || (char)input[x] == (char)'/' || (char)input[x] == (char)'?' || (char)input[x] == (char)'=' || (char)input[x] == (char)'&') {
2522 			encoded_url_string[y] = input[x];
2523 			y++;
2524 			}
2525 
2526 		/* spaces are pluses */
2527 		else if((char)input[x] <= (char)' ') {
2528 			encoded_url_string[y] = '+';
2529 			y++;
2530 			}
2531 
2532 		/* anything else gets represented by its hex value */
2533 		else {
2534 			encoded_url_string[y] = '\x0';
2535 			sprintf(temp_expansion, "%%%02X", (unsigned int)(input[x] & 0xFF));
2536 			strcat(encoded_url_string, temp_expansion);
2537 			y += 3;
2538 			}
2539 		}
2540 
2541 	/* terminate encoded string */
2542 	encoded_url_string[y] = '\x0';
2543 
2544 	return encoded_url_string;
2545 	}
2546 
2547 
2548 static int macro_key_cmp(const void *a_, const void *b_) {
2549 	struct macro_key_code *a = (struct macro_key_code *)a_;
2550 	struct macro_key_code *b = (struct macro_key_code *)b_;
2551 
2552 	return strcmp(a->name, b->name);
2553 	}
2554 
2555 
2556 /******************************************************************/
2557 /***************** MACRO INITIALIZATION FUNCTIONS *****************/
2558 /******************************************************************/
2559 
2560 /* initializes global macros */
2561 int init_macros(void) {
2562 	init_macrox_names();
2563 	int x;
2564 
2565 	/*
2566 	 * non-volatile macros are free()'d when they're set.
2567 	 * We must do this in order to not lose the constant
2568 	 * ones when we get SIGHUP or a RESTART_PROGRAM event
2569 	 * from the command fifo. Otherwise a memset() would
2570 	 * have been better.
2571 	 */
2572 	clear_volatile_macros_r(&global_macros);
2573 
2574 	/* backwards compatibility hack */
2575 	macro_x = global_macros.x;
2576 
2577 	/*
2578 	 * Now build an ordered list of X macro names so we can
2579 	 * do binary lookups later and avoid a ton of strcmp()'s
2580 	 * for each and every check that gets run. A hash table
2581 	 * is actually slower, since the most frequently used
2582 	 * keys are so long and a binary lookup is completed in
2583 	 * 7 steps for up to ~200 keys, worst case.
2584 	 */
2585 	for(x = 0; x < MACRO_X_COUNT; x++) {
2586 		macro_keys[x].code = x;
2587 		macro_keys[x].name = macro_x_names[x];
2588 		macro_keys[x].clean_options = 0;
2589 
2590 		/* host/service output/perfdata and author/comment macros should get cleaned */
2591 		if((x >= 16 && x <= 19) || (x >= 49 && x <= 52) || (x >= 99 && x <= 100) || (x >= 124 && x <= 127)) {
2592 			macro_keys[x].clean_options = (STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS);
2593 			}
2594 		/* url macros should get cleaned */
2595 		if((x >= 125 && x <= 126) || (x >= 128 && x <= 129) || (x >= 77 && x <= 78) || (x >= 74 && x <= 75)) {
2596 			macro_keys[x].clean_options = URL_ENCODE_MACRO_CHARS;
2597 			}
2598 		}
2599 
2600 	qsort(macro_keys, x, sizeof(struct macro_key_code), macro_key_cmp);
2601 	return OK;
2602 	}
2603 
2604 /*
2605  * initializes the names of macros, using this nifty little macro
2606  * which ensures we never add any typos to the list
2607  */
2608 #define add_macrox_name(name) macro_x_names[MACRO_##name] = strdup(#name)
2609 int init_macrox_names(void) {
2610 	register int x = 0;
2611 
2612 	/* initialize macro names */
2613 	for(x = 0; x < MACRO_X_COUNT; x++)
2614 		macro_x_names[x] = NULL;
2615 
2616 	/* initialize each macro name */
2617 	add_macrox_name(HOSTNAME);
2618 	add_macrox_name(HOSTALIAS);
2619 	add_macrox_name(HOSTADDRESS);
2620 	add_macrox_name(SERVICEDESC);
2621 	add_macrox_name(SERVICESTATE);
2622 	add_macrox_name(SERVICESTATEID);
2623 	add_macrox_name(SERVICEATTEMPT);
2624 	add_macrox_name(SERVICEISVOLATILE);
2625 	add_macrox_name(LONGDATETIME);
2626 	add_macrox_name(SHORTDATETIME);
2627 	add_macrox_name(DATE);
2628 	add_macrox_name(TIME);
2629 	add_macrox_name(TIMET);
2630 	add_macrox_name(LASTHOSTCHECK);
2631 	add_macrox_name(LASTSERVICECHECK);
2632 	add_macrox_name(LASTHOSTSTATECHANGE);
2633 	add_macrox_name(LASTSERVICESTATECHANGE);
2634 	add_macrox_name(HOSTOUTPUT);
2635 	add_macrox_name(SERVICEOUTPUT);
2636 	add_macrox_name(HOSTPERFDATA);
2637 	add_macrox_name(SERVICEPERFDATA);
2638 	add_macrox_name(CONTACTNAME);
2639 	add_macrox_name(CONTACTALIAS);
2640 	add_macrox_name(CONTACTEMAIL);
2641 	add_macrox_name(CONTACTPAGER);
2642 	add_macrox_name(ADMINEMAIL);
2643 	add_macrox_name(ADMINPAGER);
2644 	add_macrox_name(HOSTSTATE);
2645 	add_macrox_name(HOSTSTATEID);
2646 	add_macrox_name(HOSTATTEMPT);
2647 	add_macrox_name(NOTIFICATIONTYPE);
2648 	add_macrox_name(NOTIFICATIONNUMBER);
2649 	add_macrox_name(NOTIFICATIONISESCALATED);
2650 	add_macrox_name(HOSTEXECUTIONTIME);
2651 	add_macrox_name(SERVICEEXECUTIONTIME);
2652 	add_macrox_name(HOSTLATENCY);
2653 	add_macrox_name(SERVICELATENCY);
2654 	add_macrox_name(HOSTDURATION);
2655 	add_macrox_name(SERVICEDURATION);
2656 	add_macrox_name(HOSTDURATIONSEC);
2657 	add_macrox_name(SERVICEDURATIONSEC);
2658 	add_macrox_name(HOSTDOWNTIME);
2659 	add_macrox_name(SERVICEDOWNTIME);
2660 	add_macrox_name(HOSTSTATETYPE);
2661 	add_macrox_name(SERVICESTATETYPE);
2662 	add_macrox_name(HOSTPERCENTCHANGE);
2663 	add_macrox_name(SERVICEPERCENTCHANGE);
2664 	add_macrox_name(HOSTGROUPNAME);
2665 	add_macrox_name(HOSTGROUPALIAS);
2666 	add_macrox_name(SERVICEGROUPNAME);
2667 	add_macrox_name(SERVICEGROUPALIAS);
2668 	add_macrox_name(HOSTACKAUTHOR);
2669 	add_macrox_name(HOSTACKCOMMENT);
2670 	add_macrox_name(SERVICEACKAUTHOR);
2671 	add_macrox_name(SERVICEACKCOMMENT);
2672 	add_macrox_name(LASTSERVICEOK);
2673 	add_macrox_name(LASTSERVICEWARNING);
2674 	add_macrox_name(LASTSERVICEUNKNOWN);
2675 	add_macrox_name(LASTSERVICECRITICAL);
2676 	add_macrox_name(LASTHOSTUP);
2677 	add_macrox_name(LASTHOSTDOWN);
2678 	add_macrox_name(LASTHOSTUNREACHABLE);
2679 	add_macrox_name(SERVICECHECKCOMMAND);
2680 	add_macrox_name(HOSTCHECKCOMMAND);
2681 	add_macrox_name(MAINCONFIGFILE);
2682 	add_macrox_name(STATUSDATAFILE);
2683 	add_macrox_name(HOSTDISPLAYNAME);
2684 	add_macrox_name(SERVICEDISPLAYNAME);
2685 	add_macrox_name(RETENTIONDATAFILE);
2686 	add_macrox_name(OBJECTCACHEFILE);
2687 	add_macrox_name(TEMPFILE);
2688 	add_macrox_name(LOGFILE);
2689 	add_macrox_name(RESOURCEFILE);
2690 	add_macrox_name(COMMANDFILE);
2691 	add_macrox_name(HOSTPERFDATAFILE);
2692 	add_macrox_name(SERVICEPERFDATAFILE);
2693 	add_macrox_name(HOSTACTIONURL);
2694 	add_macrox_name(HOSTNOTESURL);
2695 	add_macrox_name(HOSTNOTES);
2696 	add_macrox_name(SERVICEACTIONURL);
2697 	add_macrox_name(SERVICENOTESURL);
2698 	add_macrox_name(SERVICENOTES);
2699 	add_macrox_name(TOTALHOSTSUP);
2700 	add_macrox_name(TOTALHOSTSDOWN);
2701 	add_macrox_name(TOTALHOSTSUNREACHABLE);
2702 	add_macrox_name(TOTALHOSTSDOWNUNHANDLED);
2703 	add_macrox_name(TOTALHOSTSUNREACHABLEUNHANDLED);
2704 	add_macrox_name(TOTALHOSTPROBLEMS);
2705 	add_macrox_name(TOTALHOSTPROBLEMSUNHANDLED);
2706 	add_macrox_name(TOTALSERVICESOK);
2707 	add_macrox_name(TOTALSERVICESWARNING);
2708 	add_macrox_name(TOTALSERVICESCRITICAL);
2709 	add_macrox_name(TOTALSERVICESUNKNOWN);
2710 	add_macrox_name(TOTALSERVICESWARNINGUNHANDLED);
2711 	add_macrox_name(TOTALSERVICESCRITICALUNHANDLED);
2712 	add_macrox_name(TOTALSERVICESUNKNOWNUNHANDLED);
2713 	add_macrox_name(TOTALSERVICEPROBLEMS);
2714 	add_macrox_name(TOTALSERVICEPROBLEMSUNHANDLED);
2715 	add_macrox_name(PROCESSSTARTTIME);
2716 	add_macrox_name(HOSTCHECKTYPE);
2717 	add_macrox_name(SERVICECHECKTYPE);
2718 	add_macrox_name(LONGHOSTOUTPUT);
2719 	add_macrox_name(LONGSERVICEOUTPUT);
2720 	add_macrox_name(TEMPPATH);
2721 	add_macrox_name(HOSTNOTIFICATIONNUMBER);
2722 	add_macrox_name(SERVICENOTIFICATIONNUMBER);
2723 	add_macrox_name(HOSTNOTIFICATIONID);
2724 	add_macrox_name(SERVICENOTIFICATIONID);
2725 	add_macrox_name(HOSTEVENTID);
2726 	add_macrox_name(LASTHOSTEVENTID);
2727 	add_macrox_name(SERVICEEVENTID);
2728 	add_macrox_name(LASTSERVICEEVENTID);
2729 	add_macrox_name(HOSTGROUPNAMES);
2730 	add_macrox_name(SERVICEGROUPNAMES);
2731 	add_macrox_name(HOSTACKAUTHORNAME);
2732 	add_macrox_name(HOSTACKAUTHORALIAS);
2733 	add_macrox_name(SERVICEACKAUTHORNAME);
2734 	add_macrox_name(SERVICEACKAUTHORALIAS);
2735 	add_macrox_name(MAXHOSTATTEMPTS);
2736 	add_macrox_name(MAXSERVICEATTEMPTS);
2737 	add_macrox_name(TOTALHOSTSERVICES);
2738 	add_macrox_name(TOTALHOSTSERVICESOK);
2739 	add_macrox_name(TOTALHOSTSERVICESWARNING);
2740 	add_macrox_name(TOTALHOSTSERVICESUNKNOWN);
2741 	add_macrox_name(TOTALHOSTSERVICESCRITICAL);
2742 	add_macrox_name(HOSTGROUPNOTES);
2743 	add_macrox_name(HOSTGROUPNOTESURL);
2744 	add_macrox_name(HOSTGROUPACTIONURL);
2745 	add_macrox_name(SERVICEGROUPNOTES);
2746 	add_macrox_name(SERVICEGROUPNOTESURL);
2747 	add_macrox_name(SERVICEGROUPACTIONURL);
2748 	add_macrox_name(HOSTGROUPMEMBERS);
2749 	add_macrox_name(SERVICEGROUPMEMBERS);
2750 	add_macrox_name(CONTACTGROUPNAME);
2751 	add_macrox_name(CONTACTGROUPALIAS);
2752 	add_macrox_name(CONTACTGROUPMEMBERS);
2753 	add_macrox_name(CONTACTGROUPNAMES);
2754 	add_macrox_name(NOTIFICATIONRECIPIENTS);
2755 	add_macrox_name(NOTIFICATIONAUTHOR);
2756 	add_macrox_name(NOTIFICATIONAUTHORNAME);
2757 	add_macrox_name(NOTIFICATIONAUTHORALIAS);
2758 	add_macrox_name(NOTIFICATIONCOMMENT);
2759 	add_macrox_name(EVENTSTARTTIME);
2760 	add_macrox_name(HOSTPROBLEMID);
2761 	add_macrox_name(LASTHOSTPROBLEMID);
2762 	add_macrox_name(SERVICEPROBLEMID);
2763 	add_macrox_name(LASTSERVICEPROBLEMID);
2764 	add_macrox_name(ISVALIDTIME);
2765 	add_macrox_name(NEXTVALIDTIME);
2766 	add_macrox_name(LASTHOSTSTATE);
2767 	add_macrox_name(LASTHOSTSTATEID);
2768 	add_macrox_name(LASTSERVICESTATE);
2769 	add_macrox_name(LASTSERVICESTATEID);
2770 
2771 	return OK;
2772 	}
2773 
2774 
2775 /******************************************************************/
2776 /********************* MACRO CLEANUP FUNCTIONS ********************/
2777 /******************************************************************/
2778 
2779 /* free memory associated with the macrox names */
2780 int free_macrox_names(void) {
2781 	register int x = 0;
2782 
2783 	/* free each macro name */
2784 	for(x = 0; x < MACRO_X_COUNT; x++)
2785 		my_free(macro_x_names[x]);
2786 
2787 	return OK;
2788 	}
2789 
2790 
2791 
2792 /* clear argv macros - used in commands */
2793 int clear_argv_macros_r(nagios_macros *mac) {
2794 	register int x = 0;
2795 
2796 	/* command argument macros */
2797 	for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++)
2798 		my_free(mac->argv[x]);
2799 
2800 	return OK;
2801 	}
2802 
2803 int clear_argv_macros(void) {
2804 	return clear_argv_macros_r(&global_macros);
2805 	}
2806 
2807 /*
2808  * copies non-volatile macros from global macro_x to **dest, which
2809  * must be large enough to hold at least MACRO_X_COUNT entries.
2810  * We use a shortlived macro to save up on typing
2811  */
2812 #define cp_macro(name) dest[MACRO_##name] = global_macros.x[MACRO_##name]
2813 void copy_constant_macros(char **dest) {
2814 	cp_macro(ADMINEMAIL);
2815 	cp_macro(ADMINPAGER);
2816 	cp_macro(MAINCONFIGFILE);
2817 	cp_macro(STATUSDATAFILE);
2818 	cp_macro(RETENTIONDATAFILE);
2819 	cp_macro(OBJECTCACHEFILE);
2820 	cp_macro(TEMPFILE);
2821 	cp_macro(LOGFILE);
2822 	cp_macro(RESOURCEFILE);
2823 	cp_macro(COMMANDFILE);
2824 	cp_macro(HOSTPERFDATAFILE);
2825 	cp_macro(SERVICEPERFDATAFILE);
2826 	cp_macro(PROCESSSTARTTIME);
2827 	cp_macro(TEMPPATH);
2828 	cp_macro(EVENTSTARTTIME);
2829 	}
2830 #undef cp_macro
2831 
2832 /* clear all macros that are not "constant" (i.e. they change throughout the course of monitoring) */
2833 int clear_volatile_macros_r(nagios_macros *mac) {
2834 	customvariablesmember *this_customvariablesmember = NULL;
2835 	customvariablesmember *next_customvariablesmember = NULL;
2836 	register int x = 0;
2837 
2838 	for(x = 0; x < MACRO_X_COUNT; x++) {
2839 		switch(x) {
2840 
2841 			case MACRO_ADMINEMAIL:
2842 			case MACRO_ADMINPAGER:
2843 			case MACRO_MAINCONFIGFILE:
2844 			case MACRO_STATUSDATAFILE:
2845 			case MACRO_RETENTIONDATAFILE:
2846 			case MACRO_OBJECTCACHEFILE:
2847 			case MACRO_TEMPFILE:
2848 			case MACRO_LOGFILE:
2849 			case MACRO_RESOURCEFILE:
2850 			case MACRO_COMMANDFILE:
2851 			case MACRO_HOSTPERFDATAFILE:
2852 			case MACRO_SERVICEPERFDATAFILE:
2853 			case MACRO_PROCESSSTARTTIME:
2854 			case MACRO_TEMPPATH:
2855 			case MACRO_EVENTSTARTTIME:
2856 				/* these don't change during the course of monitoring, so no need to free them */
2857 				break;
2858 			default:
2859 				my_free(mac->x[x]);
2860 				break;
2861 			}
2862 		}
2863 
2864 	/* contact address macros */
2865 	for(x = 0; x < MAX_CONTACT_ADDRESSES; x++)
2866 		my_free(mac->contactaddress[x]);
2867 
2868 	/* clear macro pointers */
2869 	mac->host_ptr = NULL;
2870 	mac->hostgroup_ptr = NULL;
2871 	mac->service_ptr = NULL;
2872 	mac->servicegroup_ptr = NULL;
2873 	mac->contact_ptr = NULL;
2874 	mac->contactgroup_ptr = NULL;
2875 
2876 	/* clear on-demand macro */
2877 	my_free(mac->ondemand);
2878 
2879 	/* clear ARGx macros */
2880 	clear_argv_macros_r(mac);
2881 
2882 	/* clear custom host variables */
2883 	for(this_customvariablesmember = mac->custom_host_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
2884 		next_customvariablesmember = this_customvariablesmember->next;
2885 		my_free(this_customvariablesmember->variable_name);
2886 		my_free(this_customvariablesmember->variable_value);
2887 		my_free(this_customvariablesmember);
2888 		}
2889 	mac->custom_host_vars = NULL;
2890 
2891 	/* clear custom service variables */
2892 	for(this_customvariablesmember = mac->custom_service_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
2893 		next_customvariablesmember = this_customvariablesmember->next;
2894 		my_free(this_customvariablesmember->variable_name);
2895 		my_free(this_customvariablesmember->variable_value);
2896 		my_free(this_customvariablesmember);
2897 		}
2898 	mac->custom_service_vars = NULL;
2899 
2900 	/* clear custom contact variables */
2901 	for(this_customvariablesmember = mac->custom_contact_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
2902 		next_customvariablesmember = this_customvariablesmember->next;
2903 		my_free(this_customvariablesmember->variable_name);
2904 		my_free(this_customvariablesmember->variable_value);
2905 		my_free(this_customvariablesmember);
2906 		}
2907 	mac->custom_contact_vars = NULL;
2908 
2909 	return OK;
2910 	}
2911 
2912 
2913 int clear_volatile_macros(void) {
2914 	return clear_volatile_macros_r(&global_macros);
2915 	}
2916 
2917 
2918 /* clear service macros */
2919 int clear_service_macros_r(nagios_macros *mac) {
2920 	customvariablesmember *this_customvariablesmember = NULL;
2921 	customvariablesmember *next_customvariablesmember = NULL;
2922 
2923 	/* FIXME: strings. make these not be strdup()'s anymore */
2924 	my_free(mac->x[MACRO_SERVICEDESC]);
2925 	my_free(mac->x[MACRO_SERVICEDISPLAYNAME]);
2926 	my_free(mac->x[MACRO_SERVICEOUTPUT]);
2927 	my_free(mac->x[MACRO_LONGSERVICEOUTPUT]);
2928 	my_free(mac->x[MACRO_SERVICEPERFDATA]);
2929 
2930 	/* these are recursive but persistent. what to do? */
2931 	my_free(mac->x[MACRO_SERVICECHECKCOMMAND]);
2932 	my_free(mac->x[MACRO_SERVICEACTIONURL]);
2933 	my_free(mac->x[MACRO_SERVICENOTESURL]);
2934 	my_free(mac->x[MACRO_SERVICENOTES]);
2935 
2936 	my_free(mac->x[MACRO_SERVICECHECKTYPE]);
2937 	my_free(mac->x[MACRO_SERVICESTATETYPE]);
2938 	my_free(mac->x[MACRO_SERVICESTATE]);
2939 	my_free(mac->x[MACRO_SERVICEISVOLATILE]);
2940 	my_free(mac->x[MACRO_SERVICESTATEID]);
2941 	my_free(mac->x[MACRO_SERVICEATTEMPT]);
2942 	my_free(mac->x[MACRO_MAXSERVICEATTEMPTS]);
2943 	my_free(mac->x[MACRO_SERVICEEXECUTIONTIME]);
2944 	my_free(mac->x[MACRO_SERVICELATENCY]);
2945 	my_free(mac->x[MACRO_LASTSERVICECHECK]);
2946 	my_free(mac->x[MACRO_LASTSERVICESTATECHANGE]);
2947 	my_free(mac->x[MACRO_LASTSERVICEOK]);
2948 	my_free(mac->x[MACRO_LASTSERVICEWARNING]);
2949 	my_free(mac->x[MACRO_LASTSERVICEUNKNOWN]);
2950 	my_free(mac->x[MACRO_LASTSERVICECRITICAL]);
2951 	my_free(mac->x[MACRO_SERVICEDOWNTIME]);
2952 	my_free(mac->x[MACRO_SERVICEPERCENTCHANGE]);
2953 	my_free(mac->x[MACRO_SERVICEDURATIONSEC]);
2954 	my_free(mac->x[MACRO_SERVICEDURATION]);
2955 	my_free(mac->x[MACRO_SERVICENOTIFICATIONNUMBER]);
2956 	my_free(mac->x[MACRO_SERVICENOTIFICATIONID]);
2957 	my_free(mac->x[MACRO_SERVICEEVENTID]);
2958 	my_free(mac->x[MACRO_LASTSERVICEEVENTID]);
2959 	my_free(mac->x[MACRO_SERVICEGROUPNAMES]);
2960 	my_free(mac->x[MACRO_SERVICEPROBLEMID]);
2961 	my_free(mac->x[MACRO_LASTSERVICEPROBLEMID]);
2962 
2963 	/* clear custom service variables */
2964 	for(this_customvariablesmember = mac->custom_service_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
2965 		next_customvariablesmember = this_customvariablesmember->next;
2966 		my_free(this_customvariablesmember->variable_name);
2967 		my_free(this_customvariablesmember->variable_value);
2968 		my_free(this_customvariablesmember);
2969 		}
2970 	mac->custom_service_vars = NULL;
2971 
2972 	/* clear pointers */
2973 	mac->service_ptr = NULL;
2974 
2975 	return OK;
2976 	}
2977 
2978 int clear_service_macros(void) {
2979 	return clear_service_macros_r(&global_macros);
2980 	}
2981 
2982 /* clear host macros */
2983 int clear_host_macros_r(nagios_macros *mac) {
2984 	customvariablesmember *this_customvariablesmember = NULL;
2985 	customvariablesmember *next_customvariablesmember = NULL;
2986 
2987 	/* FIXME: strings; Fix these to not be strdup()'s anymore */
2988 	my_free(mac->x[MACRO_HOSTNAME]);
2989 	my_free(mac->x[MACRO_HOSTDISPLAYNAME]);
2990 	my_free(mac->x[MACRO_HOSTALIAS]);
2991 	my_free(mac->x[MACRO_HOSTADDRESS]);
2992 	my_free(mac->x[MACRO_HOSTOUTPUT]);
2993 	my_free(mac->x[MACRO_LONGHOSTOUTPUT]);
2994 	my_free(mac->x[MACRO_HOSTPERFDATA]);
2995 
2996 	/* these are recursive but persistent. what to do? */
2997 	my_free(mac->x[MACRO_HOSTCHECKCOMMAND]);
2998 	my_free(mac->x[MACRO_HOSTACTIONURL]);
2999 	my_free(mac->x[MACRO_HOSTNOTESURL]);
3000 	my_free(mac->x[MACRO_HOSTNOTES]);
3001 
3002 	/* numbers or by necessity autogenerated strings */
3003 	my_free(mac->x[MACRO_HOSTSTATE]);
3004 	my_free(mac->x[MACRO_HOSTSTATEID]);
3005 	my_free(mac->x[MACRO_HOSTCHECKTYPE]);
3006 	my_free(mac->x[MACRO_HOSTSTATETYPE]);
3007 	my_free(mac->x[MACRO_HOSTATTEMPT]);
3008 	my_free(mac->x[MACRO_MAXHOSTATTEMPTS]);
3009 	my_free(mac->x[MACRO_HOSTDOWNTIME]);
3010 	my_free(mac->x[MACRO_HOSTPERCENTCHANGE]);
3011 	my_free(mac->x[MACRO_HOSTDURATIONSEC]);
3012 	my_free(mac->x[MACRO_HOSTDURATION]);
3013 	my_free(mac->x[MACRO_HOSTEXECUTIONTIME]);
3014 	my_free(mac->x[MACRO_HOSTLATENCY]);
3015 	my_free(mac->x[MACRO_LASTHOSTCHECK]);
3016 	my_free(mac->x[MACRO_LASTHOSTSTATECHANGE]);
3017 	my_free(mac->x[MACRO_LASTHOSTUP]);
3018 	my_free(mac->x[MACRO_LASTHOSTDOWN]);
3019 	my_free(mac->x[MACRO_LASTHOSTUNREACHABLE]);
3020 	my_free(mac->x[MACRO_HOSTNOTIFICATIONNUMBER]);
3021 	my_free(mac->x[MACRO_HOSTNOTIFICATIONID]);
3022 	my_free(mac->x[MACRO_HOSTEVENTID]);
3023 	my_free(mac->x[MACRO_LASTHOSTEVENTID]);
3024 	my_free(mac->x[MACRO_HOSTGROUPNAMES]);
3025 	my_free(mac->x[MACRO_TOTALHOSTSERVICES]);
3026 	my_free(mac->x[MACRO_TOTALHOSTSERVICESOK]);
3027 	my_free(mac->x[MACRO_TOTALHOSTSERVICESWARNING]);
3028 	my_free(mac->x[MACRO_TOTALHOSTSERVICESUNKNOWN]);
3029 	my_free(mac->x[MACRO_TOTALHOSTSERVICESCRITICAL]);
3030 	my_free(mac->x[MACRO_HOSTPROBLEMID]);
3031 	my_free(mac->x[MACRO_LASTHOSTPROBLEMID]);
3032 
3033 
3034 	/* clear custom host variables */
3035 	for(this_customvariablesmember = mac->custom_host_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
3036 		next_customvariablesmember = this_customvariablesmember->next;
3037 		my_free(this_customvariablesmember->variable_name);
3038 		my_free(this_customvariablesmember->variable_value);
3039 		my_free(this_customvariablesmember);
3040 		}
3041 	mac->custom_host_vars = NULL;
3042 
3043 	/* clear pointers */
3044 	mac->host_ptr = NULL;
3045 
3046 	return OK;
3047 	}
3048 
3049 int clear_host_macros(void) {
3050 	return clear_host_macros_r(&global_macros);
3051 	}
3052 
3053 
3054 /* clear hostgroup macros */
3055 int clear_hostgroup_macros_r(nagios_macros *mac) {
3056 	/* FIXME: make these not strdup()'s */
3057 	my_free(mac->x[MACRO_HOSTGROUPNAME]);
3058 	my_free(mac->x[MACRO_HOSTGROUPALIAS]);
3059 
3060 	/* generated but persistent. what to do? */
3061 	my_free(mac->x[MACRO_HOSTGROUPACTIONURL]);
3062 	my_free(mac->x[MACRO_HOSTGROUPNOTESURL]);
3063 	my_free(mac->x[MACRO_HOSTGROUPNOTES]);
3064 
3065 	/* generated */
3066 	my_free(mac->x[MACRO_HOSTGROUPMEMBERS]);
3067 
3068 	/* clear pointers */
3069 	mac->hostgroup_ptr = NULL;
3070 
3071 	return OK;
3072 	}
3073 
3074 int clear_hostgroup_macros(void) {
3075 	return clear_hostgroup_macros_r(&global_macros);
3076 	}
3077 
3078 
3079 /* clear servicegroup macros */
3080 int clear_servicegroup_macros_r(nagios_macros *mac) {
3081 	/* FIXME: these should not be strdup()'s */
3082 	my_free(mac->x[MACRO_SERVICEGROUPNAME]);
3083 	my_free(mac->x[MACRO_SERVICEGROUPALIAS]);
3084 
3085 	/* generated but persistent. what to do? */
3086 	my_free(mac->x[MACRO_SERVICEGROUPACTIONURL]);
3087 	my_free(mac->x[MACRO_SERVICEGROUPNOTESURL]);
3088 	my_free(mac->x[MACRO_SERVICEGROUPNOTES]);
3089 
3090 	/* generated */
3091 	my_free(mac->x[MACRO_SERVICEGROUPMEMBERS]);
3092 
3093 	/* clear pointers */
3094 	mac->servicegroup_ptr = NULL;
3095 
3096 	return OK;
3097 	}
3098 
3099 int clear_servicegroup_macros(void) {
3100 	return clear_servicegroup_macros_r(&global_macros);
3101 	}
3102 
3103 
3104 /* clear contact macros */
3105 int clear_contact_macros_r(nagios_macros *mac) {
3106 	register int x;
3107 	customvariablesmember *this_customvariablesmember = NULL;
3108 	customvariablesmember *next_customvariablesmember = NULL;
3109 
3110 	/* FIXME: these should not be strdup()'d */
3111 	my_free(mac->x[MACRO_CONTACTNAME]);
3112 	my_free(mac->x[MACRO_CONTACTALIAS]);
3113 	my_free(mac->x[MACRO_CONTACTEMAIL]);
3114 	my_free(mac->x[MACRO_CONTACTPAGER]);
3115 
3116 	/* generated per contact */
3117 	my_free(mac->x[MACRO_CONTACTGROUPNAMES]);
3118 
3119 	/* clear contact addresses */
3120 	for(x = 0; x < MAX_CONTACT_ADDRESSES; x++)
3121 		my_free(mac->contactaddress[x]);
3122 
3123 	/* clear custom contact variables */
3124 	for(this_customvariablesmember = mac->custom_contact_vars; this_customvariablesmember != NULL; this_customvariablesmember = next_customvariablesmember) {
3125 		next_customvariablesmember = this_customvariablesmember->next;
3126 		my_free(this_customvariablesmember->variable_name);
3127 		my_free(this_customvariablesmember->variable_value);
3128 		my_free(this_customvariablesmember);
3129 		}
3130 	mac->custom_contact_vars = NULL;
3131 
3132 	/* clear pointers */
3133 	mac->contact_ptr = NULL;
3134 
3135 	return OK;
3136 	}
3137 
3138 int clear_contact_macros(void) {
3139 	return clear_contact_macros_r(&global_macros);
3140 	}
3141 
3142 
3143 /* clear contactgroup macros */
3144 int clear_contactgroup_macros_r(nagios_macros *mac) {
3145 	my_free(mac->x[MACRO_CONTACTGROUPNAME]);
3146 	my_free(mac->x[MACRO_CONTACTGROUPALIAS]);
3147 	my_free(mac->x[MACRO_CONTACTGROUPMEMBERS]);
3148 
3149 	/* clear pointers */
3150 	mac->contactgroup_ptr = NULL;
3151 
3152 	return OK;
3153 	}
3154 
3155 int clear_contactgroup_macros(void) {
3156 	return clear_contactgroup_macros_r(&global_macros);
3157 	}
3158 
3159 
3160 /* clear summary macros */
3161 int clear_summary_macros_r(nagios_macros *mac) {
3162 	register int x;
3163 
3164 	for(x = MACRO_TOTALHOSTSUP; x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED; x++)
3165 		my_free(mac->x[x]);
3166 
3167 	return OK;
3168 	}
3169 
3170 int clear_summary_macros(void) {
3171 	return clear_summary_macros_r(&global_macros);
3172 	}
3173 
3174 
3175 /******************************************************************/
3176 /****************** ENVIRONMENT MACRO FUNCTIONS *******************/
3177 /******************************************************************/
3178 
3179 #ifdef NSCORE
3180 
3181 /* sets or unsets all macro environment variables */
3182 int set_all_macro_environment_vars_r(nagios_macros *mac, int set) {
3183 	if(enable_environment_macros == FALSE)
3184 		return ERROR;
3185 
3186 	set_macrox_environment_vars_r(mac, set);
3187 	set_argv_macro_environment_vars_r(mac, set);
3188 	set_custom_macro_environment_vars_r(mac, set);
3189 	set_contact_address_environment_vars_r(mac, set);
3190 
3191 	return OK;
3192 	}
3193 
3194 int set_all_macro_environment_vars(int set) {
3195 	return set_all_macro_environment_vars_r(&global_macros, set);
3196 	}
3197 
3198 
3199 /* sets or unsets macrox environment variables */
3200 int set_macrox_environment_vars_r(nagios_macros *mac, int set) {
3201 	register int x = 0;
3202 	int free_macro = FALSE;
3203 	int generate_macro = TRUE;
3204 
3205 	/* set each of the macrox environment variables */
3206 	for(x = 0; x < MACRO_X_COUNT; x++) {
3207 
3208 		free_macro = FALSE;
3209 
3210 		/* generate the macro value if it hasn't already been done */
3211 		/* THIS IS EXPENSIVE */
3212 		if(set == TRUE) {
3213 
3214 			generate_macro = TRUE;
3215 
3216 			/* skip summary macro generation if lage installation tweaks are enabled */
3217 			if((x >= MACRO_TOTALHOSTSUP && x <= MACRO_TOTALSERVICEPROBLEMSUNHANDLED) && use_large_installation_tweaks == TRUE)
3218 				generate_macro = FALSE;
3219 
3220 			if(mac->x[x] == NULL && generate_macro == TRUE)
3221 				grab_macrox_value_r(mac, x, NULL, NULL, &mac->x[x], &free_macro);
3222 			}
3223 
3224 		/* set the value */
3225 		set_macro_environment_var(macro_x_names[x], mac->x[x], set);
3226 		}
3227 
3228 	return OK;
3229 	}
3230 
3231 int set_macrox_environment_vars(int set) {
3232 	return set_macrox_environment_vars_r(&global_macros, set);
3233 	}
3234 
3235 
3236 /* sets or unsets argv macro environment variables */
3237 int set_argv_macro_environment_vars_r(nagios_macros *mac, int set) {
3238 	char *macro_name = NULL;
3239 	register int x = 0;
3240 
3241 	/* set each of the argv macro environment variables */
3242 	for(x = 0; x < MAX_COMMAND_ARGUMENTS; x++) {
3243 		asprintf(&macro_name, "ARG%d", x + 1);
3244 		set_macro_environment_var(macro_name, mac->argv[x], set);
3245 		my_free(macro_name);
3246 		}
3247 
3248 	return OK;
3249 	}
3250 
3251 int set_argv_macro_environment_vars(int set) {
3252 	return set_argv_macro_environment_vars_r(&global_macros, set);
3253 	}
3254 
3255 
3256 /* sets or unsets custom host/service/contact macro environment variables */
3257 int set_custom_macro_environment_vars_r(nagios_macros *mac, int set) {
3258 	customvariablesmember *temp_customvariablesmember = NULL;
3259 	host *temp_host = NULL;
3260 	service *temp_service = NULL;
3261 	contact *temp_contact = NULL;
3262 	char *customvarname = NULL;
3263 
3264 	/***** CUSTOM HOST VARIABLES *****/
3265 	/* generate variables and save them for later */
3266 	if((temp_host = mac->host_ptr) && set == TRUE) {
3267 		for(temp_customvariablesmember = temp_host->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
3268 			asprintf(&customvarname, "_HOST%s", temp_customvariablesmember->variable_name);
3269 			add_custom_variable_to_object(&mac->custom_host_vars, customvarname, temp_customvariablesmember->variable_value);
3270 			my_free(customvarname);
3271 			}
3272 		}
3273 	/* set variables */
3274 	for(temp_customvariablesmember = mac->custom_host_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
3275 		set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set);
3276 		}
3277 
3278 	/***** CUSTOM SERVICE VARIABLES *****/
3279 	/* generate variables and save them for later */
3280 	if((temp_service = mac->service_ptr) && set == TRUE) {
3281 		for(temp_customvariablesmember = temp_service->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
3282 			asprintf(&customvarname, "_SERVICE%s", temp_customvariablesmember->variable_name);
3283 			add_custom_variable_to_object(&mac->custom_service_vars, customvarname, temp_customvariablesmember->variable_value);
3284 			my_free(customvarname);
3285 			}
3286 		}
3287 	/* set variables */
3288 	for(temp_customvariablesmember = mac->custom_service_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next)
3289 		set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set);
3290 
3291 	/***** CUSTOM CONTACT VARIABLES *****/
3292 	/* generate variables and save them for later */
3293 	if((temp_contact = mac->contact_ptr) && set == TRUE) {
3294 		for(temp_customvariablesmember = temp_contact->custom_variables; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next) {
3295 			asprintf(&customvarname, "_CONTACT%s", temp_customvariablesmember->variable_name);
3296 			add_custom_variable_to_object(&mac->custom_contact_vars, customvarname, temp_customvariablesmember->variable_value);
3297 			my_free(customvarname);
3298 			}
3299 		}
3300 	/* set variables */
3301 	for(temp_customvariablesmember = mac->custom_contact_vars; temp_customvariablesmember != NULL; temp_customvariablesmember = temp_customvariablesmember->next)
3302 		set_macro_environment_var(temp_customvariablesmember->variable_name, clean_macro_chars(temp_customvariablesmember->variable_value, STRIP_ILLEGAL_MACRO_CHARS | ESCAPE_MACRO_CHARS), set);
3303 
3304 	return OK;
3305 	}
3306 
3307 int set_custom_macro_environment_vars(int set) {
3308 	return set_custom_macro_environment_vars_r(&global_macros, set);
3309 	}
3310 
3311 
3312 /* sets or unsets contact address environment variables */
3313 int set_contact_address_environment_vars_r(nagios_macros *mac, int set) {
3314 	char *varname = NULL;
3315 	register int x;
3316 
3317 	/* these only get set during notifications */
3318 	if(mac->contact_ptr == NULL)
3319 		return OK;
3320 
3321 	for(x = 0; x < MAX_CONTACT_ADDRESSES; x++) {
3322 		asprintf(&varname, "CONTACTADDRESS%d", x);
3323 		set_macro_environment_var(varname, mac->contact_ptr->address[x], set);
3324 		my_free(varname);
3325 		}
3326 
3327 	return OK;
3328 	}
3329 
3330 int set_contact_address_environment_vars(int set) {
3331 	return set_contact_address_environment_vars_r(&global_macros, set);
3332 	}
3333 
3334 
3335 /* sets or unsets a macro environment variable */
3336 int set_macro_environment_var(char *name, char *value, int set) {
3337 	char *env_macro_name = NULL;
3338 
3339 	/* we won't mess with null variable names */
3340 	if(name == NULL)
3341 		return ERROR;
3342 
3343 	/* create environment var name */
3344 	asprintf(&env_macro_name, "%s%s", MACRO_ENV_VAR_PREFIX, name);
3345 
3346 	/* set or unset the environment variable */
3347 	set_environment_var(env_macro_name, value, set);
3348 
3349 	/* free allocated memory */
3350 	my_free(env_macro_name);
3351 
3352 	return OK;
3353 	}
3354 
3355 
3356 #endif
3357