File: 1.15.0a/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-2016 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.15.0";
 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: 						$smtpsec=$this->Cfg->Get("mail.smtpsecure","");
283: 						$mail=new PHPMailer();
284: 						$mail->IsSMTP();
285: 						$mail->Host=$smtpserver;
286: 						$mail->From=$row['efrom'];
287: 						$mail->FromName=$fromname;
288: 						$mail->AddAddress($toaddr);
289: 						$mail->Subject=$sub;
290: 						$mail->Body=$body;
291: 						$mail->WordWrap=50;
292: 						if ($smtphostname!="") $mail->Hostname=$smtphostname;
293: 						if ($smtpauth)
294: 							{
295: 							$mail->SMTPAuth=true;
296: 							$mail->Username=$smtpusername;
297: 							$mail->Password=$smtppassword;
298: 							}
299: 						if ($smtpsec!="") $mail->SMTPSecure=$smtpsec;
300: 						if (!$mail->Send())
301: 							{ // failed
302: 							$this->Event("phpMailer to ".$toaddr." failed",1,"Flush","Email");
303: 							$this->Event("phpMailer Error: ".$mail->ErrorInfo,1,"Flush","Email");
304: 							}
305: 						else
306: 							{
307: 							$this->Event("phpMailer Sent Email To ".$toaddr,4,"Flush","Email");
308: 							}
309: 						}
310: 						
311: 					}
312: 				}
313: 				
314: 				
315: 				
316: 			}
317: 		else if ($row['atype']=="url")
318: 			{
319: 			// url send
320: 			if ($row['etype']==0) $body=$row['mdata'];
321: 			else $body="FreeNATS Alert,\r\n".$row['mdata']."\r\n--FreeNATS @ ".nicedt(time());
322: 			
323: 			$body=urlencode($body);
324: 			$tolist=array();
325: 			$f=0;
326: 			$tolist[0]="";
327: 			for ($a=0; $a<strlen($row['etolist']); $a++)
328: 				{
329: 				$chr=$row['etolist'][$a];
330: 				//echo $chr;
331: 				if (strpos($allowed,$chr)===false) // special char
332: 					{
333: 					$f++;
334: 					$tolist[$f]="";
335: 					}
336: 				else
337: 					{
338: 					$tolist[$f].=$chr;
339: 					}
340: 				}
341: 			
342: 			foreach($tolist as $tourl)
343: 				{
344: 				if ($doalert)
345: 					{
346: 					$url=$tourl.$body;
347: 					$fp=@fopen($url,"r");
348: 					if ($fp>0) fclose($fp);
349: 					else $this->Event("URL Alert Failed ".$url,1,"Flush","URL");
350: 					$this->Event("URL Alert ".$url,4,"Flush","URL");
351: 					}
352: 				}
353: 			
354: 			
355: 			}
356: 		else if ($row['atype']=="mqueue")
357: 			{
358: 			// message queue
359: 			$eventdata=array("aaid"=>$row['aaid'],"name"=>$row['aname'],"data"=>$row['mdata']);
360: 			$result=$this->EventHandler("alert_action",$eventdata);
361: 			if ($result===false) // put the data back into the queue
362: 				{
363: 				$q="UPDATE fnalertaction SET mdata=\"".$row['mdata']."\"+mdata WHERE aaid=".$row['aaid'];
364: 				$this->DB->Query($q);
365: 				if ($this->DB->Affected_Rows()<=0)
366: 					$this->Event("Persist MDATA Failed for AAID ".$row['aaid'],2,"Flush","MQueue");
367: 				}
368: 			else $this->Event("Queue Cleared for AAID ".$row['aaid']." by Handler",4,"Flush","MQueue");
369: 			}
370: 			
371: 		}
372: 	}	
373: 
374: function GetAlerts()
375: 	{
376: 	$q="SELECT nodeid,alertlevel FROM fnalert WHERE closedx=0";
377: 	$r=$this->DB->Query($q);
378: 	$c=0;
379: 	$al=array();
380: 	while ($row=$this->DB->Fetch_Array($r))
381: 		{
382: 		$al[$c]['nodeid']=$row['nodeid'];
383: 		$al[$c]['alertlevel']=$row['alertlevel'];
384: 		$c++;
385: 		}
386: 	if ($c>0) return $al;
387: 	else return false;
388: 	}
389: 	
390: function SetAlerts($nodeid,$alertlevel,$alerts="")
391: 	{
392: 	if ($alerts=="") $alerts=array();
393: 	// get current alert level
394: 	$q="SELECT alertlevel,nodealert FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
395: 	$r=$this->DB->Query($q);
396: 	$row=$this->DB->Fetch_Array($r);
397: 	$this->DB->Free($r);
398: 	$cal=$row['alertlevel'];
399: 	
400: 	$eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alertlevel,
401: 		"oldalertlevel"=>$cal);
402: 	$this->EventHandler("set_alerts",$eventdata);
403: 		
404: 	if ($alertlevel!=$cal)
405: 		{
406: 		// update table
407: 		$q="UPDATE fnnode SET alertlevel=".ss($alertlevel)." WHERE nodeid=\"".ss($nodeid)."\"";
408: 		$this->DB->Query($q);
409: 		}
410: 		
411: 	// do not continue if node alert isn't set
412: 	if ($row['nodealert']!=1) return 0;
413: 	// or if untested
414: 	if ($alertlevel<0) return 0;
415: 		
416: 	// ALERTS
417: 	// is there an existing alert for this node
418: 	$q="SELECT alertid,alertlevel FROM fnalert WHERE nodeid=\"".ss($nodeid)."\" AND closedx=0";
419: 	$r=$this->DB->Query($q);
420: 	if ($row=$this->DB->Fetch_Array($r))
421: 		{ // yes there is
422: 		// if new alert level is 0 let's close it
423: 		if ($alertlevel==0)
424: 			{
425: 			$alertid=$row['alertid'];
426: 			$q="UPDATE fnalert SET closedx=".time()." WHERE alertid=".$row['alertid'];
427: 			$this->DB->Query($q);
428: 			$closetext=$this->Cfg->Get("site.text.closed","Alert Closed");
429: 			if (is_array($alerts)) $alerts[]=$closetext;
430: 			else
431: 				{
432: 				$alerts=array($alerts); // add as first element to new array
433: 				$alerts[]=$closetext;
434: 				}
435: 			$eventdata=array("nodeid"=>$nodeid);
436: 			$this->EventHandler("alert_close",$eventdata);
437: 			}
438: 		else
439: 			{
440: 			$alertid=$row['alertid'];
441: 			// otherwise update the alert to the new value (was: regardless, now just if not a 0)
442: 			$q="UPDATE fnalert SET alertlevel=".ss($alertlevel)." WHERE alertid=".$alertid;
443: 			$this->DB->Query($q);
444: 			}
445: 		}
446: 	else
447: 		{ // no there's not
448: 		$cal=0; // the cal (current alert level) goes to zero if it's a new alert so alert_actions fire ok
449: 		if ($alertlevel>0) // only if an actual alert
450: 			{
451: 			$q="INSERT INTO fnalert(nodeid,alertlevel,openedx) VALUES(";
452: 			$q.="\"".ss($nodeid)."\",".ss($alertlevel).",".time().")";
453: 			$this->DB->Query($q);
454: 			$alertid=$this->DB->Insert_Id();
455: 			$eventdata=array("nodeid"=>$nodeid);
456: 			$this->EventHandler("alert_open",$eventdata);
457: 			}
458: 		}
459: 	// ALERT LOG with $alertid
460: 	$t=time();
461: 	$at="";
462: 	if (is_array($alerts))
463: 		{
464: 		foreach($alerts as $alert)
465: 			{
466: 			if (isset($alertid)) // misses on manual runs methinx
467: 				{
468: 				if ($at!="") $at.=", ";
469: 				$at.=$alert;
470: 				//echo $at."\n";
471: 				$iq="INSERT INTO fnalertlog(alertid,postedx,logentry) VALUES(";
472: 				$iq.=$alertid.",".$t.",\"".ss($alert)."\")";
473: 				//echo $iq;
474: 				$this->DB->Query($iq);
475: 				}
476: 			}
477: 		}
478: 		
479: 	$this->AlertAction($nodeid,$alertlevel,$alertlevel-$cal,$at);
480: 	
481: 		
482: 		
483: 	}
484: 
485: function NodeAlertLevel($nodeid)
486: 	{
487: 	$q="SELECT alertlevel FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
488: 	$r=$this->DB->Query($q);
489: 	if ($row=$this->DB->Fetch_Array($r)) return $row['alertlevel'];
490: 	else return -1;
491: 	}	
492: 
493: function GroupAlertLevel($groupid)
494: 	{
495: 	$lvl=-1;
496: 	$q="SELECT nodeid FROM fngrouplink WHERE groupid=\"".ss($groupid)."\"";
497: 	$r=$this->DB->Query($q);
498: 	while ($row=$this->DB->Fetch_Array($r))
499: 		{
500: 		$nl=$this->NodeAlertLevel($row['nodeid']);
501: 		if ($nl>$lvl) $lvl=$nl;
502: 		}
503: 	$this->DB->Free($r);
504: 	return $lvl;
505: 	}
506: 	
507: function PhoneHome($mode=0,$type="ping") // 0 - php, 1 - html, 2 - data
508: {
509: if ($mode<2)
510: 	{
511: 	$qs="?type=".$type."&data=v=".$this->Version;
512: 	if (isset($_SERVER['REMOTE_ADDR']))
513: 		$qs.=",ip=".$_SERVER['REMOTE_ADDR'];
514: 	$ploc="http://www.purplepixie.org/freenats/report/";
515: 	if ($mode==1) $ploc.="ping.html";
516: 	else $ploc.="ping.php";
517: 	
518: 	$ploc.=$qs;
519: 	
520: 	$lp=@fopen($ploc,"r");
521: 	if ($lp>0) @fclose($lp);
522: 	}
523: else
524: 	{
525: 	// data post -- !!
526: 	}
527: }
528: 
529: function GetNode($nodeid)
530: 	{
531: 	$return_row=false;
532: 	$q="SELECT * FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
533: 	$r=$this->DB->Query($q);
534: 	if ($row=$this->DB->Fetch_Array($r))
535: 		$return_row=true;
536: 		
537: 	$this->DB->Free($r);
538: 	if ($return_row) // found a valid
539: 		{
540: 		if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
541: 		else $row['name']=$row['nodeid'];
542: 		
543: 		$row['alerttext']=oText($row['alertlevel']); // textual alert status
544: 		
545: 		$row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
546: 		$row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
547: 		
548: 		// protection
549: 		$row['nskey']="";
550: 		
551: 		return $row;
552: 		}
553: 	else
554: 		return false; // or failed
555: 	}
556: 	
557: function GetNodes()
558: {
559: 	$out=array();
560: 	$q="SELECT * FROM fnnode";
561: 	$r=$this->DB->Query($q);
562: 	
563: 	while ($row=$this->DB->Fetch_Array($r))
564: 	{
565: 		if ($row['nodename']!="") $row['name']=$row['nodename']; // make a "nice" name for it
566: 		else $row['name']=$row['nodeid'];
567: 		
568: 		$row['alerttext']=oText($row['alertlevel']); // textual alert status
569: 		
570: 		$row['lastrundt']=nicedt($row['lastrunx']); // text date-time last run
571: 		$row['lastrunago']=dtago($row['lastrunx'],false); // last run ago
572: 		
573: 		// protection
574: 		$row['nskey']="";
575: 		
576: 		$out[$row['nodeid']]=$row;
577: 	}
578: 	$this->DB->Free($r);
579: 	
580: 	return $out;
581: }
582: 
583: 	
584: function GetNodeTests($nodeid)
585: 	{ // returns an array of testids for the node (enabled tests only)
586: 	$tests=array();
587: 	
588: 	// local tests
589: 	$q="SELECT localtestid FROM fnlocaltest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY localtestid ASC";
590: 	$r=$this->DB->Query($q);
591: 	while ($row=$this->DB->Fetch_Array($r))
592: 		{
593: 		$tests[]="L".$row['localtestid'];
594: 		}
595: 	$this->DB->Free($r);
596: 	
597: 	// nodeside
598: 	$q="SELECT nstestid FROM fnnstest WHERE testenabled=1 AND nodeid=\"".ss($nodeid)."\" ORDER BY testtype ASC";
599: 	$r=$this->DB->Query($q);
600: 	while ($row=$this->DB->Fetch_Array($r))
601: 		{
602: 		$tests[]="N".$row['nstestid'];
603: 		}
604: 	$this->DB->Free($r);
605: 	
606: 	return $tests;
607: 	}
608: 	
609: function SetNode($nodeid,$data)
610: 	{
611: 	$q="UPDATE fnnode SET ";
612: 	$first=true;
613: 	foreach($data as $key => $val)
614: 		{
615: 		if ($first) $first=false;
616: 		else $q.=",";
617: 		$q.=ss($key)."=\"".ss($val)."\"";
618: 		}
619: 	$q.=" WHERE nodeid=\"".ss($nodeid)."\"";
620: 	$this->DB->Query($q);
621: 	if ($this->DB->Affected_Rows()>0) return true;
622: 	
623: 	if ($this->DB->Error()) // query failed
624: 		{
625: 		$errstr1="Query Failed: ".$q;
626: 		$errstr2="Query Failed: ".$this->DB->Error_String();
627: 		$this->Event($errstr1,2,"Node","Set");
628: 		$this->Event($errstr1,2,"Node","Set");
629: 		return false;
630: 		}
631: 	return true; // query succeeded but nothing was updated
632: 	}
633: 	
634: function EnableNode($nodeid,$enabled=true)
635: 	{
636: 	if ($enabled) $ne=1;
637: 	else $ne=0;
638: 	$data=array("nodeenabled"=>$ne);
639: 	return $this->SetNode($nodeid,$data);
640: 	}
641: 	
642: function DisableNode($nodeid)
643: 	{
644: 	return $this->EnableNode($nodeid,false);
645: 	}
646: 	
647: function SetNodeSchedule($nodeid,$scheduleid)
648: 	{
649: 	$data=array("scheduleid"=>$scheduleid);
650: 	return $this->SetNode($nodeid,$data);
651: 	}
652: 	
653: function GetGroup($groupid)
654: 	{
655: 	$q="SELECT * FROM fngroup WHERE groupid=".ss($groupid)." LIMIT 0,1";
656: 	$r=$this->DB->Query($q);
657: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
658: 	
659: 	$this->DB->Free($r);
660: 	$row['alertlevel']=$this->GroupAlertLevel($groupid);
661: 	$row['alerttext']=oText($row['alertlevel']);
662: 	return $row;
663: 	}
664: 	
665: function GetGroups()
666: {
667: 	$out=array();
668: 	$q="SELECT * FROM fngroup";
669: 	$r=$this->DB->Query($q);
670: 	
671: 	while ($row=$this->DB->Fetch_Array($r))
672: 	{
673: 		$row['alertlevel']=$this->GroupAlertLevel($row['groupid']);
674: 		$row['alerttext']=oText($row['alertlevel']);
675: 		$out[$row['groupid']]=$row;
676: 	}
677: 	
678: 	$this->DB->Free($r);
679: 	return $out;
680: }
681: 	
682: function GetTest($testid,$protect=false)
683: 	{
684: 	if ($testid=="") return false;
685: 	$class=$testid[0];
686: 	if (is_numeric($class))
687: 		{
688: 		// test ID will stay the same
689: 		$class="L";
690: 		$anytestid=$testid;
691: 		}
692: 	else
693: 		{
694: 		//$testid=substr($testid,1); // as it will here also so direct use to graphs can be made
695: 		$anytestid=substr($testid,1); // the classless version
696: 		}
697: 		
698: 	$q="";
699: 	switch($class)
700: 		{
701: 		case "L": // local tests 
702: 			$q="SELECT * FROM fnlocaltest WHERE localtestid=".ss($anytestid)." LIMIT 0,1";
703: 			break;
704: 		case "N": // node-side test
705: 			$q="SELECT * FROM fnnstest WHERE nstestid=".ss($anytestid)." LIMIT 0,1";
706: 			break;
707: 		default:
708: 			return false; // can't lookup this class
709: 		}
710: 		
711: 	if ($q=="") return false;
712: 	
713: 	$r=$this->DB->Query($q);
714: 	
715: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
716: 	
717: 	$row['class']=$class;
718: 	$row['testid']=$testid;
719: 	$row['anytestid']=$anytestid;
720: 	$row['alerttext']=oText($row['alertlevel']);
721: 	$row['lastrundt']=nicedt($row['lastrunx']);
722: 	$row['lastrunago']=dtago($row['lastrunx'],false);
723: 	
724: 	if  ($row['testname']!="")  $row['name']=$row['testname'];
725: 	else
726: 			{
727: 			if ($class=="L")
728: 				{
729: 				$row['name']=lText($row['testtype']); // TODO OTHER TESTS
730: 				if ($row['testparam']!="") $row['name'].=" (".$row['testparam'].")";
731: 				}
732: 			else if ($class=="N")
733: 				{
734: 				if ($row['testdesc']!="") $row['name']=$row['testdesc'];
735: 				else $row['name']=$row['testtype'];
736: 				}
737: 			}
738: 			
739: 	if ($protect&&($class=="L")) // module test protection
740: 		{
741: 		if ($this->Tests->Exists($row['testtype'])) // in the module register
742: 			{
743: 			$this->Tests->Tests[$row['testtype']]->Create();
744: 			$this->Tests->Tests[$row['testtype']]->instance->ProtectOutput($row);
745: 			}
746: 		}
747: 	
748: 	$this->DB->Free($r);
749: 	
750: 	return $row;
751: 	}
752: 
753: 	
754: function DeleteTest($testid)
755: 	{
756: 	if ($testid=="") return false;
757: 	$class=$testid[0];
758: 	if (is_numeric($class))
759: 		{
760: 		// test ID will stay the same
761: 		$class="L";
762: 		$anytestid=$testid;
763: 		}
764: 	else
765: 		{
766: 		$anytestid=substr($testid,1); // the classless version
767: 		}
768: 		
769: 	$q="";
770: 	switch($class)
771: 		{
772: 		case "L": // local tests 
773: 			$q="DELETE FROM fnlocaltest WHERE localtestid=".ss($anytestid);
774: 			break;
775: 		case "N": // node-side test
776: 			$q="DELETE FROM fnnstest WHERE nstestid=".ss($anytestid);
777: 			break;
778: 		default:
779: 			return false; // can't lookup this class
780: 		}
781: 		
782: 	if ($q=="") return false;
783: 	
784: 	$this->DB->Query($q);
785: 	$tests=$this->DB->Affected_Rows();
786: 	
787: 	$rq="DELETE FROM fnrecord WHERE testid=\"".ss($testid)."\"";
788: 	$this->DB->Query($rq);
789: 	$records=$this->DB->Affected_Rows();
790: 	
791: 	$eq="DELETE FROM fneval WHERE testid=\"".ss($testid)."\"";
792: 	$this->DB->Query($eq);
793: 	$eval=$this->DB->Affected_Rows();
794: 	
795: 	$s="Deleted test ".$testid." (".$tests." tests, ".$records." records, ".$eval." evaluators)";
796: 	$this->Event($s,6,"Test","Delete");
797: 	}
798: 	
799: 	
800: 	
801: function InvalidateTest($testid,$rightnow=false)
802: 	{
803: 	$class=$testid[0];
804: 	if (is_numeric($class)) $class="L";
805: 	else $testid=substr($testid,1);
806: 	if ($rightnow)
807: 		{
808: 		$nextx=time();
809: 		$q="UPDATE ";
810: 		if ($class=="L") $q.="fnlocaltest";
811: 		// other ones here
812: 		
813: 		$q.=" SET nextrunx=".$nextx." WHERE ";
814: 		
815: 		if ($class=="L") $q.="localtestid=".$testid;
816: 		// other ones here
817: 		
818: 		$this->DB->Query($q);
819: 		return true;
820: 		}
821: 	// otherwise use it's interval
822: 	$q="SELECT testinterval FROM ";
823: 	
824: 	if ($class=="L") $q.="fnlocaltest WHERE localtestid=";
825: 	// other ones here
826: 	
827: 	$q.=$testid;
828: 	$r=$this->DB->Query($q);
829: 	if ($row=$this->DB->Fetch_Array($r))
830: 		{
831: 		$this->DB->Free($r);
832: 		$nextx=next_run_x($row['testinterval']);
833: 		$q="UPDATE ";
834: 		if ($class=="L") $q.="fnlocaltest";
835: 		// other ones here
836: 		
837: 		$q.=" SET nextrunx=".$nextx." WHERE ";
838: 		
839: 		if ($class=="L") $q.="localtestid=".$testid;
840: 		// other ones here
841: 		
842: 		$this->DB->Query($q);
843: 		return true;
844: 		}
845: 	return false;
846: 	}		
847: 	
848: function InvalidateNode($nodeid,$rightnow=false,$testsaswell=false)
849: 	{
850: 	if ($rightnow)
851: 		{
852: 		$nextx=time();
853: 		$q="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
854: 		$this->DB->Query($q);
855: 		if ($testsaswell)
856: 			{
857: 			$q="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
858: 			$this->DB->Query($q);
859: 			}
860: 		return true;
861: 		}
862: 	// otherwise set to it's interval
863: 	$q="SELECT testinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\"";
864: 	$r=$this->DB->Query($q);
865: 	if ($row=$this->DB->Fetch_Array($r))
866: 		{
867: 		$nextx=next_run_x($row['testinterval']);
868: 		$uq="UPDATE fnnode SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
869: 		$this->DB->Query($uq);
870: 		$this->DB->Free($r);
871: 		if ($testsaswell)
872: 			{
873: 			$uq="UPDATE fnlocaltest SET nextrunx=".$nextx." WHERE nodeid=\"".ss($nodeid)."\"";
874: 			$this->DB->Query($uq);
875: 			}
876: 		return true;
877: 		}
878: 	return false;
879: 	}
880: 	
881: 	
882: function NodeSide_Pull($nodeid)
883: 	{
884: 	$eventdata=array("nodeid"=>$nodeid,"success"=>false);
885: 	$q="SELECT nsenabled,nspullenabled,nsurl,nskey,nsinterval FROM fnnode WHERE nodeid=\"".ss($nodeid)."\" LIMIT 0,1";
886: 	$r=$this->DB->Query($q);
887: 	if (!$row=$this->DB->Fetch_Array($r)) return false;
888: 	
889: 	$this->DB->Free($r);
890: 	
891: 	$url=$row['nsurl'];
892: 	if ($row['nskey']!="") $url.="?nodekey=".$row['nskey'];
893: 	//echo $url."\n";
894: 	$this->Event("NodeSide_Pull Started for ".$nodeid,10,"Node","Pull");
895: 	
896: 	$xmlobj=new TNodeXML();
897: 	
898: 	$fp=@fopen($url,"r");
899: 	if ($fp<=0)
900: 		{
901: 		$this->Event("Pull Failed URL ".$url,1,"Node","Pull");
902: 		$this->EventHandler("nodeside_pull",$eventdata);
903: 		return false;
904: 		}
905: 	$xml="";
906: 	while (!feof($fp))
907: 		{
908: 		$xml.=fgets($fp,4096);
909: 		}
910: 	if ($xml=="")
911: 		{
912: 		$this->EventHandler("nodeside_pull",$eventdata);
913: 		return false;
914: 		}
915: 	
916: 	//echo $xml;
917: 	
918: 	$result=$xmlobj->Parse($xml);
919: 	
920: 	if ($xmlobj->Error()!="")
921: 		{
922: 		$this->Event("NodeXML Error: ".$xmlobj->Error(),1,"Node","Pull");
923: 		$this->EventHandler("nodeside_pull",$eventdata);
924: 		return false;
925: 		}
926: 	$this->Event("NodeSide_Pull Fetched ".$xmlobj->Tests." tests for ".$nodeid,10,"Node","Pull");
927: 	// Now just to actually process it...
928: 	$eventdata['success']=true;
929: 	$this->EventHandler("nodeside_pull",$eventdata);
930: 	$this->NodeSide_Process($nodeid,$xmlobj);
931: 	return true;
932: 	}	
933: 	
934: function NodeSide_Process($nodeid,&$xmlobj)
935: 	{ // nodeid + takes a TNodeXML Object
936: 	$alvl=0;
937: 	$this->Event("NodeSide_Process for ".$nodeid,10,"Node","Pull");
938: 	$q="SELECT * FROM fnnstest WHERE nodeid=\"".ss($nodeid)."\"";
939: 	$r=$this->DB->Query($q);
940: 	$tests=array();
941: 	while ($row=$this->DB->Fetch_Array($r))
942: 		{
943: 		$tests[$row['testtype']]=$row;
944: 		if (isset($xmlobj->Catalogue[$row['testtype']]))
945: 			{ // this test is in the DB and catalogue
946: 			$tests[$row['testtype']]['incat']=true;
947: 			if ($row['testenabled']==1) // it is enabled - so we test it
948: 				{
949: 				if ($row['simpleeval']==1) $level=$xmlobj->Catalogue[$row['testtype']]['ALERTLEVEL']; // use provided level
950: 				else $level=nats_eval("N".$row['nstestid'],$xmlobj->Catalogue[$row['testtype']]['VALUE']);
951: 				$dbs="Nodeside ".$row['testtype']." on ".$row['nodeid']." = ".$level;
952: 				if ($level==0) $debuglev=8;
953: 				else if ($level>0) $debuglev=5;
954: 				else $debuglev=2;
955: 				$this->Event($dbs,$debuglev,"Node","Process");
956: 				
957: 				if ($level>$alvl) $alvl=$level;
958: 				
959: 				if ($row['testrecord']==1) // record it
960: 					{
961: 					$testvalue=$xmlobj->Catalogue[$row['testtype']]['VALUE'];
962: 					$testvalue=str_replace(",",".",$testvalue);
963: 					if (!is_numeric($testvalue)) $testvalue=0;
964: 					$iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
965: 					$iq.="\"N".$row['nstestid']."\",".$level.",".time().",\"".$row['nodeid']."\",".$testvalue.")";
966: 					$this->DB->Query($iq);
967: 					if ($this->DB->Affected_Rows()<=0)
968: 						$this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
969: 					}
970: 					
971: 				// We don't do any alerting here - the tester will do that for us!
972: 				$uq="UPDATE fnnstest SET lastrunx=".time().",lastvalue=\"".ss($xmlobj->Catalogue[$row['testtype']]['VALUE'])."\",alertlevel=".$level." ";
973: 				$uq.="WHERE nstestid=".$row['nstestid'];
974: 				$this->DB->Query($uq);
975: 				if ($this->DB->Affected_Rows()<=0)
976: 						$this->Event("Nodeside ".$row['testtype']." Failed to Update or Same Values",5,"Node","Process");
977: 				
978: 				}
979: 					
980: 			// check to see if the desc has changed
981: 			if ($row['testdesc']!=$xmlobj->Catalogue[$row['testtype']]['DESC'])
982: 				{
983: 				$duq="UPDATE fnnstest SET testdesc=\"".ss($xmlobj->Catalogue[$row['testtype']]['DESC'])."\" WHERE nstestid=".$row['nstestid'];
984: 				$this->DB->Query($duq);
985: 				}
986: 				
987: 			}
988: 		else
989: 			{
990: 			// test in the DB but NOT in the catalogue
991: 			//$xmlobj->Catalogue[$row['testtype']]['incat']=false;
992: 			if ($row['testenabled']==1)
993: 				{ // enabled so shown in lists etc
994: 				// Update it to show failed status
995: 				$this->Event("No nodeside data for test N".$row['nstestid'],3,"Node","Process");
996: 				$uq="UPDATE fnnstest SET alertlevel=2,lastvalue=-1 WHERE nstestid=".$row['nstestid'];
997: 				$this->DB->Query($uq);
998: 				$alvl=2;
999: 				if ($row['testrecord']==1) // record it
1000: 					{
1001: 					$testvalue=-1;
1002: 					$iq="INSERT INTO fnrecord(testid,alertlevel,recordx,nodeid,testvalue) VALUES(";
1003: 					$iq.="\"N".$row['nstestid']."\",2,".time().",\"".$row['nodeid']."\",".$testvalue.")";
1004: 					$this->DB->Query($iq);
1005: 					if ($this->DB->Affected_Rows()<=0)
1006: 						$this->Event("Nodeside ".$row['testtype']." Failed to Record",1,"Node","Process");
1007: 					}
1008: 				}
1009: 			else // not enabled so simply delete
1010: 				{
1011: 				$this->DeleteTest("N".$row['nstestid']);
1012: 				}
1013: 			}
1014: 		}
1015: 	$this->DB->Free($r);
1016: 	
1017: 	
1018: 	// and finally we look for new tests i.e. in the cat but not in the DB
1019: 	foreach($xmlobj->Catalogue as $val)
1020: 		{
1021: 		$key=$val['NAME'];
1022: 		if (!isset($tests[$key])) // not in the DB
1023: 			{
1024: 			$q="INSERT INTO fnnstest(nodeid,testtype,testdesc,lastvalue,lastrunx,alertlevel) ";
1025: 			$q.="VALUES(\"".ss($nodeid)."\",\"".$key."\",\"".ss($val['DESC'])."\",\"".ss($val['VALUE'])."\",".time().",".ss($val['ALERTLEVEL']).")";
1026: 			//echo $q."<br>";
1027: 			$this->DB->Query($q);
1028: 			}
1029: 		}
1030: 		
1031: 	$eventdata=array("nodeid"=>$nodeid,"alertlevel"=>$alvl);
1032: 	$this->EventHandler("nodeside_process",$eventdata);
1033: 	
1034: 	
1035: 	}
1036: 	
1037: 	
1038: function AddEventHandler($event,$function)
1039: {
1040: 	if (!isset($this->EventHandlers[$event])) $this->EventHandlers[$event]=array();
1041: 	$this->EventHandlers[$event][]=$function;
1042: }
1043: 
1044: function EventHandler($event,$data)
1045: {
1046: 	$res=false;
1047: 	if ( isset($data) && is_array($data) ) $data['event']=$event;
1048: 	
1049: 	if (isset($this->EventHandlers[$event])) // handler(s) exist
1050: 	{
1051: 	for($a=0; $a<count($this->EventHandlers[$event]); $a++)
1052: 		{
1053: 		if (function_exists($this->EventHandlers[$event][$a]))
1054: 			{
1055: 			$this->Event("Event ".$event." -> ".$this->EventHandlers[$event][$a],6,"Event","Handler");
1056: 			if($this->EventHandlers[$event][$a]($data)) $res=true; // persist true only
1057: 			}
1058: 		else
1059: 			{
1060: 			$t="Illegal Handler ".$this->EventHandlers[$event][$a]." for ".$event;
1061: 			$this->Event($t,2,"Event","Handler");
1062: 			//return false;
1063: 			}
1064: 		}
1065: 	}
1066: 	else return $res;
1067: }
1068: 
1069: function StripGPC($data)
1070: {
1071: 	if (get_magic_quotes_gpc()) return stripslashes($data);
1072: 	else return $data;
1073: }
1074: 
1075: function PageError($code,$desc)
1076: {
1077: $this->PageErrors[]=array( "code" => $code, "desc" => $desc );
1078: }
1079: 	
1080: }
1081: ?>
1082: