File: 1.17.2a/server/base/freenats.inc.php (View as HTML)

  1: <?php // freenats.inc.php
  2: /* -------------------------------------------------------------
  3: This file is part of FreeNATS
  4: 
  5: FreeNATS is (C) Copyright 2008-2017 PurplePixie Systems
  6: 
  7: FreeNATS is free software: you can redistribute it and/or modify
  8: it under the terms of the GNU General Public License as published by
  9: the Free Software Foundation, either version 3 of the License, or
 10: (at your option) any later version.
 11: 
 12: FreeNATS is distributed in the hope that it will be useful,
 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15: GNU General Public License for more details.
 16: 
 17: You should have received a copy of the GNU General Public License
 18: along with FreeNATS.  If not, see www.gnu.org/licenses
 19: 
 20: For more information see www.purplepixie.org/freenats
 21: -------------------------------------------------------------- */
 22: 
 23: class TFreeNATS
 24: {
 25: var $init=false;
 26: var $DB;
 27: var $Cfg;
 28: var $Tests;
 29: var $Lang;
 30: var $RSS;
 31: var $Version="1.17.2";
 32: var $Release="a";
 33: var $EventHandlers=array();
 34: 
 35: var $PageErrors=array();
 36: 
 37: var $userdata = array();
 38: var $usergrouplock = array();
 39: 
 40: function TFreeNATS()
 41: 	{
 42: 	$this->Tests=new TNATS_Tests(); // need this available during the include phase pre-start
 43: 	}
 44: 
 45: function Start()
 46: 	{
 47: 	if ($this->init) return 0;
 48: 	global $BaseDir,$fnSkipSiteIncludes;
 49: 	if ( (!isset($BaseDir)) || ($BaseDir=="") ) $BaseDir="./";
 50: 	$this->DB=new TNATS_DB();
 51: 	$this->Cfg=new TNATS_Cfg();
 52: 	$this->DB->Connect();
 53: 	$this->Cfg->Load($this->DB);
 54: 	// Site Includes
 55: 	// Tests
 56: 	if ( (!isset($fnSkipSiteIncludes)) || ($fnSkipSiteIncludes === false) )
 57: 		{
 58: 	
 59: 		if ($this->Cfg->Get("site.include.tests",0)==1)
 60: 			{
 61: 			foreach(glob($BaseDir."site/tests/*.php") as $phpfile)
 62: 				{
 63: 				$this->Event("Including ".$phpfile,10,"NATS","Start");
 64: 				include_once($phpfile);
 65: 				}
 66: 			}
 67: 		// Events
 68: 		if ($this->Cfg->Get("site.include.events",0)==1)
 69: 			{
 70: 			foreach(glob($BaseDir."site/events/*.php") as $phpfile)
 71: 				{
 72: 				$this->Event("Including ".$phpfile,10,"NATS","Start");
 73: 				include_once($phpfile);
 74: 				}
 75: 			}
 76: 		}
 77: 
 78: 	// Timezones
 79: 	$zone=$this->Cfg->Get("site.timezone","");
 80: 	if ($zone != "")
 81: 		date_default_timezone_set($zone);
 82: 		
 83: 	// RSS
 84: 	$this->RSS = new NATS_RSS();
 85: 	
 86: 	// Language
 87: 	$this->Lang=new TNATS_Lang();
 88: 	if (isset($_COOKIE['fn_lang']) && ($_COOKIE['fn_lang']!="") ) $l=$_COOKIE['fn_lang'];
 89: 	else $l=$this->Cfg->Get("site.language","");
 90: 	$this->Lang->Load($l);
 91: 	
 92: 		
 93: 	$this->init=true;
 94: 	}
 95: 	
 96: function Stop()
 97: 	{
 98: 	$t=$this->Cfg->Get("freenats.tracker","");
 99: 	if ( ($t>0) && ($t!="") )
100: 		{
101: 		$day=date("Ymd");
102: 		if ($this->Cfg->Get("freenats.tracker.last","")!=$day)
103: 			{
104: 			$this->Cfg->Set("freenats.tracker.last",$day);
105: 			$this->PhoneHome();
106: 			}
107: 		}
108: 		
109: 	$this->DB->Disconnect();
110: 	$this->init=false;
111: 	}	
112: 	
113: function Event($logevent,$loglevel=1,$modid="NONE",$catid="NONE")
114: 	{
115: 	global $NATS_Session;
116: 	if ((isset($NATS_Session))&&($NATS_Session->auth)) $username=$NATS_Session->username;
117: 	else $username="";
118: 	$l=$this->Cfg->Get("log.level");
119: 	//echo "** $l **\n";
120: 	if ( $l=="" ) $l=10; // debug logging if no variable
121: 	if ( $l < $loglevel ) return false;
122: 	if (strlen($logevent)>249) $logevent=substr($logevent,0,245)."...";
123: 	$q="INSERT INTO fnlog(postedx,modid,catid,loglevel,logevent,username) VALUES(".time().",";
124: 	$q.="\"".ss($modid)."\",\"".ss($catid)."\",".ss($loglevel).",\"".ss($logevent)."\",\"".ss($username)."\")";
125: 	//echo $q;
126: 	$this->DB->Query($q,false);
127: 	}
128: 
129: function AlertAction($nodeid,$alertlevel,$change,$alerttext)
130: 	{
131: 	//echo "Called for node: ".$nodeid."\n";
132: 	if ($change==0) return false; // no change
133: 	if (trim($alerttext)=="") return false; // no text so a bogus event i.e. -1 to 0
134: 	//echo $nodeid.":".$alertlevel.":".$change.":".$alerttext."\n";
135: 	// get all the alertactions for this node id
136: 	$q="SELECT aaid FROM fnnalink WHERE nodeid=\"".ss($nodeid)."\"";
137: 	$r=$this->DB->Query($q);
138: 	while ($arow=$this->DB->Fetch_Array($r))
139: 		{
140: 		// get details for this alert action
141: 		$aq="SELECT * FROM fnalertaction WHERE aaid=".$arow['aaid']." LIMIT 0,1";
142: 		
143: 		$ar=$this->DB->Query($aq);
144: 		$aa=$this->DB->Fetch_Array($ar);
145: 		$this->DB->Free($ar);
146: 		
147: 		// UGGGGGGGG continue!!
148: 		// if the type is blank or disabled skip
149: 		if ( ($aa['atype']=="") || ($aa['atype']=="Disabled") ) continue;
150: 		// if warnings aren't set and it is a warning skip
151: 		if ( ($aa['awarnings']==0) && ($alertlevel==1) ) continue;
152: 		// if decreases aren't set and it is a decrease skip
153: 		if ( ($aa['adecrease']==0) && ($change<1) ) continue;
154: 		// if has a schedule and it dictates not to run now then skip
155: 		if (($aa['scheduleid']!=0)&&(!run_x_in_schedule(time(),$aa['scheduleid']))) continue;
156: 		
157: 		// made it this far
158: 		
159: 		$ndata=$nodeid.": ".$alerttext;
160: 		$this->ActionAddData($arow['aaid'],$ndata);
161: 		
162: 		/* // spun to ActionAddData
163: 		if ($aa['mdata']!="") $ndata=$aa['mdata']."\n".$nodeid.": ".$alerttext;
164: 		else $ndata=$nodeid.": ".$alerttext;
165: 		$uq="UPDATE fnalertaction SET mdata=\"".ss($ndata)."\" WHERE aaid=".$arow['aaid'];
166: 		//echo $uq."\n";
167: 		$this->DB->Query($uq);
168: 		*/
169: 		}
170: 	}
171: 	
172: function ActionAddData($aaid, $newmdata)
173: 	{
174: 	$q="SELECT aaid,mdata FROM fnalertaction WHERE aaid=".ss($aaid)." LIMIT 0,1";
175: 	$r=$this->DB->Query($q);
176: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
177: 	$this->DB->Free($r);
178: 	
179: 	if ($row['mdata']!="") $ndata=$row['mdata']."\n".$newmdata;
180: 	else $ndata=$newmdata;
181: 	
182: 	$uq="UPDATE fnalertaction SET mdata=\"".ss($ndata)."\" WHERE aaid=".$row['aaid'];
183: 	$this->DB->Query($uq);
184: 	return true;
185: 	}
186: 	
187: function ActionFlush()
188: 	{
189: 	global $allowed,$BaseDir; // allowed chars from screen in YA BODGE
190: 	$q="SELECT * FROM fnalertaction WHERE mdata!=\"\"";
191: 	$r=$this->DB->Query($q);
192: 	while ($row=$this->DB->Fetch_Array($r))
193: 		{
194: 			
195: 			$doalert=true;
196: 			
197: 		// clear mdata right at the start to get around duplicate emails whilst processing
198: 			$q="UPDATE fnalertaction SET mdata=\"\" WHERE aaid=".$row['aaid'];
199: 			$this->DB->Query($q);
200: 			
201: 			if ($this->DB->Affected_Rows()<=0) // already flushed or failed to flush
202: 				{
203: 				$doalert=false;
204: 				$this->Event("Alert Action Already Flushed - Skipping",8,"Flush","Action");
205: 				}
206: 			
207: 		// alert counter
208: 		$td=date("Ymd");
209: 		if ($td!=$row['ctrdate']) // new day or no flush record
210: 			{
211: 			$q="UPDATE fnalertaction SET ctrdate=\"".$td."\",ctrtoday=1 WHERE aaid=".$row['aaid'];
212: 			$this->DB->Query($q);
213: 			}
214: 		else
215: 			{
216: 			
217: 				if ( ($row['ctrlimit']==0) || ($row['ctrlimit']>$row['ctrtoday']) ) // no limit or below
218: 					{
219: 					$q="UPDATE fnalertaction SET ctrtoday=ctrtoday+1 WHERE aaid=".$row['aaid'];
220: 					$this->DB->Query($q);
221: 					}
222: 				else // at or over limit
223: 					{
224: 					$this->Event("Alert Action Limit Reached - Skipping",2,"Flush","Action");
225: 					$doalert=false;
226: 					}
227: 			
228: 			}
229: 			
230: 			
231: 		if ($row['atype']=="email")
232: 			{
233: 			if ($row['esubject']==0) $sub="";
234: 			else if ($row['esubject']==1) $sub=$this->Cfg->Get("alert.subject.short","FreeNATS Alert");
235: 			else $sub=$this->Cfg->Get("alert.subject.long","** FreeNATS Alert **");
236: 			$body="";
237: 			if ($row['etype']==0) $body=$row['mdata'];
238: 			else 
239: 				{
240: 				$body=$this->Cfg->Get("alert.body.header","FreeNATS Alert,");
241: 				$body.="\r\n\r\n".$row['mdata']."\r\n\r\n";
242: 				$body.=$this->Cfg->Get("alert.body.footer","");
243: 				$body.="\r\n-- FreeNATS @ ".nicedt(time());
244: 				}
245: 			//$tolist=preg_split("[\n\r]",$row['etolist']);
246: 			$tolist=array();
247: 			$f=0;
248: 			$tolist[0]="";
249: 			for ($a=0; $a<strlen($row['etolist']); $a++)
250: 				{
251: 				$chr=$row['etolist'][$a];
252: 				//echo $chr;
253: 				if (strpos($allowed,$chr)===false) // special char
254: 					{
255: 					$f++;
256: 					$tolist[$f]="";
257: 					}
258: 				else
259: 					{
260: 					$tolist[$f].=$chr;
261: 					}
262: 				}
263: 			
264: 			foreach($tolist as $toaddr)
265: 				{
266: 				$toaddr=nices($toaddr);
267: 				if ($toaddr!="")
268: 					{
269: 					$smtpserver=$this->Cfg->Get("mail.smtpserver","");
270: 					if ($smtpserver=="")
271: 						{
272: 						// mail() method - local delivery
273: 						$header="From: ".$row['efrom']."\r\n";
274: 						if ($doalert)
275: 							{
276: 							mail($toaddr,$sub,$body,$header);
277: 							$this->Event("Sent alert email to ".$toaddr,4,"Flush","Email");
278: 							}		
279: 						}
280: 					else // use phpmailer direct SMTP delivery
281: 						{
282: 						include_once($BaseDir."phpmailer/class.phpmailer.php");
283: 						$fromname=$this->Cfg->Get("mail.fromname","");
284: 						if ($fromname=="") $fromname="FreeNATS";
285: 						$smtpusername=$this->Cfg->Get("mail.smtpusername",""); // removed .
286: 						if ($smtpusername!="") $smtpauth=true;
287: 						else $smtpauth=false;
288: 						$smtppassword=$this->Cfg->Get("mail.smtppassword",""); // removed .
289: 						$smtphostname=$this->Cfg->Get("mail.smtphostname",""); // removed .
290: 						$smtpsec=$this->Cfg->Get("mail.smtpsecure","");
291: 						$mail=new PHPMailer();
292: 						$mail->IsSMTP();
293: 						$mail->Host=$smtpserver;
294: 						$mail->From=$row['efrom'];
295: 						$mail->FromName=$fromname;
296: 						$mail->AddAddress($toaddr);
297: 						$mail->Subject=$sub;
298: 						$mail->Body=$body;
299: 						$mail->WordWrap=50;
300: 						if ($smtphostname!="") $mail->Hostname=$smtphostname;
301: 						if ($smtpauth)
302: 							{
303: 							$mail->SMTPAuth=true;
304: 							$mail->Username=$smtpusername;
305: 							$mail->Password=$smtppassword;
306: 							}
307: 						if ($smtpsec!="") $mail->SMTPSecure=$smtpsec;
308: 						if (!$mail->Send())
309: 							{ // failed
310: 							$this->Event("phpMailer to ".$toaddr." failed",1,"Flush","Email");
311: 							$this->Event("phpMailer Error: ".$mail->ErrorInfo,1,"Flush","Email");
312: 							}
313: 						else
314: 							{
315: 							$this->Event("phpMailer Sent Email To ".$toaddr,4,"Flush","Email");
316: 							}
317: 						}
318: 						
319: 					}
320: 				}
321: 				
322: 				
323: 				
324: 			}
325: 		else if ($row['atype']=="url")
326: 			{
327: 			// url send
328: 			if ($row['etype']==0) $body=$row['mdata'];
329: 			else $body="FreeNATS Alert,\r\n".$row['mdata']."\r\n--FreeNATS @ ".nicedt(time());
330: 			
331: 			$body=urlencode($body);
332: 			$tolist=array();
333: 			$f=0;
334: 			$tolist[0]="";
335: 			for ($a=0; $a<strlen($row['etolist']); $a++)
336: 				{
337: 				$chr=$row['etolist'][$a];
338: 				//echo $chr;
339: 				if (strpos($allowed,$chr)===false) // special char
340: 					{
341: 					$f++;
342: 					$tolist[$f]="";
343: 					}
344: 				else
345: 					{
346: 					$tolist[$f].=$chr;
347: 					}
348: 				}
349: 			
350: 			foreach($tolist as $tourl)
351: 				{
352: 				if ($doalert)
353: 					{
354: 					$url=$tourl.$body;
355: 					$fp=@fopen($url,"r");
356: 					if ($fp>0) fclose($fp);
357: 					else $this->Event("URL Alert Failed ".$url,1,"Flush","URL");
358: 					$this->Event("URL Alert ".$url,4,"Flush","URL");
359: 					}
360: 				}
361: 			
362: 			
363: 			}
364: 		else if ($row['atype']=="mqueue")
365: 			{
366: 			// message queue
367: 			$eventdata=array("aaid"=>$row['aaid'],"name"=>$row['aname'],"data"=>$row['mdata']);
368: 			$result=$this->EventHandler("alert_action",$eventdata);
369: 			if ($result===false) // put the data back into the queue
370: 				{
371: 				$q="UPDATE fnalertaction SET mdata=\"".$row['mdata']."\"+mdata WHERE aaid=".$row['aaid'];
372: 				$this->DB->Query($q);
373: 				if ($this->DB->Affected_Rows()<=0)
374: 					$this->Event("Persist MDATA Failed for AAID ".$row['aaid'],2,"Flush","MQueue");
375: 				}
376: 			else $this->Event("Queue Cleared for AAID ".$row['aaid']." by Handler",4,"Flush","MQueue");
377: 			}
378: 			
379: 		}
380: 	}	
381: 
382: function GetAlerts()
383: 	{
384: 	global $NATS_Session;
385: 	$q="SELECT nodeid,alertlevel FROM fnalert WHERE closedx=0";
386: 	$r=$this->DB->Query($q);
387: 	$c=0;
388: 	$al=array();
389: 	while ($row=$this->DB->Fetch_Array($r))
390: 	{
391: 		if ($this->isUserAllowedNode($NATS_Session->username,$row['node']))
392: 		{
393: 			$al[$c]['nodeid']=$row['nodeid'];
394: 			$al[$c]['alertlevel']=$row['alertlevel'];
395: 			$c++;
396: 		}
397: 	}
398: 	if ($c>0) return $al;
399: 	else return false;
400: 	}
401: 	
402: function SetAlerts($nodeid,$alertlevel,$alerts="")
403: 	{
404: 	if ($alerts=="") $alerts=array();
405: 	// get current alert level
406: 	$q="SELECT alertlevel,nodealert FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
407: 	$r=$this->DB->Query($q);
408: 	$row=$this->DB->Fetch_Array($r);
409: 	$this->DB->Free($r);
410: 	$cal=$row['alertlevel'];
411: 	
412: 	$eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alertlevel,
413: 		"oldalertlevel"=>$cal);
414: 	$this->EventHandler("set_alerts",$eventdata);
415: 		
416: 	if ($alertlevel!=$cal)
417: 		{
418: 		// update table
419: 		$q="UPDATE fnnode SET alertlevel=".ss($alertlevel)." WHERE nodeid=\"".ss($nodeid)."\"";
420: 		$this->DB->Query($q);
421: 		}
422: 		
423: 	// do not continue if node alert isn't set
424: 	if ($row['nodealert']!=1) return 0;
425: 	// or if untested
426: 	if ($alertlevel<0) return 0;
427: 		
428: 	// ALERTS
429: 	// is there an existing alert for this node
430: 	$q="SELECT alertid,alertlevel FROM fnalert WHERE nodeid=\"".ss($nodeid)."\" AND closedx=0";
431: 	$r=$this->DB->Query($q);
432: 	if ($row=$this->DB->Fetch_Array($r))
433: 		{ // yes there is
434: 		// if new alert level is 0 let's close it
435: 		if ($alertlevel==0)
436: 			{
437: 			$alertid=$row['alertid'];
438: 			$q="UPDATE fnalert SET closedx=".time()." WHERE alertid=".$row['alertid'];
439: 			$this->DB->Query($q);
440: 			$closetext=$this->Cfg->Get("site.text.closed","Alert Closed");
441: 			if (is_array($alerts)) $alerts[]=$closetext;
442: 			else
443: 				{
444: 				$alerts=array($alerts); // add as first element to new array
445: 				$alerts[]=$closetext;
446: 				}
447: 			$eventdata=array("nodeid"=>$nodeid);
448: 			$this->EventHandler("alert_close",$eventdata);
449: 			}
450: 		else
451: 			{
452: 			$alertid=$row['alertid'];
453: 			// otherwise update the alert to the new value (was: regardless, now just if not a 0)
454: 			$q="UPDATE fnalert SET alertlevel=".ss($alertlevel)." WHERE alertid=".$alertid;
455: 			$this->DB->Query($q);
456: 			}
457: 		}
458: 	else
459: 		{ // no there's not
460: 		$cal=0; // the cal (current alert level) goes to zero if it's a new alert so alert_actions fire ok
461: 		if ($alertlevel>0) // only if an actual alert
462: 			{
463: 			$q="INSERT INTO fnalert(nodeid,alertlevel,openedx) VALUES(";
464: 			$q.="\"".ss($nodeid)."\",".ss($alertlevel).",".time().")";
465: 			$this->DB->Query($q);
466: 			$alertid=$this->DB->Insert_Id();
467: 			$eventdata=array("nodeid"=>$nodeid);
468: 			$this->EventHandler("alert_open",$eventdata);
469: 			}
470: 		}
471: 	// ALERT LOG with $alertid
472: 	$t=time();
473: 	$at="";
474: 	if (is_array($alerts))
475: 		{
476: 		foreach($alerts as $alert)
477: 			{
478: 			if (isset($alertid)) // misses on manual runs methinx
479: 				{
480: 				if ($at!="") $at.=", ";
481: 				$at.=$alert;
482: 				//echo $at."\n";
483: 				$iq="INSERT INTO fnalertlog(alertid,postedx,logentry) VALUES(";
484: 				$iq.=$alertid.",".$t.",\"".ss($alert)."\")";
485: 				//echo $iq;
486: 				$this->DB->Query($iq);
487: 				}
488: 			}
489: 		}
490: 		
491: 	$this->AlertAction($nodeid,$alertlevel,$alertlevel-$cal,$at);
492: 	
493: 		
494: 		
495: 	}
496: 
497: function NodeAlertLevel($nodeid)
498: 	{
499: 	$q="SELECT alertlevel FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
500: 	$r=$this->DB->Query($q);
501: 	if ($row=$this->DB->Fetch_Array($r)) return $row['alertlevel'];
502: 	else return -1;
503: 	}	
504: 
505: function GroupAlertLevel($groupid)
506: 	{
507: 	$lvl=-1;
508: 	$q="SELECT nodeid FROM fngrouplink WHERE groupid=\"".ss($groupid)."\"";
509: 	$r=$this->DB->Query($q);
510: 	while ($row=$this->DB->Fetch_Array($r))
511: 		{
512: 		$nl=$this->NodeAlertLevel($row['nodeid']);
513: 		if ($nl>$lvl) $lvl=$nl;
514: 		}
515: 	$this->DB->Free($r);
516: 	return $lvl;
517: 	}
518: 	
519: function PhoneHome($mode=0,$type="ping") // 0 - php, 1 - html, 2 - data
520: {
521: if ($mode<2)
522: 	{
523: 	$qs="?type=".$type."&data=v=".$this->Version;
524: 	if (isset($_SERVER['REMOTE_ADDR']))
525: 		$qs.=",ip=".$_SERVER['REMOTE_ADDR'];
526: 	$ploc="http://www.purplepixie.org/freenats/report/";
527: 	if ($mode==1) $ploc.="ping.html";
528: 	else $ploc.="ping.php";
529: 	
530: 	$ploc.=$qs;
531: 	
532: 	$lp=@fopen($ploc,"r");
533: 	if ($lp>0) @fclose($lp);
534: 	}
535: else
536: 	{
537: 	// data post -- !!
538: 	}
539: }
540: 
541: function GetNode($nodeid)
542: 	{
543: 	$return_row=false;
544: 	$q="SELECT * FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
545: 	$r=$this->DB->Query($q);
546: 	if ($row=$this->DB->Fetch_Array($r))
547: 		$return_row=true;
548: 		
549: 	$this->DB->Free($r);
550: 	if ($return_row) // found a valid
551: 		{
552: 		if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
553: 		else $row['name']=$row['nodeid'];
554: 		
555: 		$row['alerttext']=oText($row['alertlevel']); // textual alert status
556: 		
557: 		$row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
558: 		$row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
559: 		
560: 		// protection
561: 		$row['nskey']="";
562: 		
563: 		return $row;
564: 		}
565: 	else
566: 		return false; // or failed
567: 	}
568: 	
569: function GetNodes()
570: {
571: 	$out=array();
572: 	$q="SELECT * FROM fnnode";
573: 	$r=$this->DB->Query($q);
574: 	
575: 	while ($row=$this->DB->Fetch_Array($r))
576: 	{
577: 		if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
578: 		else $row['name']=$row['nodeid'];
579: 		
580: 		$row['alerttext']=oText($row['alertlevel']); // textual alert status
581: 		
582: 		$row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
583: 		$row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
584: 		
585: 		// protection
586: 		$row['nskey']="";
587: 		
588: 		$out[$row['nodeid']]=$row;
589: 	}
590: 	$this->DB->Free($r);
591: 	
592: 	return $out;
593: }
594: 
595: 	
596: function GetNodeTests($nodeid)
597: 	{ // returns an array of testids for the node (enabled tests only)
598: 	$tests=array();
599: 	
600: 	// local tests
601: 	$q="SELECT localtestid FROM fnlocaltest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY localtestid ASC";
602: 	$r=$this->DB->Query($q);
603: 	while ($row=$this->DB->Fetch_Array($r))
604: 		{
605: 		$tests[]="L".$row['localtestid'];
606: 		}
607: 	$this->DB->Free($r);
608: 	
609: 	// nodeside
610: 	$q="SELECT nstestid FROM fnnstest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY testtype ASC";
611: 	$r=$this->DB->Query($q);
612: 	while ($row=$this->DB->Fetch_Array($r))
613: 		{
614: 		$tests[]="N".$row['nstestid'];
615: 		}
616: 	$this->DB->Free($r);
617: 	
618: 	return $tests;
619: 	}
620: 	
621: function SetNode($nodeid,$data)
622: 	{
623: 	$q="UPDATE fnnode SET ";
624: 	$first=true;
625: 	foreach($data as $key => $val)
626: 		{
627: 		if ($first) $first=false;
628: 		else $q.=",";
629: 		$q.=ss($key)."=\"".ss($val)."\"";
630: 		}
631: 	$q.=" WHERE nodeid=\"".ss($nodeid)."\"";
632: 	$this->DB->Query($q);
633: 	if ($this->DB->Affected_Rows()>0) return true;
634: 	
635: 	if ($this->DB->Error()) // query failed
636: 		{
637: 		$errstr1="Query Failed: ".$q;
638: 		$errstr2="Query Failed: ".$this->DB->Error_String();
639: 		$this->Event($errstr1,2,"Node","Set");
640: 		$this->Event($errstr1,2,"Node","Set");
641: 		return false;
642: 		}
643: 	return true; // query succeeded but nothing was updated
644: 	}
645: 	
646: function EnableNode($nodeid,$enabled=true)
647: 	{
648: 	if ($enabled) $ne=1;
649: 	else $ne=0;
650: 	$data=array("nodeenabled"=>$ne);
651: 	return $this->SetNode($nodeid,$data);
652: 	}
653: 	
654: function DisableNode($nodeid)
655: 	{
656: 	return $this->EnableNode($nodeid,false);
657: 	}
658: 	
659: function SetNodeSchedule($nodeid,$scheduleid)
660: 	{
661: 	$data=array("scheduleid"=>$scheduleid);
662: 	return $this->SetNode($nodeid,$data);
663: 	}
664: 	
665: function GetGroup($groupid)
666: 	{
667: 	$q="SELECT * FROM fngroup WHERE groupid=".ss($groupid)." LIMIT 0,1";
668: 	$r=$this->DB->Query($q);
669: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
670: 	
671: 	$this->DB->Free($r);
672: 	$row['alertlevel']=$this->GroupAlertLevel($groupid);
673: 	$row['alerttext']=oText($row['alertlevel']);
674: 	return $row;
675: 	}
676: 	
677: function GetGroups()
678: {
679: 	$out=array();
680: 	$q="SELECT * FROM fngroup";
681: 	$r=$this->DB->Query($q);
682: 	
683: 	while ($row=$this->DB->Fetch_Array($r))
684: 	{
685: 		$row['alertlevel']=$this->GroupAlertLevel($row['groupid']);
686: 		$row['alerttext']=oText($row['alertlevel']);
687: 		$out[$row['groupid']]=$row;
688: 	}
689: 	
690: 	$this->DB->Free($r);
691: 	return $out;
692: }
693: 	
694: function GetTest($testid,$protect=false)
695: 	{
696: 	if ($testid=="") return false;
697: 	$class=$testid[0];
698: 	if (is_numeric($class))
699: 		{
700: 		// test ID will stay the same
701: 		$class="L";
702: 		$anytestid=$testid;
703: 		}
704: 	else
705: 		{
706: 		//$testid=substr($testid,1); // as it will here also so direct use to graphs can be made
707: 		$anytestid=substr($testid,1); // the classless version
708: 		}
709: 		
710: 	$q="";
711: 	switch($class)
712: 		{
713: 		case "L": // local tests 
714: 			$q="SELECT * FROM fnlocaltest WHERE localtestid=".ss($anytestid)." LIMIT 0,1";
715: 			break;
716: 		case "N": // node-side test
717: 			$q="SELECT * FROM fnnstest WHERE nstestid=".ss($anytestid)." LIMIT 0,1";
718: 			break;
719: 		default:
720: 			return false; // can't lookup this class
721: 		}
722: 		
723: 	if ($q=="") return false;
724: 	
725: 	$r=$this->DB->Query($q);
726: 	
727: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
728: 	
729: 	$row['class']=$class;
730: 	$row['testid']=$testid;
731: 	$row['anytestid']=$anytestid;
732: 	$row['alerttext']=oText($row['alertlevel']);
733: 	$row['lastrundt']=nicedt($row['lastrunx']);
734: 	$row['lastrunago']=dtago($row['lastrunx'],false);
735: 	
736: 	if  ($row['testname']!="")  $row['name']=$row['testname'];
737: 	else
738: 			{
739: 			if ($class=="L")
740: 				{
741: 				$row['name']=lText($row['testtype']); // TODO OTHER TESTS
742: 				if ($row['testparam']!="") $row['name'].=" (".$row['testparam'].")";
743: 				}
744: 			else if ($class=="N")
745: 				{
746: 				if ($row['testdesc']!="") $row['name']=$row['testdesc'];
747: 				else $row['name']=$row['testtype'];
748: 				}
749: 			}
750: 			
751: 	if ($protect&&($class=="L")) // module test protection
752: 		{
753: 		if ($this->Tests->Exists($row['testtype'])) // in the module register
754: 			{
755: 			$this->Tests->Tests[$row['testtype']]->Create();
756: 			$this->Tests->Tests[$row['testtype']]->instance->ProtectOutput($row);
757: 			}
758: 		}
759: 	
760: 	$this->DB->Free($r);
761: 	
762: 	return $row;
763: 	}
764: 
765: 	
766: function DeleteTest($testid)
767: 	{
768: 	if ($testid=="") return false;
769: 	$class=$testid[0];
770: 	if (is_numeric($class))
771: 		{
772: 		// test ID will stay the same
773: 		$class="L";
774: 		$anytestid=$testid;
775: 		}
776: 	else
777: 		{
778: 		$anytestid=substr($testid,1); // the classless version
779: 		}
780: 		
781: 	$q="";
782: 	switch($class)
783: 		{
784: 		case "L": // local tests 
785: 			$q="DELETE FROM fnlocaltest WHERE localtestid=".ss($anytestid);
786: 			break;
787: 		case "N": // node-side test
788: 			$q="DELETE FROM fnnstest WHERE nstestid=".ss($anytestid);
789: 			break;
790: 		default:
791: 			return false; // can't lookup this class
792: 		}
793: 		
794: 	if ($q=="") return false;
795: 	
796: 	$this->DB->Query($q);
797: 	$tests=$this->DB->Affected_Rows();
798: 	
799: 	$rq="DELETE FROM fnrecord WHERE testid=\"".ss($testid)."\"";
800: 	$this->DB->Query($rq);
801: 	$records=$this->DB->Affected_Rows();
802: 	
803: 	$eq="DELETE FROM fneval WHERE testid=\"".ss($testid)."\"";
804: 	$this->DB->Query($eq);
805: 	$eval=$this->DB->Affected_Rows();
806: 	
807: 	$s="Deleted test ".$testid." (".$tests." tests, ".$records." records, ".$eval." evaluators)";
808: 	$this->Event($s,6,"Test","Delete");
809: 	}
810: 	
811: 	
812: 	
813: function InvalidateTest($testid,$rightnow=false)
814: 	{
815: 	$class=$testid[0];
816: 	if (is_numeric($class)) $class="L";
817: 	else $testid=substr($testid,1);
818: 	if ($rightnow)
819: 		{
820: 		$nextx=time();
821: 		$q="UPDATE ";
822: 		if ($class=="L") $q.="fnlocaltest";
823: 		// other ones here
824: 		
825: 		$q.=" SET nextrunx=".$nextx." WHERE ";
826: 		
827: 		if ($class=="L") $q.="localtestid=".$testid;
828: 		// other ones here
829: 		
830: 		$this->DB->Query($q);
831: 		return true;
832: 		}
833: 	// otherwise use it's interval
834: 	$q="SELECT testinterval FROM ";
835: 	
836: 	if ($class=="L") $q.="fnlocaltest WHERE localtestid=";
837: 	// other ones here
838: 	
839: 	$q.=$testid;
840: 	$r=$this->DB->Query($q);
841: 	if ($row=$this->DB->Fetch_Array($r))
842: 		{
843: 		$this->DB->Free($r);
844: 		$nextx=next_run_x($row['testinterval']);
845: 		$q="UPDATE ";
846: 		if ($class=="L") $q.="fnlocaltest";
847: 		// other ones here
848: 		
849: 		$q.=" SET nextrunx=".$nextx." WHERE ";
850: 		
851: 		if ($class=="L") $q.="localtestid=".$testid;
852: 		// other ones here
853: 		
854: 		$this->DB->Query($q);
855: 		return true;
856: 		}
857: 	return false;
858: 	}		
859: 	
860: function InvalidateNode($nodeid,$rightnow=false,$testsaswell=false)
861: 	{
862: 	if ($rightnow)
863: 		{
864: 		$nextx=time();
865: 		$q="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
866: 		$this->DB->Query($q);
867: 		if ($testsaswell)
868: 			{
869: 			$q="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
870: 			$this->DB->Query($q);
871: 			}
872: 		return true;
873: 		}
874: 	// otherwise set to it's interval
875: 	$q="SELECT testinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
876: 	$r=$this->DB->Query($q);
877: 	if ($row=$this->DB->Fetch_Array($r))
878: 		{
879: 		$nextx=next_run_x($row['testinterval']);
880: 		$uq="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
881: 		$this->DB->Query($uq);
882: 		$this->DB->Free($r);
883: 		if ($testsaswell)
884: 			{
885: 			$uq="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
886: 			$this->DB->Query($uq);
887: 			}
888: 		return true;
889: 		}
890: 	return false;
891: 	}
892: 	
893: 	
894: function NodeSide_Pull($nodeid)
895: 	{
896: 	$eventdata=array("nodeid"=>$nodeid,"success"=>false);
897: 	$q="SELECT nsenabled,nspullenabled,nsurl,nskey,nsinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
898: 	$r=$this->DB->Query($q);
899: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
900: 	
901: 	$this->DB->Free($r);
902: 	
903: 	$url=$row['nsurl'];
904: 	if ($row['nskey']!="") $url.="?nodekey=".$row['nskey'];
905: 	//echo $url."\n";
906: 	$this->Event("NodeSide_Pull Started for ".$nodeid,10,"Node","Pull");
907: 	
908: 	$xmlobj=new TNodeXML();
909: 	
910: 	$fp=@fopen($url,"r");
911: 	if ($fp<=0)
912: 		{
913: 		$this->Event("Pull Failed URL ".$url,1,"Node","Pull");
914: 		$this->EventHandler("nodeside_pull",$eventdata);
915: 		return false;
916: 		}
917: 	$xml="";
918: 	while (!feof($fp))
919: 		{
920: 		$xml.=fgets($fp,4096);
921: 		}
922: 	if ($xml=="")
923: 		{
924: 		$this->EventHandler("nodeside_pull",$eventdata);
925: 		return false;
926: 		}
927: 	
928: 	//echo $xml;
929: 	
930: 	$result=$xmlobj->Parse($xml);
931: 	
932: 	if ($xmlobj->Error()!="")
933: 		{
934: 		$this->Event("NodeXML Error: ".$xmlobj->Error(),1,"Node","Pull");
935: 		$this->EventHandler("nodeside_pull",$eventdata);
936: 		return false;
937: 		}
938: 	$this->Event("NodeSide_Pull Fetched ".$xmlobj->Tests." tests for ".$nodeid,10,"Node","Pull");
939: 	// Now just to actually process it...
940: 	$eventdata['success']=true;
941: 	$this->EventHandler("nodeside_pull",$eventdata);
942: 	$this->NodeSide_Process($nodeid,$xmlobj);
943: 	return true;
944: 	}	
945: 	
946: function NodeSide_Process($nodeid,&$xmlobj)
947: 	{ // nodeid + takes a TNodeXML Object
948: 	$alvl=0;
949: 	$this->Event("NodeSide_Process for ".$nodeid,10,"Node","Pull");
950: 	$q="SELECT * FROM fnnstest WHERE nodeid=\"".ss($nodeid)."\"";
951: 	$r=$this->DB->Query($q);
952: 	$tests=array();
953: 	while ($row=$this->DB->Fetch_Array($r))
954: 		{
955: 		$tests[$row['testtype']]=$row;
956: 		if (isset($xmlobj->Catalogue[$row['testtype']]))
957: 			{ // this test is in the DB and catalogue
958: 			$tests[$row['testtype']]['incat']=true;
959: 			if ($row['testenabled']==1) // it is enabled - so we test it
960: 				{
961: 				if ($row['simpleeval']==1) $level=$xmlobj->Catalogue[$row['testtype']]['ALERTLEVEL']; // use provided level
962: 				else $level=nats_eval("N".$row['nstestid'],$xmlobj->Catalogue[$row['testtype']]['VALUE']);
963: 				$dbs="Nodeside ".$row['testtype']." on ".$row['nodeid']." = ".$level;
964: 				if ($level==0) $debuglev=8;
965: 				else if ($level>0) $debuglev=5;
966: 				else $debuglev=2;
967: 				$this->Event($dbs,$debuglev,"Node","Process");
968: 				
969: 				if ($level>$alvl) $alvl=$level;
970: 				
971: 				if ($row['testrecord']==1) // record it
972: 					{
973: 					$testvalue=$xmlobj->Catalogue[$row['testtype']]['VALUE'];
974: 					$testvalue=str_replace(",",".",$testvalue);
975: 					if (!is_numeric($testvalue)) $testvalue=0;
976: 					$iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
977: 					$iq.="\"N".$row['nstestid']."\",".$level.",".time().",\"".$row['nodeid']."\",".$testvalue.")";
978: 					$this->DB->Query($iq);
979: 					if ($this->DB->Affected_Rows()<=0)
980: 						$this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
981: 					}
982: 					
983: 				// We don't do any alerting here - the tester will do that for us!
984: 				$uq="UPDATE fnnstest SET lastrunx=".time().",lastvalue=\"".ss($xmlobj->Catalogue[$row['testtype']]['VALUE'])."\",alertlevel=".$level." ";
985: 				$uq.="WHERE nstestid=".$row['nstestid'];
986: 				$this->DB->Query($uq);
987: 				if ($this->DB->Affected_Rows()<=0)
988: 						$this->Event("Nodeside ".$row['testtype']." Failed to Update or Same Values",5,"Node","Process");
989: 				
990: 				}
991: 					
992: 			// check to see if the desc has changed
993: 			if ($row['testdesc']!=$xmlobj->Catalogue[$row['testtype']]['DESC'])
994: 				{
995: 				$duq="UPDATE fnnstest SET testdesc=\"".ss($xmlobj->Catalogue[$row['testtype']]['DESC'])."\" WHERE nstestid=".$row['nstestid'];
996: 				$this->DB->Query($duq);
997: 				}
998: 				
999: 			}
1000: 		else
1001: 			{
1002: 			// test in the DB but NOT in the catalogue
1003: 			//$xmlobj->Catalogue[$row['testtype']]['incat']=false;
1004: 			if ($row['testenabled']==1)
1005: 				{ // enabled so shown in lists etc
1006: 				// Update it to show failed status
1007: 				$this->Event("No nodeside data for test N".$row['nstestid'],3,"Node","Process");
1008: 				$uq="UPDATE fnnstest SET alertlevel=2,lastvalue=-1 WHERE nstestid=".$row['nstestid'];
1009: 				$this->DB->Query($uq);
1010: 				$alvl=2;
1011: 				if ($row['testrecord']==1) // record it
1012: 					{
1013: 					$testvalue=-1;
1014: 					$iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
1015: 					$iq.="\"N".$row['nstestid']."\",2,".time().",\"".$row['nodeid']."\",".$testvalue.")";
1016: 					$this->DB->Query($iq);
1017: 					if ($this->DB->Affected_Rows()<=0)
1018: 						$this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
1019: 					}
1020: 				}
1021: 			else // not enabled so simply delete
1022: 				{
1023: 				$this->DeleteTest("N".$row['nstestid']);
1024: 				}
1025: 			}
1026: 		}
1027: 	$this->DB->Free($r);
1028: 	
1029: 	
1030: 	// and finally we look for new tests i.e. in the cat but not in the DB
1031: 	foreach($xmlobj->Catalogue as $val)
1032: 		{
1033: 		$key=$val['NAME'];
1034: 		if (!isset($tests[$key])) // not in the DB
1035: 			{
1036: 			$q="INSERT INTO fnnstest(nodeid,testtype,testdesc,lastvalue,lastrunx,alertlevel) ";
1037: 			$q.="VALUES(\"".ss($nodeid)."\",\"".$key."\",\"".ss($val['DESC'])."\",\"".ss($val['VALUE'])."\",".time().",".ss($val['ALERTLEVEL']).")";
1038: 			//echo $q."<br>";
1039: 			$this->DB->Query($q);
1040: 			}
1041: 		}
1042: 		
1043: 	$eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alvl);
1044: 	$this->EventHandler("nodeside_process",$eventdata);
1045: 	
1046: 	
1047: 	}
1048: 	
1049: 	
1050: function AddEventHandler($event,$function)
1051: {
1052: 	if (!isset($this->EventHandlers[$event])) $this->EventHandlers[$event]=array();
1053: 	$this->EventHandlers[$event][]=$function;
1054: }
1055: 
1056: function EventHandler($event,$data)
1057: {
1058: 	$res=false;
1059: 	if ( isset($data) && is_array($data) ) $data['event']=$event;
1060: 	
1061: 	if (isset($this->EventHandlers[$event])) // handler(s) exist
1062: 	{
1063: 	for($a=0; $a<count($this->EventHandlers[$event]); $a++)
1064: 		{
1065: 		if (function_exists($this->EventHandlers[$event][$a]))
1066: 			{
1067: 			$this->Event("Event ".$event." -> ".$this->EventHandlers[$event][$a],6,"Event","Handler");
1068: 			if($this->EventHandlers[$event][$a]($data)) $res=true; // persist true only
1069: 			}
1070: 		else
1071: 			{
1072: 			$t="Illegal Handler ".$this->EventHandlers[$event][$a]." for ".$event;
1073: 			$this->Event($t,2,"Event","Handler");
1074: 			//return false;
1075: 			}
1076: 		}
1077: 	}
1078: 	else return $res;
1079: }
1080: 
1081: function StripGPC($data)
1082: {
1083: 	if (get_magic_quotes_gpc()) return stripslashes($data);
1084: 	else return $data;
1085: }
1086: 
1087: function PageError($code,$desc)
1088: {
1089: 	$this->PageErrors[]=array( "code" => $code, "desc" => $desc );
1090: }
1091: 
1092: function isUserRestricted($username)
1093: {
1094: 	if (!isset($this->userdata[$username]))
1095: 	{
1096: 		$q="SELECT * FROM fnuser WHERE username=\"".ss($username)."\" LIMIT 0,1";
1097: 		$r=$this->DB->Query($q);
1098: 		if ($u=$this->DB->Fetch_Array($r))
1099: 			$this->userdata[$username]=$u;
1100: 		else
1101: 			return false;
1102: 		$this->DB->Free($r);
1103: 	}
1104: 
1105: 	// If user is a normal user & restricted then YES
1106: 	if ($this->userdata[$username]['userlevel']<2 && $this->userdata[$username]['grouplock'])
1107: 		return true;
1108: 	return false;
1109: }
1110: 
1111: function isUserAllowedGroup($username, $groupid)
1112: {
1113: 	if (!$this->isUserRestricted($username)) return true;
1114: 
1115: 	if (!isset($this->usergrouplock[$username]))
1116: 	{
1117: 		$q="SELECT * FROM fngrouplock WHERE username=\"".ss($username)."\"";
1118: 		$r=$this->DB->Query($q);
1119: 		$this->usergrouplock[$username]=array();
1120: 		while($row=$this->DB->Fetch_Array($r))
1121: 			$this->usergrouplock[$username][]=$row['groupid'];
1122: 	}
1123: 
1124: 	if (in_array($groupid,$this->usergrouplock[$username]))
1125: 		return true;
1126: 	return false;
1127: }
1128: 
1129: function isUserAllowedNode($username, $nodeid)
1130: {
1131: 	if (!$this->isUserRestricted($username)) return true;
1132: 
1133: 	$q="SELECT groupid FROM fngrouplink WHERE nodeid=\"".ss($nodeid)."\"";
1134: 	$r=$this->DB->Query($q);
1135: 	while ($row=$this->DB->Fetch_Array($r))
1136: 	{
1137: 		if ($this->isUserAllowedGroup($username, $row['groupid']))
1138: 			return true;
1139: 	}
1140: 
1141: 	return false;
1142: }
1143: 	
1144: }
1145: ?>
1146: