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