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