1<?php
2/*
3 +-------------------------------------------------------------------------+
4 | Copyright (C) 2004-2021 The Cacti Group                                 |
5 |                                                                         |
6 | This program is free software; you can redistribute it and/or           |
7 | modify it under the terms of the GNU General Public License             |
8 | as published by the Free Software Foundation; either version 2          |
9 | of the License, or (at your option) any later version.                  |
10 |                                                                         |
11 | This program is distributed in the hope that it will be useful,         |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
14 | GNU General Public License for more details.                            |
15 +-------------------------------------------------------------------------+
16 | Cacti: The Complete RRDtool-based Graphing Solution                     |
17 +-------------------------------------------------------------------------+
18 | This code is designed, written, and maintained by the Cacti Group. See  |
19 | about.php and/or the AUTHORS file for specific developer information.   |
20 +-------------------------------------------------------------------------+
21 | http://www.cacti.net/                                                   |
22 +-------------------------------------------------------------------------+
23*/
24
25function clog_get_datasource_titles($local_data_ids) {
26	if (!is_array($local_data_ids)) {
27		$local_data_ids = array($local_data_ids);
28	}
29
30	$titles = array();
31	foreach ($local_data_ids as $local_data_id) {
32		if (!array_key_exists($local_data_id, $titles)) {
33			$titles[$local_data_id] = get_data_source_title($local_data_id);
34		}
35	}
36
37	return $titles;
38}
39
40function clog_get_graphs_from_datasource($local_data_id) {
41	return array_rekey(db_fetch_assoc_prepared('SELECT DISTINCT
42		gtg.local_graph_id AS id,
43		gtg.title_cache AS name
44		FROM graph_templates_graph AS gtg
45		INNER JOIN graph_templates_item AS gti
46		ON gtg.local_graph_id=gti.local_graph_id
47		INNER JOIN data_template_rrd AS dtr
48		ON gti.task_item_id=dtr.id
49		WHERE gtg.local_graph_id>0
50		AND dtr.local_data_id = ?',
51		array($local_data_id)), 'id', 'name');
52}
53
54function clog_validate_filename(&$file, &$filepath, &$filename, $filecheck = false) {
55	global $config;
56
57	$logfile = read_config_option('path_cactilog');
58	if ($logfile == '') {
59		$logfile = '/var/log/cacti/log';
60	}
61
62	$errfile  = read_config_option('path_stderrlog');
63	$errbase  = basename($errfile);
64
65	$file     = basename($file);
66	$logbase  = basename($logfile);
67
68	$filepath = '';
69	$filename = '';
70	$filefull = '';
71
72	if (!empty($errfile) && strpos($file, $errbase) === 0) {
73		$filepath = dirname($errfile);
74		$filename = $errbase;
75		$filefull = $filepath . '/' . $file;
76	} elseif (!empty($logfile) && strpos($file, $logbase) === 0) {
77		$filepath = dirname($logfile);
78		$filename = $logbase;
79		$filefull = $filepath . '/' . $file;
80	}
81
82	return ($filecheck ? file_exists($filefull) : !empty($filefull));
83}
84
85function clog_purge_logfile() {
86	global $config;
87
88	$filename = get_nfilter_request_var('filename');
89
90	if (!clog_validate_filename($filename, $logpath, $logname)) {
91		raise_message('clog_invalid');
92		header('Location: ' . get_current_page());
93		exit(0);
94	}
95
96	$purgefile = $logpath . '/' . $filename;
97	$logfile = $logpath . '/'. $logname;
98
99	if (file_exists($purgefile)) {
100		if (is_writable($purgefile)) {
101			if ($logfile != $purgefile) {
102				unlink($purgefile);
103				raise_message('clog_remove');
104			} else {
105				/* fill in the current date for printing in the log */
106				if (defined('CACTI_DATE_TIME_FORMAT')) {
107					$date = date(CACTI_DATE_TIME_FORMAT);
108				} else {
109					$date = date('Y-m-d H:i:s');
110				}
111
112				$log_fh = fopen($logfile, 'w');
113				fwrite($log_fh, __('%s - WEBUI NOTE: Cacti Log Cleared from Web Management Interface.', $date) . PHP_EOL);
114				fclose($log_fh);
115				raise_message('clog_purged');
116			}
117
118			cacti_log('NOTE: Cacti Log file ' . $purgefile . ', Removed by user ' . get_username($_SESSION['sess_user_id']), false, 'WEBUI');
119		} else {
120			raise_message('clog_permissions');
121		}
122	} else {
123		raise_message('clog_missing');
124	}
125}
126
127function clog_view_logfile() {
128	global $config;
129
130	$exclude_reported = false;
131
132	$clogAdmin = clog_admin();
133
134	/* ================= input validation and session storage ================= */
135	$filters = array(
136		'page' => array(
137			'filter'  => FILTER_VALIDATE_INT,
138			'default' => '1'
139		),
140		'tail_lines' => array(
141			'filter'  => FILTER_VALIDATE_INT,
142			'default' => read_config_option('num_rows_log'),
143			'pageset' => true
144		),
145		'message_type' => array(
146			'filter'  => FILTER_VALIDATE_INT,
147			'default' => '-1',
148			'pageset' => true
149		),
150		'filename' => array(
151			'filter'  => FILTER_CALLBACK,
152			'default' => read_config_option('path_cactilog'),
153			'pageset' => true,
154			'options' => array('options' => 'sanitize_search_string')
155		),
156		'refresh' => array(
157			'filter'  => FILTER_VALIDATE_INT,
158			'default' => read_config_option('log_refresh_interval')
159		),
160		'reverse' => array(
161			'filter'  => FILTER_VALIDATE_INT,
162			'default' => '1'
163		),
164		'rfilter' => array(
165			'filter'  => FILTER_VALIDATE_IS_REGEX,
166			'default' => '',
167			'pageset' => true
168		)
169	);
170
171	validate_store_request_vars($filters, 'sess_clog');
172	/* ================= input validation ================= */
173
174	/* enable page refreshes */
175	kill_session_var('custom');
176
177	set_request_var('page_referrer', 'view_logfile');
178	load_current_session_value('page_referrer', 'page_referrer', 'view_logfile');
179
180	$logfile = basename(get_nfilter_request_var('filename'));
181	$logname = '';
182
183	if (!clog_validate_filename($logfile, $logpath, $logname, true)) {
184		$logfile = read_config_option('path_cactilog');
185	} else {
186		$logfile = $logpath . '/' . $logfile;
187	}
188
189	if ($clogAdmin && isset_request_var('purge_continue')) {
190		clog_purge_logfile();
191		$logfile = read_config_option('path_cactilog');
192	}
193
194	$page_nr = get_request_var('page');
195
196	$page = $config['url_path'] . 'clog' . (!$clogAdmin ? '_user' : '') . '.php?header=false';
197	$page .= '&filename=' . basename($logfile) . '&page=' . $page_nr;
198
199	$refresh = array(
200		'seconds' => get_request_var('refresh'),
201		'page'    => $page,
202		'logout'  => 'false'
203	);
204
205	set_page_refresh($refresh);
206
207	general_header();
208
209	if ($clogAdmin && isset_request_var('purge')) {
210		form_start('clog.php');
211
212		html_start_box(__('Purge'), '50%', '', '3', 'center', '');
213
214		print "<tr>
215			<td class='textArea'>
216				<p>" . __('Click \'Continue\' to purge the Log File.<br><br><br>Note: If logging is set to both Cacti and Syslog, the log information will remain in Syslog.') . "</p>
217			</td>
218		</tr>
219		<tr class='saveRow'>
220			<td colspan='2' class='right'>
221				<input type='button' class='ui-button ui-corner-all ui-widget' id='cancel' value='" . __esc('Cancel') . "'>&nbsp
222				<input type='button' class='ui-button ui-corner-all ui-widget' id='pc' name='purge_continue' value='" . __esc('Continue') . "' title='" . __esc('Purge Log') . "'>
223				<script type='text/javascript'>
224				$('#pc').click(function() {
225					strURL = location.pathname+'?purge_continue=1&header=false&filename=" . basename($logfile) . "';
226					loadPageNoHeader(strURL);
227				});
228
229				$('#cancel').click(function() {
230					strURL = location.pathname+'?header=false';
231					loadPageNoHeader(strURL);
232				});
233
234				$(function() {
235					applySkin();
236				});
237				</script>
238			</td>
239		</tr>\n";
240
241		html_end_box();
242
243		return;
244	}
245
246	html_start_box(__('Log Filters'), '100%', '', '3', 'center', '');
247	filter($clogAdmin, basename($logfile));
248	html_end_box();
249
250	/* read logfile into an array and display */
251	$total_rows      = 0;
252	$number_of_lines = get_request_var('tail_lines') < 0 ? read_config_option('max_display_rows') : get_request_var('tail_lines');
253
254	$logcontents = tail_file($logfile, $number_of_lines, get_request_var('message_type'), get_request_var('rfilter'), $page_nr, $total_rows);
255
256	if (get_request_var('reverse') == 1) {
257		$logcontents = array_reverse($logcontents);
258	}
259
260	if (!$clogAdmin) {
261		$exclude_regex = read_config_option('clog_exclude', true);
262		if ($exclude_regex != '') {
263			$ad_filter = __(' - Admin Filter active');
264		} else {
265			$ad_filter = __(' - Admin Unfiltered');
266		}
267	} else {
268		$ad_filter = __(' - Admin view');
269		$exclude_regex = '';
270	}
271
272	if (get_request_var('message_type') > 0 || get_request_var('rfilter') != '') {
273		$start_string = __('Log [Total Lines: %d %s - Filter active]', $total_rows, $ad_filter);
274	} else {
275		$start_string = __('Log [Total Lines: %d %s - Unfiltered]', $total_rows, $ad_filter);
276	}
277
278	$rfilter      = get_request_var('rfilter');
279	$reverse      = get_request_var('reverse');
280	$refreshTime  = get_request_var('refresh');
281	$message_type = get_request_var('message_type');
282	$tail_lines   = get_request_var('tail_lines');
283	$base_url     = $config['url_path'] . 'clog.php';
284
285	$nav = html_nav_bar($base_url, MAX_DISPLAY_PAGES, $page_nr, $number_of_lines, $total_rows, 1, __('Entries'), 'page', 'main');
286
287	print $nav;
288
289	html_start_box($start_string, '100%', '', '3', 'center', '');
290
291	$linecolor = false;
292
293	$hosts = db_fetch_assoc('SELECT id, description
294		FROM host
295		WHERE disabled = ""
296		AND deleted = ""');
297
298	$hostDescriptions = array();
299	foreach ($hosts as $host) {
300		$hostDescriptions[$host['id']] = html_escape($host['description']);
301	}
302
303	$regex_array = clog_get_regex_array();
304	foreach ($logcontents as $item) {
305		$new_item = html_escape($item);
306
307		$new_item = preg_replace_callback($regex_array['complete'],'clog_regex_parser',$new_item);
308
309		/* respect the exclusion filter */
310		if ($exclude_regex != '' && !$clogAdmin) {
311			if (validate_is_regex($exclude_regex)) {
312				if (preg_match($exclude_regex, $new_item)) {
313					continue;
314				}
315			} elseif (!$exclude_reported) {
316				cacti_log('Cacti Log Exclude Regex "' . $exclude_regex . '" is Invalid.  Update your Exclude Regex to be valid!');
317				$exclude_reported = true;
318			}
319		}
320
321		/* get the background color */
322		if (strpos($new_item, 'ERROR') !== false || strpos($new_item, 'FATAL') !== false) {
323			$class = 'clogError';
324		} elseif (strpos($new_item, 'WARN') !== false) {
325			$class = 'clogWarning';
326		} elseif (strpos($new_item, ' SQL ') !== false) {
327			$class = 'clogSQL';
328		} elseif (strpos($new_item, 'DEBUG') !== false) {
329			$class = 'clogDebug';
330		} elseif (strpos($new_item, 'STATS') !== false) {
331			$class = 'clogStats';
332		} else {
333			if ($linecolor) {
334				$class = 'odd';
335			} else {
336				$class = 'even';
337			}
338			$linecolor = !$linecolor;
339		}
340
341		?>
342		<tr class='<?php print $class;?>'>
343			<td>
344				<?php print $new_item;?>
345			</td>
346		</tr>
347		<?php
348	}
349
350	html_end_box(false);
351
352	if ($total_rows) {
353		print $nav;
354	}
355
356	bottom_footer();
357}
358
359function filter_sort($a, $b) {
360	$a_parts = explode('-', $a);
361	$b_parts = explode('-', $b);
362
363	$a_date = '99999999';
364	if (cacti_count($a_parts) > 1) {
365		$a_date = $a_parts[1];
366	}
367
368	$b_date = '99999999';
369	if (cacti_count($b_parts) > 1) {
370		$b_date = $b_parts[1];
371	}
372
373	// Invert the order, replace _'s with +'s to make them sort after .'s, prefix the date
374	// This makes cacti_stderr.log appear after cacti.log in date descending order with
375	// no date files first
376	return strcmp($b_date . '-' . str_replace('_','+',$b_parts[0]), $a_date . '-' . str_replace('_','+',$a_parts[0]));
377}
378
379function clog_get_logfiles() {
380	global $config;
381
382	$stdFileArray = $stdLogFileArray = $stdErrFileArray = array();
383	$configLogPath = read_config_option('path_cactilog');
384	$configLogBase = basename($configLogPath);
385	$stderrLogPath = read_config_option('path_stderrlog');
386	$stderrLogBase = basename($stderrLogPath);
387
388	if ($configLogPath == '') {
389		$logPath = $config['base_path'] . '/log/';
390	} else {
391		$logPath = dirname($configLogPath);
392	}
393
394	if (is_readable($logPath)) {
395		$files = @scandir($logPath);
396	} else {
397		$files = array('cacti.log');
398	}
399
400	// Defaults go first and second
401	$stdFileArray[] = basename($configLogPath);
402
403	// After Defaults, do Cacti log first (of archived)
404	if (cacti_sizeof($files)) {
405		$stdLogFileArray = array();
406		foreach ($files as $logFile) {
407			if (in_array($logFile, array('.', '..', '.htaccess', $configLogBase, $stderrLogBase))) {
408				continue;
409			}
410
411			$explode = explode('.', $logFile);
412			if (substr($explode[max(array_keys($explode))], 0, 3) != 'log') {
413				continue;
414			}
415
416			if (!clog_validate_filename($logFile, $logPath, $logName)) {
417				continue;
418			}
419
420			if (!empty($stderrlogbase) && strpos($logFile, $stderrLogBase) === 0){
421				$stdErrFileArray[] = $logFile;
422			} else {
423				$stdLogFileArray[] = $logFile;
424			}
425		}
426
427		$stdErrFileArray = array_unique($stdErrFileArray);
428		$stdLogFileArray = array_unique($stdLogFileArray);
429	}
430
431	// Defaults go first and second
432	if (!empty($stderrLogPath)) {
433		$stdFileArray[] = basename($stderrLogPath);
434
435		// After Defaults, do Cacti StdErr log second (of archived)
436		if (dirname($stderrLogPath) != $logPath) {
437			$errFiles = @scandir(dirname($stderrLogPath));
438			$files = $errFiles;
439			if (cacti_sizeof($files)) {
440				$stdErrFileArray = array();
441				foreach ($files as $logFile) {
442					if (in_array($logFile, array('.', '..', '.htaccess', $configLogBase, $stderrLogBase))) {
443						continue;
444					}
445
446					$explode = explode('.', $logFile);
447					if (substr($explode[max(array_keys($explode))], 0, 3) != 'log') {
448						continue;
449					}
450
451					if (!clog_validate_filename($logFile, $logPath, $logName)) {
452						continue;
453					}
454
455					$stdErrFileArray[] = $logFile;
456				}
457
458				$stdErrFileArray = array_unique($stdErrFileArray);
459			}
460		}
461	}
462
463	arsort($stdLogFileArray, SORT_NATURAL);
464	arsort($stdErrFileArray, SORT_NATURAL);
465
466	return array_unique(array_merge($stdFileArray, $stdLogFileArray, $stdErrFileArray));
467}
468
469function filter($clogAdmin, $selectedFile) {
470	global $page_refresh_interval, $log_tail_lines, $config;
471	?>
472	<tr class='even'>
473		<td>
474		<form id='logfile'>
475			<table class='filterTable'>
476				<tr>
477					<td>
478						<?php print __('File');?>
479					</td>
480					<td>
481						<select id='filename'>
482						<?php
483						$logFileArray = clog_get_logfiles();
484
485						if (cacti_sizeof($logFileArray)) {
486							foreach ($logFileArray as $logFile) {
487								print "<option value='" . $logFile . "'";
488
489								if ($selectedFile == $logFile) {
490									print ' selected';
491								}
492
493								$logParts = explode('-', $logFile);
494
495								$logDate = cacti_count($logParts) < 2 ? '' : $logParts[1] . (isset($logParts[2]) ? '-' . $logParts[2]:'');
496								$logName = $logParts[0];
497
498								print '>' . $logName . ($logDate != '' ? ' [' . substr($logDate,4) . ']':'') . "</option>\n";
499							}
500						}
501						?>
502						</select>
503					</td>
504					<td>
505						<?php print __('Tail Lines');?>
506					</td>
507					<td>
508						<select id='tail_lines'>
509							<?php
510							foreach($log_tail_lines AS $tail_lines => $display_text) {
511								print "<option value='" . $tail_lines . "'";
512								if (get_request_var('tail_lines') == $tail_lines) {
513									print ' selected';
514								}
515								print '>' . $display_text . "</option>\n";
516							}
517							?>
518						</select>
519					</td>
520					<td>
521						<span>
522							<input type='submit' class='ui-button ui-corner-all ui-widget' id='go' value='<?php print __esc('Go');?>'>
523							<input type='button' class='ui-button ui-corner-all ui-widget' id='clear' value='<?php print __esc('Clear');?>'>
524						<?php if ($clogAdmin) {?><input type='button' class='ui-button ui-corner-all ui-widget' id='purge' value='<?php print __esc('Purge');?>'><?php }?>
525						</span>
526					</td>
527				</tr>
528			</table>
529			<table class='filterTable'>
530				<tr>
531					<td>
532						<?php print __('Type');?>
533					</td>
534					<td>
535						<select id='message_type'>
536							<option value='-1'<?php if (get_request_var('message_type') == '-1') {?> selected<?php }?>><?php print __('All');?></option>
537							<option value='1'<?php if (get_request_var('message_type') == '1') {?> selected<?php }?>><?php print __('Stats');?></option>
538							<option value='2'<?php if (get_request_var('message_type') == '2') {?> selected<?php }?>><?php print __('Warnings');?></option>
539							<option value='3'<?php if (get_request_var('message_type') == '3') {?> selected<?php }?>><?php print __('Errors');?></option>
540							<option value='4'<?php if (get_request_var('message_type') == '4') {?> selected<?php }?>><?php print __('Debug');?></option>
541							<option value='5'<?php if (get_request_var('message_type') == '5') {?> selected<?php }?>><?php print __('SQL Calls');?></option>
542						</select>
543					</td>
544					<td>
545						<?php print __('Display Order');?>
546					</td>
547					<td>
548						<select id='reverse'>
549							<option value='1'<?php if (get_request_var('reverse') == '1') {?> selected<?php }?>><?php print __('Newest First');?></option>
550							<option value='2'<?php if (get_request_var('reverse') == '2') {?> selected<?php }?>><?php print __('Oldest First');?></option>
551						</select>
552					</td>
553					<td>
554						<?php print __('Refresh');?>
555					</td>
556					<td>
557						<select id='refresh'>
558							<?php
559							foreach($page_refresh_interval AS $seconds => $display_text) {
560								print "<option value='" . $seconds . "'";
561								if (get_request_var('refresh') == $seconds) {
562									print ' selected';
563								}
564								print '>' . $display_text . '</option>';
565							}
566							?>
567						</select>
568					</td>
569				</tr>
570			</table>
571			<table class='filterTable'>
572				<tr>
573					<td>
574						<?php print __('Search');?>
575					</td>
576					<td>
577						<input type='text' class='ui-state-default ui-corner-all' id='rfilter' size='75' value='<?php print html_escape_request_var('rfilter');?>'>
578					</td>
579				</tr>
580			</table>
581		</form>
582		<script type='text/javascript'>
583
584		$(function() {
585			$('#rfilter, #reverse, #refresh, #message_type, #filename, #tail_lines').unbind().change(function() {
586				applyFilter();
587			});
588
589			$('#clear').unbind().click(function() {
590				strURL = basename(location.pathname) + '?clear=true&header=false';
591				loadPageNoHeader(strURL);
592			});
593
594			$('#purge').unbind().click(function() {
595				strURL = basename(location.pathname) + '?purge=true&header=false&filename=' + $('#filename').val();
596				loadPageNoHeader(strURL);
597			});
598
599			$('#logfile').submit(function(event) {
600				event.preventDefault();
601				applyFilter();
602			});
603		});
604
605		function applyFilter() {
606			refreshMSeconds=$('#refresh').val()*1000;
607
608			strURL = basename(location.pathname)+
609				'?rfilter=' + base64_encode($('#rfilter').val())+
610				'&reverse='+$('#reverse').val()+
611				'&refresh='+$('#refresh').val()+
612				'&message_type='+$('#message_type').val()+
613				'&tail_lines='+$('#tail_lines').val()+
614				'&filename='+$('#filename').val()+
615				'&header=false';
616
617			loadPageNoHeader(strURL);
618		}
619		</script>
620		</td>
621	</tr>
622	<?php
623}
624
625function clog_get_regex_array() {
626	static $regex_array = array();
627
628	if (!cacti_sizeof($regex_array)) {
629		$regex_array = array(
630			1  => array('name' => 'DS',     'regex' => '( DS\[)([, \d]+)(\])',       'func' => 'clog_regex_datasource'),
631			2  => array('name' => 'DQ',     'regex' => '( DQ\[)([, \d]+)(\])',       'func' => 'clog_regex_dataquery'),
632			3  => array('name' => 'Device', 'regex' => '( Device\[)([, \d]+)(\])',   'func' => 'clog_regex_device'),
633			4  => array('name' => 'Poller', 'regex' => '( Poller\[)([, \d]+)(\])',   'func' => 'clog_regex_poller'),
634			5  => array('name' => 'RRA',    'regex' => "([_\/])(\d+)(\.rrd&#039;)",  'func' => 'clog_regex_rra'),
635			6  => array('name' => 'GT',     'regex' => '( GT\[)([, \d]+)(\])',       'func' => 'clog_regex_graphtemplates'),
636			7  => array('name' => 'Graph',  'regex' => '( Graph\[)([, \d]+)(\])',    'func' => 'clog_regex_graphs'),
637			8  => array('name' => 'Graphs', 'regex' => '( Graphs\[)([, \d]+)(\])',   'func' => 'clog_regex_graphs'),
638			9  => array('name' => 'User',   'regex' => '( User\[)([, \d]+)(\])',     'func' => 'clog_regex_users'),
639			10 => array('name' => 'User',   'regex' => '( Users\[)([, \d]+)(\])',    'func' => 'clog_regex_users'),
640			11 => array('name' => 'Rule',   'regex' => '( Rule\[)([, \d]+)(\])',   	 'func' => 'clog_regex_rule'),
641		);
642
643		$regex_array = api_plugin_hook_function('clog_regex_array',$regex_array);
644		$regex_complete = '';
645		foreach ($regex_array as $regex_key => $regex_setting) {
646			$regex_complete .= (strlen($regex_complete)?')|(':'').$regex_setting['regex'];
647		}
648		$regex_complete = '~('.$regex_complete.')~';
649		$regex_array['complete'] = $regex_complete;
650	}
651
652	return $regex_array;
653}
654
655function clog_regex_parser($matches) {
656	$result = $matches[0];
657	$match = $matches[0];
658
659	$key_match = -1;
660	for ($index = 1; $index < cacti_sizeof($matches); $index++) {
661		if ($match == $matches[$index]) {
662			$key_match = $index;
663			break;
664		}
665	}
666
667	if ($key_match != -1) {
668		$key_setting = ($key_match - 1) / 4 + 1;
669		$regex_array = clog_get_regex_array();
670
671		if (cacti_sizeof($regex_array)) {
672			if (array_key_exists($key_setting, $regex_array)) {
673				$regex_setting = $regex_array[$key_setting];
674
675				$rekey_array = array();
676				for ($j = 0; $j < 4; $j++) {
677					$rekey_array[$j] = $matches[$key_match + $j];
678				}
679
680				if (function_exists($regex_setting['func'])) {
681					$result=call_user_func_array($regex_setting['func'],array($rekey_array));
682				} else {
683					$result=$match;
684				}
685			}
686		}
687	}
688
689	return $result;
690}
691
692function clog_regex_device($matches) {
693	global $config;
694
695	$result = $matches[0];
696
697	$dev_ids = explode(',',str_replace(" ","",$matches[2]));
698	if (cacti_sizeof($dev_ids)) {
699		$result = '';
700		$hosts = db_fetch_assoc('SELECT id, description
701			FROM host
702			WHERE id in (' . implode(',',$dev_ids) . ')');
703
704		$hostDescriptions = array();
705		if (cacti_sizeof($hosts)) {
706			foreach ($hosts as $host) {
707				$hostDescriptions[$host['id']] = html_escape($host['description']);
708			}
709		}
710
711		foreach ($dev_ids as $host_id) {
712			$result .= $matches[1].'<a href=\'' . html_escape($config['url_path'] . 'host.php?action=edit&id=' . $host_id) . '\'>' . (isset($hostDescriptions[$host_id]) ? $hostDescriptions[$host_id]:$host_id) . '</a>' . $matches[3];
713		}
714	}
715
716	return $result;
717}
718
719function clog_regex_datasource($matches) {
720	global $config;
721
722	$result = $matches[0];
723
724	$ds_ids = explode(',',str_replace(" ","",$matches[2]));
725	if (cacti_sizeof($ds_ids)) {
726		$result = '';
727
728		$graph_rows = array_rekey(db_fetch_assoc('SELECT DISTINCT
729			gtg.local_graph_id AS id
730			FROM graph_templates_graph AS gtg
731			INNER JOIN graph_templates_item AS gti
732			ON gtg.local_graph_id=gti.local_graph_id
733			INNER JOIN data_template_rrd AS dtr
734			ON gti.task_item_id=dtr.id
735			WHERE gtg.local_graph_id>0
736			AND dtr.local_data_id IN (' . $matches[2] . ')'),'id','id');
737
738		$graph_results = '';
739		if (cacti_sizeof($graph_rows)) {
740			$graph_ids = implode(',',$graph_rows);
741			$graph_array = array( 0 => '', 1 => ' Graphs[', 2 => $graph_ids, 3 => ']');
742
743			$graph_results = clog_regex_graphs($graph_array);
744		}
745
746		$result .= $matches[1];
747		$i       = 0;
748
749		$ds_ids = array_unique($ds_ids);
750		$ds_titles = clog_get_datasource_titles($ds_ids);
751		if (!isset($ds_titles)) {
752			$ds_titles = array();
753		}
754
755		foreach($ds_ids as $ds_id) {
756			$ds_title = $ds_id;
757			if (array_key_exists($ds_id, $ds_titles)) {
758				$ds_title = $ds_titles[$ds_id];
759			}
760			$result .= ($i == 0 ? '':', ') . "<a href='" . html_escape($config['url_path'] . 'data_sources.php?action=ds_edit&id=' . $ds_id) . "'>" . html_escape($ds_title) . '</a>';
761
762			$i++;
763		}
764
765		$result .= $matches[3] . $graph_results;
766	}
767
768	return $result;
769}
770
771function clog_regex_poller($matches) {
772	global $config;
773
774	$result = $matches[0];
775
776	$poller_ids = explode(',',str_replace(" ","",$matches[2]));
777	if (cacti_sizeof($poller_ids)) {
778		$result = '';
779		$pollers = db_fetch_assoc_prepared('SELECT id, name
780			FROM poller
781			WHERE id in (' . implode(',',$poller_ids) . ')');
782
783		$pollerDescriptions = array();
784		if (cacti_sizeof($pollers)) {
785			foreach ($pollers as $poller) {
786				$pollerDescriptions[$poller['id']] = html_escape($poller['name']);
787			}
788		}
789
790		foreach ($poller_ids as $poller_id) {
791			$result .= $matches[1].'<a href=\'' . html_escape($config['url_path'] . 'pollers.php?action=edit&id=' . $poller_id) . '\'>' . (isset($pollerDescriptions[$poller_id]) ? $pollerDescriptions[$poller_id]:$poller_id) . '</a>' . $matches[3];
792		}
793	}
794
795	return $result;
796}
797
798function clog_regex_dataquery($matches) {
799	global $config;
800
801	$result = $matches[0];
802
803	$query_ids = explode(',',str_replace(" ","",$matches[2]));
804	if (cacti_sizeof($query_ids)) {
805		$result = '';
806		$querys = db_fetch_assoc('SELECT id, name
807			FROM snmp_query
808			WHERE id in (' . implode(',',$query_ids) . ')');
809
810		$queryDescriptions = array();
811		if (cacti_sizeof($querys)) {
812			foreach ($querys as $query) {
813				$queryDescriptions[$query['id']] = html_escape($query['name']);
814			}
815		}
816
817		foreach ($query_ids as $query_id) {
818			$result .= $matches[1].'<a href=\'' . html_escape($config['url_path'] . 'data_queries.php?action=edit&id=' . $query_id) . '\'>' . (isset($queryDescriptions[$query_id]) ? $queryDescriptions[$query_id]:$query_id) . '</a>' . $matches[3];
819		}
820	}
821
822	return $result;
823}
824
825function clog_regex_rra($matches) {
826	global $config;
827
828	$result = $matches[0];
829
830	$local_data_ids = $matches[2];
831	if (strlen($local_data_ids)) {
832		$datasource_array = array( 0 => '', 1 => ' DS[', 2 => $local_data_ids, 3 => ']');
833		$datasource_result = clog_regex_datasource($datasource_array);
834		if (strlen($datasource_result)) {
835			$result .= ' '. $datasource_result;
836		}
837	}
838
839	return $result;
840}
841
842function clog_regex_graphs($matches) {
843	global $config;
844
845	$result = $matches[0];
846
847	$query_ids = explode(',',str_replace(" ","",$matches[2]));
848	if (cacti_sizeof($query_ids)) {
849		$result = '';
850		$graph_add = $config['url_path'] . 'graph_view.php?page=1&style=selective&action=preview&graph_add=';
851
852		$title = '';
853		$i     = 0;
854
855		$querys = db_fetch_assoc('SELECT DISTINCT
856			gtg.local_graph_id AS id,
857			gtg.title_cache AS title
858			FROM graph_templates_graph AS gtg
859			INNER JOIN graph_templates_item AS gti
860			ON gtg.local_graph_id=gti.local_graph_id
861			INNER JOIN data_template_rrd AS dtr
862			ON gti.task_item_id=dtr.id
863			WHERE gtg.local_graph_id in (' . implode(',',$query_ids) . ')');
864
865		$result .= $matches[1] . "<a href='";
866
867		$queryDescriptions = array();
868		if (cacti_sizeof($querys)) {
869			foreach ($querys as $query) {
870				$queryDescriptions[$query['id']] = html_escape($query['title']);
871			}
872		}
873
874		$i=0;
875		foreach ($query_ids as $query_id) {
876			$graph_add .= ($i > 0 ? '%2C' : '') . $query_id;
877			$title     .= ($title != '' ? ', ':'') . html_escape((isset($queryDescriptions[$query_id]) ? $queryDescriptions[$query_id]:$query_id));
878			$i++;
879		}
880
881		$result .= html_escape($graph_add) . '\'>' . $title . '</a>' . $matches[3];
882	}
883	return $result;
884}
885
886function clog_regex_graphtemplates($matches) {
887	global $config;
888
889	$result = $matches[0];
890
891	$query_ids = explode(',',str_replace(" ","",$matches[2]));
892	if (cacti_sizeof($query_ids)) {
893		$result = '';
894		$querys = db_fetch_assoc('SELECT id, name
895			FROM graph_templates
896			WHERE id in ('  . implode(',',$query_ids) . ')');
897
898		$queryDescriptions = array();
899		if (cacti_sizeof($querys)) {
900			foreach ($querys as $query) {
901				$queryDescriptions[$query['id']] = html_escape($query['name']);
902			}
903		}
904
905		foreach ($query_ids as $query_id) {
906			$result .= $matches[1].'<a href=\'' . html_escape($config['url_path'] . 'graph_templates.php?action=template_edit&id=' . $query_id) . '\'>' . (isset($queryDescriptions[$query_id]) ? $queryDescriptions[$query_id]:$query_id) . '</a>' . $matches[3];
907		}
908	}
909
910	return $result;
911}
912
913function clog_regex_users($matches) {
914	global $config;
915
916	$result = $matches[0];
917
918	$query_ids = explode(',',str_replace(" ","",$matches[2]));
919	if (cacti_sizeof($query_ids)) {
920		$result = '';
921
922		$querys = db_fetch_assoc('SELECT DISTINCT
923			id, username
924			FROM user_auth
925			WHERE id in (' . implode(',',$query_ids) . ')');
926
927		$queryDescriptions = array();
928		if (cacti_sizeof($querys)) {
929			foreach ($querys as $query) {
930				$queryDescriptions[$query['id']] = html_escape($query['username']);
931			}
932		}
933
934		foreach ($query_ids as $query_id) {
935			$result .= $matches[1];
936			if (isset($queryDescriptions[$query_id])) {
937				$result .= '<a href=\'' . html_escape($config['url_path'] . 'user_admin.php?action=user_edit&tab=general&id=' . $query_id) . '\'>' . $queryDescriptions[$query_id] . '</a>';
938			} else {
939				$result .= $query_id;
940			}
941			$result .= $matches[3];
942		}
943	}
944	return $result;
945}
946
947function clog_regex_rule($matches) {
948	global $config;
949
950	$result = $matches[0];
951
952	$dev_ids = explode(',',str_replace(" ","",$matches[2]));
953	if (cacti_sizeof($dev_ids)) {
954		$result = '';
955		$rules = db_fetch_assoc('SELECT id, name
956			FROM automation_graph_rules
957			WHERE id in (' . implode(',',$dev_ids) . ')');
958
959		$ruleNames = array();
960		if (cacti_sizeof($rules)) {
961			foreach ($rules as $rule) {
962				$ruleNames[$rule['id']] = html_escape($rule['name']);
963			}
964		}
965
966		foreach ($dev_ids as $rule_id) {
967			$result .= $matches[1].'<a href=\'' . html_escape($config['url_path'] . 'automation_graph_rules.php?action=edit&id=' . $rule_id) . '\'>' . (isset($ruleNames[$rule_id]) ? $ruleNames[$rule_id]:$rule_id) . '</a>' . $matches[3];
968		}
969	}
970
971	return $result;
972}
973