1 /*
2  *  RNtrack - FTN message tracker/router
3  *
4  *  nodelist.cpp - Work with nodelists
5  *
6  *  Copyright (c) 2003-2005 Alex Soukhotine, 2:5030/1157
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  $Id: nodelist.cpp 257 2020-01-30 18:19:33Z dukelsky $
14  */
15 
16 #ifndef __GNUC__
17     #include <io.h>
18     #include <direct.h>
19     #ifdef _MSC_VER
20         #include "dirent/dirent.h"
21     #endif
22 #else
23     #include <unistd.h>
24     #include <sys/types.h>
25     #include <dirent.h>
26     #include <sys/stat.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 
33 #include "compiler.h"
34 #include "constant.hpp"
35 #include "vars.hpp"
36 #include "configure.hpp"
37 #include "log.hpp"
38 #include "nodelist.hpp"
39 #include "age.hpp"
40 #include "utils.hpp"
41 
42 char * NodelistPath;
43 
44 static bool NodelistTurnOff = FALSE;
45 static int NodelistLineNum  = 0;
46 
47 static const char mErrReadIndex[] = "Error reading index file.";
48 static const char mNdlChanged[] =
49     "Some nodelists have changed. Recompilation is necessary.";
50 static const char mIndNFound[] =
51     "Index file not found. Create new index file.";
52 static const char mErrNdlMustFull[] =
53     "Error: You must define default Zone for Regional and Network versions of nodelist.";
54 static const char mErrNdlFormat[] = "Incorrect nodelist format.";
55 
56 #define ErrReadIndex Log.Level(LOGE) << mErrReadIndex << EOL
57 #define IndexChanged Log.Level(LOGI) << mNdlChanged << EOL
58 #define IndexNotFound Log.Level(LOGI) << mIndNFound << EOL
59 
60 
61 typedef struct _Ntr
62 {
63     dword Number;
64     dword Attrib;
65     struct _Ntr * Next;
66     struct _Ntr * Sub;
67 } Ntr;
68 
ErrNdlFormat(const char * m)69 void ErrNdlFormat(const char * m)
70 {
71     Log.Level(LOGE) << "Error in line " << NodelistLineNum << ", " <<
72                     mErrNdlFormat << EOL;
73     Log.Level(LOGE) << m << EOL;
74     NodelistTurnOff = TRUE;
75 }
76 
FindNodelist(char * Mask,char * Name)77 int FindNodelist(char * Mask, char * Name)
78 {
79     int maxext;
80     DIR * dd;
81     struct dirent * ff;
82     char NDir[512], Path[512], Fname[512];
83     char * tmt = NULL;
84     FILE * ft;
85 
86     *Name   = '\0';
87     Path[1] = '\0';
88     maxext  = (-1);
89 
90     GetFilePath(Path, Mask);
91 
92     if(NodelistPath != NULL && *Path != PATHDELIMC
93 #ifndef __unix__
94             && Path[1] != ':'
95 #endif
96       )
97     {
98         strcpy(NDir, NodelistPath);
99         strcat(NDir, Path);
100         strcpy(Path, NDir);
101     }
102 
103     GetFileName(Fname, Mask);
104 
105     if(strchr(Fname, '*') || strchr(Fname, '?'))
106     {
107         if((dd = opendir(dirslashbug(Path))) != 0)
108         {
109             while((ff = readdir(dd)) != NULL)
110             {
111                 if(fsCompareName(ff->d_name, Fname) != 0 &&
112                         (tmt = strrchr(ff->d_name, '.')) != NULL)
113                 {
114                     tmt++;
115 
116                     if(StrIsNum(tmt) && atoi(tmt) > maxext)
117                     {
118                         maxext = atoi(tmt);
119                         strcpy(Name, Path);
120                         strcat(Name, ff->d_name);
121                     }
122                 }
123             }
124             closedir(dd);
125         }
126         else
127         {
128             yyerror("Nodelist not found.");
129             return -1;
130         }
131     }
132     else
133     {
134         strcpy(Name, Path);
135         strcat(Name, Fname);
136     }
137 
138     if(*Name == '\0')
139     {
140         yyerror("Nodelist not found.");
141         return -1;
142     }
143 
144     if((ft = fopen(Name, "rt")) == NULL)
145     {
146         yyerror("Unable to open Nodelist.");
147         return -1;
148     }
149     else
150     {
151         fclose(ft);
152     }
153 
154     return 0;
155 } // FindNodelist
156 
157 // ------------------- Compile and write one nodelist  --------------------
158 
159 static FILE * nh;
160 static int CurrentNet = -1;
161 static int CurrentZone    = -1;
162 static Ntr ** CurrentHub  = NULL;
163 static Ntr * _pNodeList   = NULL;
164 static bool PointListMode = FALSE;
165 static Ntr * BossNode     = NULL;
166 
OpenNodelist(char * FName)167 bool OpenNodelist(char * FName)
168 {
169     nh = fopen(FName, "rt");
170 
171     if(nh == NULL)
172     {
173         Log.Level(LOGE) << "Unable to open nodelist '" << FName << "'" << EOL;
174         return FALSE;
175     }
176 
177     return TRUE;
178 }
179 
CloseNodelist(void)180 bool CloseNodelist(void)
181 {
182     return fclose(nh) == 0;
183 }
184 
ReadNdlLine(char * Buff,int Count)185 int ReadNdlLine(char * Buff, int Count)
186 {
187     char * tmt;
188 
189     Buff[0] = ';';
190 
191     while(Buff[0] == ';')
192     {
193         NodelistLineNum++;
194 
195         if(fgets(Buff, Count, nh) == NULL)
196         {
197             Buff[0] = '\0';
198             return -1;
199         }
200 
201         tmt = strchr(Buff, '\n');
202 
203         if(tmt != NULL)
204         {
205             *tmt = '\0';
206         }
207 
208         tmt = strchr(Buff, '\r');
209 
210         if(tmt != NULL)
211         {
212             *tmt = '\0';
213         }
214 
215         tmt = strchr(Buff, (char)0x1a);
216 
217         if(tmt != NULL)
218         {
219             *tmt = '\0';
220         }
221 
222         if(strlen(Buff) == 0)
223         {
224             Buff[0] = ';';
225         }
226     }
227     return (int)strlen(Buff);
228 } // ReadNdlLine
229 
ExistByNumber(Ntr * Addr,unsigned int Number)230 Ntr * ExistByNumber(Ntr * Addr, unsigned int Number)
231 {
232     Ntr * tmt;
233 
234     tmt = Addr;
235 
236     while(tmt != NULL)
237     {
238         if((tmt->Number & 0xffff) == (Number & 0xffff))
239         {
240             return tmt;
241         }
242 
243         tmt = tmt->Next;
244     }
245     return NULL;
246 }
247 
GetCurrentZone(void)248 Ntr * GetCurrentZone(void)
249 {
250     return ExistByNumber(_pNodeList, CurrentZone);
251 }
252 
GetCurrentNet(void)253 Ntr * GetCurrentNet(void)
254 {
255     Ntr * tmt;
256 
257     if((tmt = GetCurrentZone()) != NULL)
258     {
259         if(tmt->Sub != NULL)
260         {
261             return ExistByNumber(tmt->Sub, CurrentNet);
262         }
263         else
264         {
265             return NULL;
266         }
267     }
268     else
269     {
270         return NULL;
271     }
272 }
273 
DelDupNode(unsigned int Node)274 bool DelDupNode(unsigned int Node)
275 {
276 // Remove a node from the list if it is already present there but check
277 // whether it is a hub. If it is a hub then do not remove it. If the node
278 // is also a hub now then we set the current hub pointer to the hub.
279 // Return TRUE  if the node was successfully removed
280 //              or it was absent in the list
281 //        FALSE if the node was in the list as a hub and it is a hub now.
282     Ntr * tr;
283 
284     tr = GetCurrentNet();
285     assert(tr != NULL);
286     tr = tr->Sub;
287 
288     while(tr != NULL)
289     {
290         if((tr->Number & 0xffff) == (Node & 0xffff))
291         {
292             if((tr->Number & A_MASK) != A_HUB)
293             {
294                 tr->Number = (unsigned int)-1;
295                 return TRUE;
296             }
297             else if(((tr->Number & A_MASK) == A_HUB) &&
298                     ((Node & A_MASK) == A_HUB))
299             {
300 //            Log.Level(LOGD) << "Two nodes? " << tr->Number << " " << Node <<
301                 // EOL;
302 //            Log.Level(LOGD) << "Net: " << CurrentZone << ":" << CurrentNet <<
303                 // EOL;
304                 CurrentHub = &(tr->Next);
305                 return FALSE;
306             }
307         }
308 
309         tr = tr->Next;
310     }
311     return TRUE;
312 } // DelDupNode
313 
AddElemToList(Ntr ** Addr,unsigned int Number)314 void AddElemToList(Ntr ** Addr, unsigned int Number)
315 {
316     Ntr * tmt;
317 
318     tmt = (Ntr *)malloc(sizeof(Ntr));
319     CheckMem((char *)tmt);
320     memset(tmt, 0, sizeof(Ntr));
321     tmt->Number = Number;
322 
323     while((*Addr) != 0)
324     {
325         Addr = &((*Addr)->Next);
326     }
327     *Addr = tmt;
328 }
329 
AddNetToList(void)330 void AddNetToList(void)
331 {
332     Ntr * tr;
333 
334     tr = GetCurrentZone();
335     assert(tr != NULL);
336     AddElemToList(&(tr->Sub), CurrentNet);
337 }
338 
AddZoneToList(void)339 void AddZoneToList(void)
340 {
341     AddElemToList(&_pNodeList, CurrentZone);
342     AddNetToList();
343 }
344 
_SetCurrentZone(unsigned int Zone)345 void _SetCurrentZone(unsigned int Zone)
346 {
347     CurrentZone = Zone;
348     CurrentNet  = Zone;
349     CurrentHub  = NULL;
350 
351     if(GetCurrentZone() == 0)
352     {
353         AddZoneToList();
354     }
355 }
356 
_AddNode(unsigned int Node)357 void _AddNode(unsigned int Node)
358 {
359 // Add a node to the list. If it is absent there then just prepend it
360 // to the CurrentHub list. If there is no CurrentHub list then we add
361 // the node as usual. If the node is already present in the list
362 // then do nothing.
363     Ntr * tr, * tmt;
364 
365     if(DelDupNode(Node) == TRUE)
366     {
367         if(CurrentHub != NULL)
368         {
369             tmt = (Ntr *)malloc(sizeof(Ntr));
370             CheckMem((char *)tmt);
371             memset(tmt, 0, sizeof(Ntr));
372             tmt->Number = Node;
373             tr = (*CurrentHub)->Next;
374             (*CurrentHub)->Next = tmt;
375             tmt->Next = tr;
376         }
377         else
378         {
379             tr = GetCurrentNet();
380             assert(tr != NULL);
381             AddElemToList(&(tr->Sub), Node);
382         }
383     }
384 } // _AddNode
385 
_SetCurrentNet(unsigned int Net)386 void _SetCurrentNet(unsigned int Net)
387 {
388     CurrentNet = Net;
389     CurrentHub = NULL;
390 
391     if(GetCurrentNet() == NULL)
392     {
393         AddNetToList();
394     }
395 }
396 
_SetCurrentBoss(char * tmt)397 bool _SetCurrentBoss(char * tmt)
398 {
399     FA f;
400     Ntr * tp;
401 
402     BossNode = NULL;
403     f.Parse((const char * &)tmt);
404 
405     if(f.Masked())
406     {
407         return FALSE;
408     }
409 
410     if((f.Point() & 0xffff) != 0)
411     {
412         return FALSE;
413     }
414 
415     tp = ExistByNumber(_pNodeList, f.Zone());
416 
417     if(tp == NULL)
418     {
419         return TRUE;
420     }
421 
422     if(tp->Sub == NULL)
423     {
424         return TRUE;
425     }
426 
427     tp = ExistByNumber(tp->Sub, f.Net());
428 
429     if(tp == NULL)
430     {
431         return TRUE;
432     }
433 
434     if(tp->Sub == NULL)
435     {
436         return TRUE;
437     }
438 
439     tp = ExistByNumber(tp->Sub, f.Node());
440 
441     if(tp == NULL)
442     {
443         return TRUE;
444     }
445 
446     BossNode = tp;
447     return TRUE;
448 } // _SetCurrentBoss
449 
_AddPoint(int pnt)450 void _AddPoint(int pnt)
451 {
452     if(BossNode != NULL)
453     {
454         AddElemToList(&(BossNode->Sub), pnt);
455     }
456 }
457 
ParseNodeLine(char * tmt)458 bool ParseNodeLine(char * tmt)
459 {
460     unsigned int tmp;
461 
462 // DumpNdl();
463 // fprintf(stderr,"%s\n",tmt);
464 //   printf("'%s'\n",tmt);
465     switch(*tmt)
466     {
467     case 'B': // Boss record. Pointlist?
468     case 'b':
469         PointListMode = TRUE;
470 
471         if(_SetCurrentBoss(tmt + 5) != TRUE)
472         {
473             ErrNdlFormat("Bad BOSS record");
474             return FALSE;
475         }
476 
477         break;
478 
479     case 'Z': // Zone record
480         PointListMode = FALSE;
481         _SetCurrentZone(atoi(tmt + 5));
482         break;
483 
484     case 'R': // Region record
485         PointListMode = FALSE;
486 
487         if(CurrentZone == 0)
488         {
489             Log.Level(LOGE) << mErrNdlMustFull << EOL;
490             return FALSE;
491         }
492 
493         tmp  = atoi(tmt + 7);
494         tmp |= A_REGION;
495         _SetCurrentNet(tmp); // Region is a strange type of net.
496         break;
497 
498     case 'H': // Host, Hub, or Hold record
499 
500         switch(*(tmt + 2))
501         {
502         case 's': // Host
503             PointListMode = FALSE;
504 
505             if(CurrentZone == 0)
506             {
507                 Log.Level(LOGE) << mErrNdlMustFull << EOL;
508                 return FALSE;
509             }
510 
511             _SetCurrentNet(atoi(tmt + 5));
512             break;
513 
514         case 'b': // Hub
515 
516             if(PointListMode == TRUE)
517             {
518                 ErrNdlFormat("HUB record in pointlist!");
519                 return FALSE;
520             }
521 
522             if(CurrentZone == 0)
523             {
524                 ErrNdlFormat("HUB record without Zone record!");
525                 return FALSE;
526             }
527 
528             tmp  = atoi(tmt + 4);
529             tmp |= A_HUB;
530             _AddNode(tmp);
531             break;
532 
533         case 'l': // Hold
534 
535             if(PointListMode == TRUE)
536             {
537                 ErrNdlFormat("Node or point with HOLD flag!");
538                 return FALSE;
539             }
540 
541             if(CurrentZone == 0)
542             {
543                 ErrNdlFormat("HOLD record without Zone record!");
544                 return FALSE;
545             }
546 
547             tmp  = atoi(tmt + 5);
548             tmp |= A_HOLD;
549             _AddNode(tmp);
550             break;
551 
552         default:
553             ErrNdlFormat("Unknown format!");
554             return FALSE;
555         } // switch
556         break;
557 
558     case ',': // Simple node
559 
560         if(PointListMode == TRUE)
561         {
562             _AddPoint(atoi(tmt + 1));
563         }
564         else
565         {
566             if(CurrentZone == 0)
567             {
568                 ErrNdlFormat("Node record without Zone record!");
569                 return FALSE;
570             }
571 
572             if(CurrentNet == 0)
573             {
574                 ErrNdlFormat("Node record without Host/Region record!");
575                 return FALSE;
576             }
577 
578             _AddNode(atoi(tmt + 1));
579         }
580 
581         break;
582 
583     case 'D': // Down
584 
585         if(PointListMode == TRUE)
586         {
587             ErrNdlFormat("DOWN record in pointlist!");
588             return FALSE;
589         }
590 
591         if(CurrentZone == 0)
592         {
593             ErrNdlFormat("Node Down record without Zone record!");
594             return FALSE;
595         }
596 
597         if(CurrentNet == 0)
598         {
599             ErrNdlFormat("Node Down record without Host/Region record!");
600             return FALSE;
601         }
602 
603         tmp  = atoi(tmt + 5);
604         tmp |= A_DOWN;
605         _AddNode(tmp);
606         break;
607 
608     case 'P': // Pvt or Point
609     case 'p':
610 
611         switch(*(tmt + 1))
612         {
613         case 'v': // Pvt
614 
615             if(PointListMode == TRUE)
616             {
617                 ErrNdlFormat("PVT record in pointlist!");
618                 return FALSE;
619             }
620 
621             if(CurrentZone == 0)
622             {
623                 ErrNdlFormat("Node Pvt record without Zone record!");
624                 return FALSE;
625             }
626 
627             if(CurrentNet == 0)
628             {
629                 ErrNdlFormat("Node Pvt record without Host record!");
630                 return FALSE;
631             }
632 
633             tmp  = atoi(tmt + 4);
634             tmp |= A_PVT;
635             _AddNode(tmp);
636             break;
637 
638         case 'o': // Point
639 
640             if(PointListMode == FALSE)
641             {
642                 ErrNdlFormat("POINT record not in pointlist!");
643                 return FALSE;
644             }
645 
646             tmp = atoi(tmt + 6);
647             _AddPoint(tmp);
648             break;
649 
650         default:
651             ErrNdlFormat("Unknown format!");
652             return FALSE;
653         } // switch
654         break;
655 
656     default: // No one? Hmm...
657         ErrNdlFormat("Unknown format!");
658         return FALSE;
659     } // switch
660     return TRUE;
661 } // ParseNodeLine
662 
ParseOneNodelist(NodeListElem * Elem)663 bool ParseOneNodelist(NodeListElem * Elem)
664 {
665     char Buff[512];
666 
667     Log.Level(LOGI) << "Compile nodelist '" << Elem->Name << "'";
668 
669     if(Elem->StartZone != 0)
670     {
671         _SetCurrentZone(Elem->StartZone); // Set address to Zone:Zone/0; 1st
672         // line of the nodelist should be
673         // "Host" or "Region"
674         Log.Level(LOGI) << ", start zone number is " << Elem->StartZone << EOL;
675     }
676     else
677     {
678         CurrentZone = 0;
679     }
680 
681     CurrentNet = 0;
682     Log.Level(LOGI) << " ..." << EOL;
683 
684     if(!OpenNodelist(Elem->Name))
685     {
686         return FALSE;
687     }
688 
689     NodelistLineNum = 0;
690 
691     while(ReadNdlLine(Buff, 510) > 0)
692     {
693         if(!ParseNodeLine(Buff))
694         {
695             CloseNodelist();
696             return FALSE;
697         }
698     }
699     CloseNodelist();
700     Log.Level(LOGI) << "Done" << EOL;
701     return TRUE;
702 } // ParseOneNodelist
703 
704 // ------------------------------------------------------
705 // Flush compiled nodelist to disk
706 // ------------------------------------------------------
707 
708 #if 0
709 void PrintNtr(Ntr * tmt, char * Buff)
710 {
711     int len;
712     Ntr * tmt2;
713 
714     len  = strlen(Buff);
715     tmt2 = tmt;
716 
717     while(tmt != NULL)
718     {
719         sprintf(Buff + len, "%d ", tmt->Number & 0xffff);
720         PrintNtr(tmt->Sub, Buff);
721         tmt = tmt->Next;
722     }
723 
724     if(tmt2 == NULL)
725     {
726         printf("%s\n", Buff);
727     }
728 }
729 #endif
730 
ElementsInList(Ntr * Addr)731 int ElementsInList(Ntr * Addr)
732 {
733     Ntr * tmt;
734     int Elems;
735 
736     tmt   = Addr;
737     Elems = 0;
738 
739     while(tmt != NULL)
740     {
741         if(tmt->Number != (unsigned int)-1)
742         {
743             Elems++;
744         }
745 
746         tmt = tmt->Next;
747     }
748     return Elems;
749 }
750 
SaveElements(FILE * fh,Ntr * Addr)751 bool SaveElements(FILE * fh, Ntr * Addr)
752 {
753     Ntr * tmt;
754 
755     tmt = Addr;
756 
757     while(tmt != NULL)
758     {
759         if(tmt->Number != (unsigned int)-1)
760         {
761             if(fwrite(&tmt->Number, sizeof(int), 1, fh) != 1)
762             {
763                 Log.Level(LOGE) << "Unable to write body of Elems" << EOL;
764                 return FALSE;
765             }
766         }
767 
768         tmt = tmt->Next;
769     }
770     return TRUE;
771 }
772 
FlushElements(FILE * fh,Ntr * tmt)773 bool FlushElements(FILE * fh, Ntr * tmt)
774 {
775     int Elems;
776 
777     Elems = ElementsInList(tmt);
778 
779     if(fwrite(&Elems, sizeof(Elems), 1, fh) != 1)
780     {
781         Log.Level(LOGE) << "Unable to write Elems" << EOL;
782         return FALSE;
783     }
784 
785     if(!SaveElements(fh, tmt))
786     {
787         return FALSE;
788     }
789 
790     return TRUE;
791 }
792 
FlushSubElements(FILE * fh,Ntr * tmt)793 bool FlushSubElements(FILE * fh, Ntr * tmt)
794 {
795     if(FlushElements(fh, tmt) == FALSE)
796     {
797         return FALSE;
798     }
799 
800     while(tmt != NULL)
801     {
802         if(tmt->Number != (unsigned int)-1)
803         {
804             if(FlushSubElements(fh, tmt->Sub) == FALSE)
805             {
806                 return FALSE;
807             }
808         }
809 
810         tmt = tmt->Next;
811     }
812     return TRUE;
813 }
814 
FlushElementsTree(FILE * fh)815 bool FlushElementsTree(FILE * fh)
816 {
817     return FlushSubElements(fh, _pNodeList);
818 }
819 
820 // ------------------------------------------------------
821 // Free parser memory
822 // ------------------------------------------------------
823 
FreeSubElements(Ntr * tmt)824 void FreeSubElements(Ntr * tmt)
825 {
826     Ntr * tmt2;
827 
828     if(tmt == NULL)
829     {
830         return;
831     }
832 
833     while(tmt != NULL)
834     {
835         FreeSubElements(tmt->Sub);
836         tmt2 = tmt->Next;
837         free(tmt);
838         tmt = tmt2;
839     }
840 }
841 
FreeParserMem(void)842 void FreeParserMem(void)
843 {
844     FreeSubElements(_pNodeList);
845     _pNodeList = NULL;
846 }
847 
848 // ------------------------------------------------------
849 
FlushNodelist(FILE * fh)850 bool FlushNodelist(FILE * fh)
851 {
852 #if 0
853     char Buff[1024];
854     PrintNtr(_pNodeList, Buff);
855 #endif
856 
857     if(FlushElementsTree(fh) == FALSE)
858     {
859         return FALSE;
860     }
861 
862     FreeParserMem();
863     return TRUE;
864 }
865 
866 // ------------------------- class NodeLists -----------------------
867 
NodeLists()868 NodeLists::NodeLists()
869 {
870     NList = NULL;
871     Lists = 0;
872     StartZone = 0;
873     IndexName = strdup(DefaultIndex);
874 }
875 
~NodeLists()876 NodeLists::~NodeLists()
877 {
878     if(NList != NULL)
879     {
880         free(NList);
881         NList = NULL;
882     }
883 
884     Lists = 0;
885 
886     if(IndexName != NULL)
887     {
888         free(IndexName);
889         IndexName = NULL;
890     }
891 }
892 
893 #if 0
894 void PrintNch(Nch * tmt, char * Buff)
895 {
896     int i;
897     int len;
898 
899     len = strlen(Buff);
900     i   = 0;
901 
902     while(tmt[i].Number != -1)
903     {
904         sprintf(Buff + len, "%d ", tmt[i].Number & 0xffff);
905         PrintNch(tmt[i].Sub, Buff);
906         i++;
907     }
908 
909     if(tmt[0].Number == -1)
910     {
911         printf("%s\n", Buff);
912     }
913 }
914 #endif
915 
Print(void)916 void NodeLists::Print(void)
917 {
918 #if 0
919     int tmc;
920     char Buff[1024];
921     NodeListElem * tmt;
922     printf("Index file: '%s'\n", IndexName);
923     printf("Total nodelists: '%d'\n", Lists);
924     tmt = NList;
925     tmc = Lists;
926 
927     while(tmc != 0)
928     {
929         printf("Nodelist name: '%s'\n", tmt->Name);
930         printf("Nodelist Date: '%d'\n", tmt->Time);
931         tmc--;
932         tmt++;
933     }
934     Buff[0] = '\0';
935     PrintNch(Index, Buff);
936 #endif
937 }
938 
IndexFile(char * File)939 void NodeLists::IndexFile(char * File)
940 {
941     if(IndexName != NULL)
942     {
943         free(IndexName);
944         IndexName = NULL;
945     }
946 
947     IndexName = strdup(File);
948 }
949 
CompileNeed(void)950 bool NodeLists::CompileNeed(void)
951 {
952     FILE * fh;
953     unsigned int tmp;
954     NodeListElem Elem;
955 
956 // 1 - does index file exist?
957     if(access(IndexName, F_OK) != 0)
958     {
959         IndexNotFound;
960         return TRUE;
961     }
962 
963 // 2 - can we open it?
964     fh = fopen(IndexName, "r+b");
965 
966     if(fh == NULL)
967     {
968         Log.Level(LOGE) << "Unable to open index file." << EOL;
969         return TRUE;
970     }
971 
972 // 3 - can we read the signature from it?
973     if(fread(&tmp, sizeof(tmp), 1, fh) != 1)
974     {
975         ErrReadIndex;
976         fclose(fh);
977         return TRUE;
978     }
979 
980 // 4 - is signature correct?
981     if(tmp != NdlSign)
982     {
983         Log.Level(LOGE) <<
984                         "Index file from the old version of RNtrack. Recompilation is necessary."
985                         <<
986                         EOL;
987         fclose(fh);
988         return TRUE;
989     }
990 
991 // 5 - can we read nodelist count?
992     if(fread(&tmp, sizeof(tmp), 1, fh) != 1)
993     {
994         ErrReadIndex;
995         fclose(fh);
996         return TRUE;
997     }
998 
999 // 6 - is the count of nodelists the same?
1000     if(tmp != (unsigned int)Lists)
1001     {
1002         IndexChanged;
1003         fclose(fh);
1004         return TRUE;
1005     }
1006 
1007 // 7 - have nodelists not changed?
1008     for(unsigned int i = 0; i < tmp; i++)
1009     {
1010         if(fread(&Elem, sizeof(Elem), 1, fh) != 1)
1011         {
1012             ErrReadIndex;
1013             fclose(fh);
1014             return TRUE;
1015         }
1016 
1017         if((MaxNodelistAge != (time_t)-1) && (NodelistTurnOff != TRUE))
1018         {
1019             if((time(NULL) - (NList + i)->Time) > MaxNodelistAge)
1020             {
1021                 Log.Level(LOGW) << "Nodelist '" <<
1022                                 (NList + i)->Name << "' too old." << EOL;
1023                 Log.Level(LOGI) <<
1024                                 "Checking existance in nodelists turned off." << EOL;
1025                 NodelistTurnOff = TRUE;
1026                 Log.Level(LOGD) << "Time  : " << (int)(time(NULL)) << EOL;
1027                 Log.Level(LOGD) << "NTime : " << (int)(NList + i)->Time << EOL;
1028                 Log.Level(LOGD) << "Age   : " <<
1029                                 (int)(time(NULL) - (NList + i)->Time) << EOL;
1030                 Log.Level(LOGD) << "MaxAge: " << (int)MaxNodelistAge << EOL;
1031             }
1032         }
1033 
1034         if(memcmp(&Elem, NList + i, sizeof(Elem)) != 0)
1035         {
1036             Log.Level(LOGD) <<
1037                             "NodeLists::CompileNeed. memcmp failed. Nodelist changed." << EOL;
1038             Log.Level(LOGD) << "--Information should be:" << EOL;
1039             Log.Level(LOGD) << "NName : " << (NList + i)->Name << EOL;
1040             Log.Level(LOGD) << "NTime : " << (int)(NList + i)->Time << EOL;
1041             Log.Level(LOGD) << "Zone  : " <<
1042                             (int)(NList + i)->StartZone << EOL;
1043             Log.Level(LOGD) << "--Information in index file:" << EOL;
1044             Log.Level(LOGD) << "NName : " << Elem.Name << EOL;
1045             Log.Level(LOGD) << "NTime : " << Elem.Time << EOL;
1046             Log.Level(LOGD) << "Zone  : " << Elem.StartZone << EOL;
1047             IndexChanged;
1048             fclose(fh);
1049             return TRUE;
1050         }
1051     }
1052     fclose(fh);
1053     return FALSE;
1054 } // CompileNeed
1055 
Names(char * Buff)1056 char * NodeLists::Names(char * Buff)
1057 {
1058     NodeListElem * Elem;
1059     int i;
1060     char * tmt;
1061 
1062     Buff[0] = '\0';
1063 
1064     for(Elem = NList, i = 0; i < Lists; Elem++, i++)
1065     {
1066         tmt = strrchr(Elem->Name, PATHDELIMC);
1067 
1068         if(tmt != NULL)
1069         {
1070             tmt++;
1071         }
1072         else
1073         {
1074             tmt = Elem->Name;
1075         }
1076 
1077         strcat(Buff, tmt);
1078 
1079         if(i + 1 < Lists)
1080         {
1081             strcat(Buff, ", ");
1082         }
1083     }
1084     return Buff;
1085 } // Names
1086 
Compile(void)1087 bool NodeLists::Compile(void)
1088 {
1089     FILE * fh;
1090     char * tmt;
1091     int tmp;
1092     int i;
1093 
1094 // 1  - Write new _empty_ header.
1095     fh = fopen(IndexName, "wb");
1096 
1097     if(fh == NULL)
1098     {
1099         Log.Level(LOGE) << "Unable to create index file." << EOL;
1100         return FALSE;
1101     }
1102 
1103     tmt = (char *)malloc(
1104               sizeof(NdlSign) + sizeof(int) + sizeof(NodeListElem) * Lists);
1105     CheckMem(tmt);
1106     memset(tmt, '\0',
1107            sizeof(NdlSign) + sizeof(int) + sizeof(NodeListElem) * Lists);
1108 
1109     if(fwrite(tmt, sizeof(NdlSign) + sizeof(int) + sizeof(NodeListElem) *
1110               Lists, 1, fh) != 1)
1111     {
1112         Log.Level(LOGE) <<
1113                         "Unable to write temporary header to index file." << EOL;
1114         fclose(fh);
1115         free(tmt);
1116         return FALSE;
1117     }
1118 
1119     free(tmt);
1120 
1121 // 2  - Write compiled nodelists.
1122 
1123     for(i = 0; i < Lists; i++)
1124     {
1125         if(!ParseOneNodelist(NList + i))
1126         {
1127             fclose(fh);
1128             return FALSE;
1129         }
1130     }
1131 
1132     if(!FlushNodelist(fh))
1133     {
1134         fclose(fh);
1135         return FALSE;
1136     }
1137 
1138 // 3  - Write new, true header.
1139 
1140     if(fseek(fh, 0, SEEK_SET) != 0)
1141     {
1142         Log.Level(LOGE) <<
1143                         "Unable to set pointer to the beginning of the index file." << EOL;
1144         fclose(fh);
1145         return FALSE;
1146     }
1147 
1148     tmp = NdlSign;
1149 
1150     if(fwrite(&tmp, sizeof(tmp), 1, fh) != 1)
1151     {
1152         Log.Level(LOGE) << "Unable to write a signature to the index file." <<
1153                         EOL;
1154         fclose(fh);
1155         return FALSE;
1156     }
1157 
1158     if(fwrite(&Lists, sizeof(Lists), 1, fh) != 1)
1159     {
1160         Log.Level(LOGE) <<
1161                         "Unable to write a Nodelist counter to the index file." << EOL;
1162         fclose(fh);
1163         return FALSE;
1164     }
1165 
1166     for(i = 0; i < Lists; i++)
1167     {
1168         if((MaxNodelistAge != (time_t)-1) && (NodelistTurnOff != TRUE))
1169         {
1170             if((time(NULL) - (NList + i)->Time) > MaxNodelistAge)
1171             {
1172                 Log.Level(LOGW) << "Nodelist '" <<
1173                                 (NList + i)->Name << "' too old." << EOL;
1174                 Log.Level(LOGI) <<
1175                                 "Checking of existence in nodelists is turned off." << EOL;
1176                 NodelistTurnOff = TRUE;
1177                 Log.Level(LOGD) << "Age   : " <<
1178                                 (int)(time(NULL) - (NList + i)->Time) << EOL;
1179                 Log.Level(LOGD) << "MaxAge: " << (int)MaxNodelistAge << EOL;
1180             }
1181         }
1182 
1183         if(fwrite(NList + i, sizeof(NodeListElem), 1, fh) != 1)
1184         {
1185             Log.Level(LOGE) <<
1186                             "Unable to write a Nodelist information to the index file." << EOL;
1187             fclose(fh);
1188             return FALSE;
1189         }
1190     }
1191     fclose(fh);
1192     return TRUE;
1193 } // Compile
1194 
1195 #ifdef _DEBUG
1196 
IPrint(Nch * Ind)1197 void IPrint(Nch * Ind)
1198 {
1199     if(Ind != NULL)
1200     {
1201         fprintf(stderr, "---%p>", Ind);
1202 
1203         while(Ind->Number != -1)
1204         {
1205             fprintf(stderr, " %u", Ind->Number);
1206             Ind++;
1207         }
1208         fprintf(stderr, "\n");
1209     }
1210 }
1211 
1212 #endif
LoadOneIndex(FILE * fh,Nch * & Ind)1213 bool NodeLists::LoadOneIndex(FILE * fh, Nch * & Ind)
1214 {
1215     unsigned int tmp;
1216     Nch * tmt;
1217     unsigned int i;
1218 
1219     if(fread(&tmp, sizeof(tmp), 1, fh) != 1)
1220     {
1221         return FALSE;
1222     }
1223 
1224     tmt = (Nch *)malloc((tmp + 1) * sizeof(Nch));
1225     CheckMem((char *)tmt);
1226     memset(tmt, 0, (tmp + 1) * sizeof(Nch));
1227     tmt[tmp].Number = (unsigned int)-1;
1228 
1229     for(i = 0; i < tmp; i++)
1230     {
1231         if(fread(&tmt[i].Number, sizeof(int), 1, fh) != 1)
1232         {
1233             return FALSE;
1234         }
1235     }
1236     Ind = tmt;
1237 
1238     for(i = 0; i < tmp; i++)
1239     {
1240         if(LoadOneIndex(fh, Ind[i].Sub) == FALSE)
1241         {
1242             return FALSE;
1243         }
1244     }
1245     return TRUE;
1246 } // LoadOneIndex
1247 
Load(void)1248 bool NodeLists::Load(void)
1249 {
1250     FILE * fh;
1251 
1252     if(!Enabled() || NodelistTurnOff)
1253     {
1254         return TRUE;
1255     }
1256 
1257     if(CompileNeed())
1258     {
1259         if(!Compile())
1260         {
1261             if(NodelistTurnOff)
1262             {
1263                 Log.Level(LOGN) << "Nodelists are not used." << EOL;
1264                 return TRUE;
1265             }
1266 
1267             return FALSE;
1268         }
1269     }
1270     else
1271     {
1272         if(NodelistTurnOff)
1273         {
1274             Log.Level(LOGN) << "Nodelists are not used." << EOL;
1275             return TRUE;
1276         }
1277     }
1278 
1279     fh = fopen(IndexName, "rb");
1280 
1281     if(fh == NULL)
1282     {
1283         Log.Level(LOGE) << "Unable to open index file." << EOL;
1284         return FALSE;
1285     }
1286 
1287     if(fseek(fh, sizeof(NdlSign) + sizeof(int) + sizeof(NodeListElem) * Lists,
1288              SEEK_SET) != 0)
1289     {
1290         Log.Level(LOGE) << "Unable to seek in index file." << EOL;
1291         return FALSE;
1292     }
1293 
1294     if(!LoadOneIndex(fh, Index))
1295     {
1296         Log.Level(LOGE) << "Unable to load index file." << EOL;
1297         return FALSE;
1298     }
1299 
1300     fclose(fh);
1301     return TRUE;
1302 } // Load
1303 
Srch(Nch * Addr,unsigned int Number)1304 Nch * NodeLists::Srch(Nch * Addr, unsigned int Number)
1305 {
1306     if(Addr == NULL)
1307     {
1308         return NULL;
1309     }
1310 
1311     while(Addr->Number != (unsigned int)-1)
1312     {
1313         if((Addr->Number & 0xffff) == (Number & 0xffff))
1314         {
1315             return Addr;
1316         }
1317 
1318         Addr++;
1319     }
1320     return NULL;
1321 }
1322 
FindHub(FA const & f)1323 unsigned int NodeLists::FindHub(FA const & f)
1324 {
1325     Nch * tmt;
1326     unsigned int currHub = 0;
1327 
1328 // If nodelists are switched off or it is necesary to say that a node exists
1329 // then return A_HOST for any address.
1330 // In other parts of this program compare return value of this
1331 // function only with (-1).
1332 
1333     if(NodelistTurnOff)
1334     {
1335         return 0;
1336     }
1337 
1338     if(ExistInNodelist(f) != (unsigned int)-1)
1339     {
1340         tmt = Srch(Index, f.Zone() & 0xffff);
1341 
1342         if(tmt == NULL)
1343         {
1344             return 0;
1345         }
1346 
1347         tmt = tmt->Sub;
1348         tmt = Srch(tmt, f.Net() & 0xffff);
1349 
1350         if(tmt == NULL)
1351         {
1352             return 0;
1353         }
1354 
1355         if(f.Node() == 0)
1356         {
1357             return 0;
1358         }
1359 
1360         tmt = tmt->Sub;
1361 
1362         while((tmt->Number & 0xffff) != (f.Node() & 0xffff))
1363         {
1364             if((tmt->Number & A_MASK) == A_HUB)
1365             {
1366                 currHub = tmt->Number;
1367             }
1368 
1369             if((((tmt + 1)->Number & 0xffff) == (f.Node() & 0xffff)) &&
1370                     (((tmt + 1)->Number & A_MASK) == A_HUB))
1371             {
1372                 currHub = (tmt + 1)->Number;
1373             }
1374 
1375             tmt++;
1376         }
1377     }
1378 
1379     if(currHub != 0)
1380     {
1381         currHub = currHub & 0xffff;
1382     }
1383 
1384     return currHub;
1385 } // FindHub
1386 
ExistInNodelist(FA const & f)1387 unsigned int NodeLists::ExistInNodelist(FA const & f)
1388 {
1389     Nch * tmt;
1390 
1391 // If nodelists are switched off or it is necesary to say that a node exists
1392 // then return A_HOST for any address.
1393 // In other parts of this program compare return value of this
1394 // function only with (-1).
1395 
1396     if(NodelistTurnOff)
1397     {
1398         return A_HOST;
1399     }
1400 
1401     tmt = Srch(Index, f.Zone() & 0xffff);
1402 
1403     if(tmt == NULL)
1404     {
1405         return (SoftCheckInNodelists == FALSE) ? (unsigned int)-1 : A_HOST;
1406     }
1407 
1408     tmt = tmt->Sub;
1409     tmt = Srch(tmt, f.Net() & 0xffff);
1410 
1411     if(tmt == NULL)
1412     {
1413         return (SoftCheckInNodelists == FALSE) ? (unsigned int)-1 : A_HOST;
1414     }
1415 
1416     if(f.Node() == 0)
1417     {
1418         return A_HOST;
1419     }
1420 
1421     tmt = tmt->Sub;
1422     tmt = Srch(tmt, f.Node() & 0xffff);
1423 
1424     if(tmt == NULL)
1425     {
1426         return (unsigned int)-1;
1427     }
1428 
1429     if((f.Point() & 0xffff) != 0)
1430     {
1431         switch(CheckPoints)
1432         {
1433         case CHECKPNT_HARD:
1434 
1435             if(Srch(tmt->Sub, f.Point() & 0xffff) == NULL)
1436             {
1437                 return (unsigned int)-1;
1438             }
1439 
1440             break;
1441 
1442         case CHECKPNT_SOFT:
1443 
1444             if(tmt->Sub == NULL)
1445             {
1446                 break;
1447             }
1448 
1449             if(tmt->Sub->Number == (unsigned int)-1)
1450             {
1451                 break;
1452             }
1453 
1454             if(Srch(tmt->Sub, f.Point() & 0xffff) == NULL)
1455             {
1456                 return (unsigned int)-1;
1457             }
1458 
1459             break;
1460 
1461         case CHECKPNT_NEVER:
1462             break;
1463         } // switch
1464     }
1465 
1466     return tmt->Number;
1467 } // ExistInNodelist
1468 
GetFlags(FA const & f)1469 unsigned int NodeLists::GetFlags(FA const & f)
1470 {
1471     Nch * tmt;
1472 
1473     if(NodelistTurnOff)
1474     {
1475         return A_NONE;
1476     }
1477 
1478     tmt = Srch(Index, f.Zone() & 0xffff);
1479 
1480     if(tmt == NULL)
1481     {
1482         return A_NONODE;
1483     }
1484 
1485     tmt = tmt->Sub;
1486     tmt = Srch(tmt, f.Net() & 0xffff);
1487 
1488     if(tmt == NULL)
1489     {
1490         return A_NONODE;
1491     }
1492 
1493     if(f.Node() == 0)
1494     {
1495         return A_HOST;
1496     }
1497 
1498     tmt = tmt->Sub;
1499     tmt = Srch(tmt, f.Node() & 0xffff);
1500 
1501     if(tmt == NULL)
1502     {
1503         return A_NONODE;
1504     }
1505 
1506     return tmt->Number;
1507 } // GetFlags
1508 
SayNodelistFlags(FA const & f)1509 void SayNodelistFlags(FA const & f)
1510 {
1511     unsigned int i;
1512 
1513     i = Ndl.GetFlags(f);
1514 
1515     if(i == A_NONODE)
1516     {
1517         Log.Level(LOGD) << "NONODE";
1518         return;
1519     }
1520 
1521     i &= A_MASK;
1522 
1523     if(i == A_DOWN)
1524     {
1525         Log.Level(LOGD) << "DOWN";
1526     }
1527 
1528     if(i == A_HOLD)
1529     {
1530         Log.Level(LOGD) << "HOLD";
1531     }
1532 
1533     if(i == A_HUB)
1534     {
1535         Log.Level(LOGD) << "HUB";
1536     }
1537 
1538     if(i == A_HOST)
1539     {
1540         Log.Level(LOGD) << "HOST";
1541     }
1542 
1543     if(i == A_PVT)
1544     {
1545         Log.Level(LOGD) << "PVT";
1546     }
1547 
1548     if(i == A_REGION)
1549     {
1550         Log.Level(LOGD) << "REGION";
1551     }
1552 } // SayNodelistFlags
1553 
InSubHubs(FA const & Addr,FA const & Mask)1554 bool NodeLists::InSubHubs(FA const & Addr, FA const & Mask)
1555 {
1556     Nch * tmt;
1557     bool Existing;
1558 
1559 // If the node used as a mask is in the nodelist and it is a hub or host
1560 // then check if the Addr belongs to the "subhub" list of nodes linked in
1561 // the nodelist to the hub or to the host. Otherwise check a point.
1562 // And there is a mess with regions. Blast them thrice together with
1563 // those who developed Fidonet standards.
1564 
1565     Existing = (ExistInNodelist(Addr) == (unsigned int)-1 ? FALSE : TRUE);
1566 
1567 // Node is equal Mask?
1568     if((Addr.Zone() & 0xffff) == (Mask.Zone() & 0xffff) &&
1569             (Addr.Net() & 0xffff) == (Mask.Net() & 0xffff) &&
1570             (Addr.Node() & 0xffff) == (Mask.Node() & 0xffff))
1571     {
1572         if((Addr.Point() & 0xffff) != 0)
1573         {
1574             return Existing;
1575         }
1576 
1577         return TRUE;
1578     }
1579 
1580     if(Existing == FALSE)
1581     {
1582         return FALSE;
1583     }
1584 
1585 // Is the node in the same zone?
1586     if((Addr.Zone() & 0xffff) != (Mask.Zone() & 0xffff))
1587     {
1588         return FALSE;
1589     }
1590 
1591 // Search the zone of mask.
1592     tmt = Srch(Index, Mask.Zone() & 0xffff);
1593 
1594     if(tmt == NULL)
1595     {
1596 //      Log.Level(LOGD) << "Zone " << (Mask.Zone() & 0xffff) << " missing" <<
1597         // EOL;
1598         return FALSE;
1599     }
1600 
1601     tmt = tmt->Sub;
1602 
1603     if(tmt == NULL)
1604     {
1605 //      Log.Level(LOGD) << "Zone " << (Mask.Zone() & 0xffff) << " Empty" << EOL;
1606         return FALSE;
1607     }
1608 
1609 // Search the Net of mask.
1610     tmt = Srch(tmt, Mask.Net() & 0xffff);
1611 
1612     if(tmt == NULL)
1613     {
1614 //      Log.Level(LOGD) << "Net " << (Mask.Zone() & 0xffff) << ":" <<
1615         // (Mask.Net() & 0xffff) << " missing" << EOL;
1616         return FALSE;
1617     }
1618 
1619     if((tmt->Number & A_MASK) == A_REGION)
1620     {
1621         if((Mask.Node() & 0xffff) == 0)
1622         {
1623             // Mask to region. Search net.
1624             while(tmt->Number != (unsigned int)-1)
1625             {
1626                 if((tmt->Number & 0xffff) == (Addr.Net() & 0xffff))
1627                 {
1628                     // The net is found. Search node.
1629                     tmt = tmt->Sub;
1630 
1631                     if(tmt == NULL)
1632                     {
1633                         return FALSE;
1634                     }
1635 
1636                     if((Addr.Node() & 0xffff) == 0)
1637                     {
1638                         return TRUE;
1639                     }
1640 
1641                     if(Srch(tmt, Addr.Node() & 0xffff) == NULL)
1642                     {
1643                         return FALSE;
1644                     }
1645                     else
1646                     {
1647                         return TRUE;
1648                     }
1649                 }
1650 
1651                 tmt++;
1652 
1653                 if((tmt->Number & A_MASK) == A_REGION)
1654                 {
1655                     // Next region began but net was not found...
1656                     return FALSE;
1657                 }
1658             }
1659             return FALSE;
1660         }
1661     }
1662 
1663     if((Addr.Net() & 0xffff) != (Mask.Net() & 0xffff))
1664     {
1665 //      Log.Level(LOGD) << "Node " << Addr << " not equal to mask " << Mask << "
1666 // and mask is not a regional mask." << EOL;
1667         return FALSE;
1668     }
1669 
1670     tmt = tmt->Sub;
1671 
1672     if(tmt == NULL)
1673     {
1674 //      Log.Level(LOGD) << "Node " << Addr << " not equal to mask " << Mask << "
1675 // and no nodes in mask net." << EOL;
1676         return FALSE;
1677     }
1678 
1679     // If the mask is a HOST then the beginning has already been found.
1680     // Otherwise continue the search.
1681     if((Mask.Node() & 0xffff) != 0)
1682     {
1683         tmt = Srch(tmt, Mask.Node() & 0xffff);
1684 
1685         if(tmt == NULL)
1686         {
1687             return FALSE;
1688         }
1689 
1690         // if Mask is not a hub - leave.
1691         if((tmt->Number & A_MASK) != A_HUB)
1692         {
1693             return FALSE;
1694         }
1695 
1696         tmt++;
1697     }
1698 
1699     // Ok. We have the beginning of the list.
1700     // Search the node down to a hub or to the end of the list.
1701     while(tmt->Number != (unsigned int)-1 && (tmt->Number & A_MASK) != A_HUB)
1702     {
1703         if((tmt->Number & 0xffff) == (Addr.Node() & 0xffff))
1704         {
1705             return Existing;
1706         }
1707 
1708         tmt++;
1709     }
1710     return FALSE;
1711 } // InSubHubs
1712 
AddNodelist(char * tmt,int TempZone)1713 int NodeLists::AddNodelist(char * tmt, int TempZone)
1714 {
1715     char Buff[512];
1716     struct stat NdlStat;
1717     NodeListElem * Elem;
1718 
1719     memset(Buff, 0, 512);
1720 
1721     if(strlen(tmt) == 0)
1722     {
1723         yyerror("Missing parameter: nodelist name or mask.");
1724         return -1;
1725     }
1726 
1727     if((TempZone <= 0) && (TempZone != -3))
1728     {
1729         yyerror("Zone number must be between 1 and 65535");
1730         return -1;
1731     }
1732 
1733     if(TempZone != -3)
1734     {
1735         StartZone = TempZone;
1736     }
1737     else
1738     {
1739         StartZone = 0;
1740     }
1741 
1742     if(FindNodelist(tmt, Buff) != 0)
1743     {
1744         return -1;
1745     }
1746 
1747     if(stat(Buff, &NdlStat) != 0)
1748     {
1749         Log.Level(LOGE) << "Unable to get information about nodelist '" <<
1750                         Buff << "'." << EOL;
1751         return -1;
1752     }
1753 
1754     Elem = (NodeListElem *)malloc(sizeof(NodeListElem) + 100);
1755     CheckMem((char *)Elem);
1756     memcpy(Elem->Name, Buff, 512);
1757     Elem->Time = NdlStat.st_mtime;
1758     Elem->StartZone = StartZone;
1759     Log.Level(LOGD) << "NTime : " << (int)Elem->Time << EOL;
1760 
1761     if(NList == NULL)
1762     {
1763         NList = Elem;
1764         Lists = 1;
1765     }
1766     else
1767     {
1768         tmt = (char *)realloc(NList, (Lists + 1) * sizeof(NodeListElem));
1769         CheckMem((char *)tmt);
1770         NList = (NodeListElem *)tmt;
1771         memcpy(NList + Lists, Elem, sizeof(NodeListElem));
1772         Lists++;
1773         free(Elem);
1774     }
1775 
1776     return 0;
1777 } // AddNodelist
1778 
1779 // --------------------------------------------------------------------
1780 
SetMaxNodelistAge(int tmt)1781 int SetMaxNodelistAge(int tmt)
1782 {
1783     if(MaxNodelistAge != (time_t)-1)
1784     {
1785         yyerror("Max nodelists age already set.");
1786         return -1;
1787     }
1788 
1789     if(tmt < 1)
1790     {
1791         yyerror("Parameter must be a number greater than 0.");
1792         return -1;
1793     }
1794 
1795     MaxNodelistAge = tmt * 24 * 60 * 60;
1796     return 0;
1797 }
1798 
1799 // --------------------------------------------------------------------
1800 
SetNodelist(char * tmt,int TempZone)1801 int SetNodelist(char * tmt, int TempZone)
1802 {
1803     return Ndl.AddNodelist(tmt, TempZone);
1804 }
1805