File:
1.16.0a/server/base/freenats.inc.php (
View as Code)
1: 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; $a247: {
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; $a333: {
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."
";
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; $aEventHandlers[$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: