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