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