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