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