1 // $Id$
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 
16 #if defined (__TSC__)
17 # pragma call(inline_max => 150)
18 #endif
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <time.h>
24 #if defined (__TSC__)
25 # include <alloc.h>
26 # include <dir.h>
27 # define EOLCHR "\n"
28 #elif defined (__WATCOMC__)
29 # include <malloc.h>
30 # include <direct.h>
31 # include <io.h>
32 
33 # define fnsplit _splitpath
34 # define fnmerge _makepath
35 
36 # define EOLCHR "\n"
37 
38 # if defined (__OS2__)
39 #  define _OS2 1
40 # endif
41 #elif defined(__GNUC__)
42 //  #include <malloc.h>
43 # include <sys/param.h>         // for MAXPATHLEN
44 # include <dirent.h>
45 # include <unistd.h>
46 # include <glob.h>
47 
48 # define strnicmp(x,y,z) strncasecmp(x,y,z)
49 # define stricmp(x,y) strcasecmp(x,y)
50 # define itoa(i,a,base) (sprintf(a,"%i",i),a)
51 
52 # define EOLCHR "\n"
53 # define link linkd
54 
55 #elif defined (__MSVC__)
56 # include <io.h>
57 # define EOLCHR "\n"
58 # define MAXDRIVE  3
59 # define fnsplit _splitpath
60 # define fnmerge _makepath
61 #endif
62 
63 #define VERSION   "1.37"
64 #define CREATED   "%c %s routing for %d:%d/%d. Created by Hubroute generator "VERSION""EOLCHR"%c %45s%c"EOLCHR""
65 #ifdef _TARGET
66 # if defined (__GNUC__)
67 #  define TARGET "GNU/" _TARGET
68 # else
69 #  define TARGET _TARGET
70 # endif
71 #else /*defined (__GNUC__) */
72 # if defined(_OS2) || defined (__OS2__)
73 #  define TARGET "OS/2"
74 # elif defined (__NT__) && defined (_WIN64)
75 #  define TARGET "w64"
76 # elif defined (__NT__)
77 #  define TARGET "w32"
78 # elif defined (__DJGPP__)
79 #  define TARGET "dpmi-djgpp"
80 # elif defined (__GNUC__)
81 #  define TARGET "GNU/Unix"
82 # else
83 #  define TARGET "DOS"
84 # endif
85 #endif
86 
87 #ifdef boolean
88 # undef boolean
89 #endif
90 
91 typedef unsigned short ushort;
92 typedef unsigned long ulong;
93 typedef unsigned short boolean;
94 
95 struct nodeaddr
96 {
97   ushort z, n, f;
nodeaddrnodeaddr98   nodeaddr( ushort zz = 0, ushort nn = 0, ushort ff = 0 ):z( zz ), n( nn ), f( ff )
99   {
100   };
operator ==nodeaddr101   boolean operator==( nodeaddr & a )
102   {
103     return z == a.z && n == a.n && f == a.f;
104   };
CleanUpnodeaddr105   void CleanUp( void )
106   {
107     z = n = f = 0;
108   }
109 };
110 
111 struct listitem
112 {
113   ushort idx;                   // uplink index in file
114   ushort is_uplink;             // is first in route.raw
115   nodeaddr addr;
116 };
117 
118 struct link
119 {
120   ushort flavor;
121   nodeaddr addr;
122 };
123 
124 struct CfgValue
125 {
126   const char *Name;
127   void *Value;
128   ushort Pass;
129     boolean( *LoadVal ) ( char *in, void *out );
130 };
131 
132 static const char *ErrNoMemory = EOLCHR "Unable to allocate memory.";
133 static const char *ErrOpenCfg = EOLCHR "Unable to open config file.";
134 static const char *ErrNoFile = "Unable to open file.";
135 static const char *ErrOpenTmp = EOLCHR "Unable to open temp file.";
136 static const char *ErrOpenTmpX = EOLCHR "Unable to open temp file \"%s\"." EOLCHR;
137 static const char *ErrOpenDest = EOLCHR "Unable to open dest file.";
138 static const char *ErrUnknownRouteType = EOLCHR "Unsupported route type.";
139 static const char *ErrUnknownMinType = EOLCHR "Illegal value of \"Minimized\".";
140 static const char *ErrQuoteString = "Illegal quoted string.";
141 static const char *ErrMissMainAddr = EOLCHR "Missing or illegal main address.";
142 static const char *ErrMissRouteType = EOLCHR "Missing \"RouteType\" keyword.";
143 static const char *ErrMissMinType = EOLCHR "Missing \"Minimize\" keyword. YES Accepted.";
144 static const char *ErrNoReplEnd = EOLCHR "Missing \"RouteEnd\" in dest file.";
145 static const char *ErrNoReplBeg = EOLCHR "Missing \"RouteBegin\" in dest file.";
146 static const char *ErrBadNdlType = "Bad \"HubRoute\" definition.";
147 static const char *ErrMissDirect =
148   EOLCHR "%s is routed via us, but missing in \"Link\" definitions." EOLCHR
149   " \'DefaultFlavor\' assumed.";
150 static const char *ErrReroute = EOLCHR "Rerouting for %s.";
151 static const char *ErrLoop = EOLCHR "RouteLoop detected for %s. Try to route by default";
152 static const char *WarnNoMin = EOLCHR "Unable to minimize tree - out of memory";
153 
154 #define Error(s)   fprintf(stderr,"%s" EOLCHR,s)
155 #define ErrorS(s,str)   fprintf(stderr,s,str)
156 #define ErrorL(s)  fprintf(stderr, "%s %d: %s" EOLCHR, CfgFile, CfgLine, s)
157 
158 #define true     1
159 #define false    0
160 
161 #define ItemNum(arr) (sizeof(arr)/sizeof(arr[0]))
162 
163 #define MAXNODES  5000
164 #define MAXWILD   2000
165 #define MAXLINKS  1000
166 #define MAXAKAS   50
167 #define BUFFLEN   30000
168 #define PATHLEN   100
169 #define WILDVALUE 0xFFFF
170 #define DEADLOCK_DEPTH  10
171 int MAX_ROUTE_LEN = 64;
172 
173 enum
174 {
175   DIRECT_FLAVOR = 1, CRASH_FLAVOR = 2, HOLD_FLAVOR = 4,
176   NORMAL_FLAVOR = 16, FILE_FLAVOR = 32, NOARC_FLAVOR = 64
177 };
178 
179 static ushort DefaultFlavor = HOLD_FLAVOR;
180 
181 #if defined (__WATCOMC__)
182 # define MAXPATH 256
183 # define MAXDRIVE  3
184 # define MAXDIR  256
185 # define MAXFILE NAME_MAX
186 # define MAXEXT  NAME_MAX
187 #elif defined (__GNUC__)  || (__MSVC__)
188 # ifdef MAXPATHLEN
189 #  define MAXPATH MAXPATHLEN
190 # else
191 #  define MAXPATH 512
192 # endif
193 # define MAXDIR  MAXPATH
194 # define MAXFILE MAXPATH
195 # define MAXEXT  MAXPATH
196 #endif
197 
198 #if defined(__GNUC__)
199 static char TempFile[MAXPATH];
200 
201 #else
202 static char TempFile[MAXPATH];
203 static char OutDrv[MAXDRIVE];
204 #endif
205 
206 #if !defined (__GNUC__)
207 static char OutDir[MAXDIR];
208 static char OutName[MAXFILE];
209 static char OutExt[MAXEXT];
210 #endif
211 
212 #define SQUISH    1
213 #define ITRACK    2
214 #define TMAIL     3
215 #define BPACK     4
216 #define IMBINK    5
217 #define XMAIL     6
218 #define IFMAIL    7
219 #define BIP       8
220 #define UNIMAIL   9
221 #define QECHO     10
222 #define FIDOGATE  11
223 #define FTRACK    12
224 #define HUSKY     13
225 static ushort RouteMode = 0;
226 static ushort MinMode = 0;
227 static ushort KillTransit = 0;
228 
229 #if defined (__GNUC__)
230 glob_t globbuf;
231 #endif
232 
233 static char *Buff;
234 static char *Prefix;
235 static nodeaddr PrevNode;
236 static nodeaddr *MyNode = NULL;
237 static nodeaddr UpNode( 0, 0, 0 );      // t-mail routing only
238 static link *Link;
239 static listitem *Node;
240 static listitem *WildNode;      // Wildcards in nodelist
241 static ushort nNodes = 0, nLinks = 0, nAKAs = 0, nWilds = 0;
242 static ushort level;            // 0 - node, 1 - net, 2 - zone, 3 - world
243 static time_t currtime;
244 static char *CfgFile;
245 static ushort CfgLine;
246 static char WriteTo[PATHLEN];
247 static FILE *NewRoute;
248 static FILE *OldRoute;
249 
250 #define Spit(s) { fputs(s, NewRoute); fputs(EOLCHR, NewRoute); }
251 static char RouteBegin[100];
252 static char RouteEnd[100];
253 static boolean StarWild, AddPoint, DefaultFromMe, FullAddr, FillRoute, WithSlash, TmailAddFor;
254 static char CmntSym = '#';
255 
InMemory(nodeaddr addr)256 static ushort InMemory( nodeaddr addr )
257 {
258   for( ushort i = 0; i < nNodes; i++ )
259     if( Node[i].addr == addr )
260       return i;
261   return 0xFFFF;
262 }
263 
IsMyNode(nodeaddr addr)264 static boolean IsMyNode( nodeaddr addr )
265 {
266   int i;
267   for( i = 0; i < nAKAs; i++ )
268     if( MyNode[i] == addr )
269       return true;
270   return false;
271 }
272 
DirectLink(ushort Idx)273 static boolean DirectLink( ushort Idx )
274 {
275   int i;
276   for( i = 0; i < nLinks; i++ )
277     if( Link[i].addr == Node[Idx].addr )
278       return true;
279   return false;
280 }
281 
DirectLink(nodeaddr n)282 static boolean DirectLink( nodeaddr n )
283 {
284   int i;
285   for( i = 0; i < nLinks; i++ )
286     if( Link[i].addr == n )
287       return true;
288   return false;
289 }
290 
skipws(char ** p)291 inline void skipws( char **p )
292 {
293   while( **p == ' ' || **p == '\t' || **p == '\r' )
294     ( *p )++;
295 }
296 
getnum(char ** p)297 static ushort getnum( char **p )
298 {
299   int i = 0;
300   while( isdigit( **p ) )
301     i = i * 10 + ( *( ( *p )++ ) - '0' );
302   return ( ushort ) i;
303 }
304 
ScanNode(char ** p)305 static nodeaddr ScanNode( char **p )
306 {
307   nodeaddr addr = PrevNode;
308   ushort tmp, mode;
309 
310 #define START 1
311 #define SCAN  2
312 #define DONE  3
313   skipws( p );
314   mode = START;
315   while( mode != DONE )
316   {
317     switch ( mode )
318     {
319     case START:
320       if( strnicmp( *p, "World", 5 ) == 0 )
321       {
322         addr.z = addr.n = addr.f = WILDVALUE;
323         PrevNode = *MyNode;     // _Main_ aka
324         *p += 5;
325         return addr;
326       }
327     case SCAN:
328       skipws( p );
329       if( strnicmp( *p, "All", 3 ) == 0 )
330       {
331         tmp = WILDVALUE;
332         *p += 3;
333       }
334       else if( **p == '*' )
335       {
336         tmp = WILDVALUE;
337         *p += 1;
338       }
339       else
340         tmp = getnum( p );
341       switch ( **p )
342       {
343       case ':':
344         addr.z = tmp;
345         mode = SCAN;
346         ( *p )++;
347         break;
348       case '/':
349         addr.n = tmp;
350         mode = SCAN;
351         ( *p )++;
352         break;
353       default:
354         addr.f = tmp;
355         mode = DONE;
356       }
357     }
358   }
359   PrevNode = addr;
360 
361   // Skip unnesessary tail such as point address etc.
362   while( **p != ' ' && **p != '\t' && **p != '\r' && **p != '\n' && **p != '\0' )
363     ( *p )++;
364   return addr;
365 
366 #undef START
367 #undef SCAN
368 #undef DONE
369 }
370 
WriteNode(nodeaddr Node,char * out,short addrtype)371 static ushort WriteNode( nodeaddr Node, char *out, short addrtype )
372 {
373   char tmp[10];
374   ushort wildlevel = 0;
375   if( Node.f == WILDVALUE )
376     wildlevel++;
377   if( Node.n == WILDVALUE )
378     wildlevel++;
379   if( Node.z == WILDVALUE )
380     wildlevel++;
381   if( wildlevel == level || addrtype == 1 )
382   {
383     const char *Wild = ( StarWild ) ? "*" : "All";
384     strcat( out, " " );
385     if( Node.z == WILDVALUE && Node.n == WILDVALUE && Node.n == WILDVALUE )
386       strcat( out, StarWild ? "*:*/*" : "World" );
387     else
388     {
389       if( addrtype || FullAddr || Node.z != PrevNode.z )
390       {
391         strcat( out, itoa( Node.z, tmp, 10 ) );
392         strcat( out, ":" );
393       }
394       if( addrtype || FullAddr || Node.n != PrevNode.n || Node.f == WILDVALUE )
395       {
396         strcat( out, Node.n != WILDVALUE ? itoa( Node.n, tmp, 10 ) : Wild );
397         if( !WithSlash )
398           strcat( out, "/" );
399       }
400       if( WithSlash )
401         strcat( out, "/" );
402       strcat( out, Node.f != WILDVALUE ? itoa( Node.f, tmp, 10 ) : Wild );
403     }
404     if( AddPoint && !addrtype )
405       strcat( out, ".*" );
406     if( DefaultFromMe )
407       PrevNode = *MyNode;       // Main aka
408     else
409       PrevNode = Node;
410   }
411   return ( ushort ) strlen( out );
412 }
413 
StrNode(nodeaddr Node)414 static char *StrNode( nodeaddr Node )
415 {
416   static char buff[40];
417   boolean tmp = FullAddr;
418   buff[0] = '\0';
419   FullAddr = true;
420   buff[WriteNode( Node, buff, 1 )] = '\0';
421   FullAddr = tmp;
422   return buff;
423 }
424 
TestCmpQuality(nodeaddr & S,nodeaddr & D)425 static ushort TestCmpQuality( nodeaddr & S, nodeaddr & D )
426 {
427   ushort Q = 0;
428   if( ( D.z != WILDVALUE && S.z != D.z ) ||
429       ( D.n != WILDVALUE && S.n != D.n ) || ( D.f != WILDVALUE && S.f != D.f ) )
430     return 0;                   // Not match
431 
432   if( D.z == WILDVALUE )
433     Q++;
434   else
435     Q += 2;
436 
437   if( D.n == WILDVALUE )
438     Q += 10;
439   else
440     Q += 20;
441 
442   if( D.f == WILDVALUE )
443     Q += 100;
444   else
445     Q += 200;                   // Who cares... :)
446 
447   return Q;
448 }
449 
FixWildcard(void)450 static void FixWildcard( void )
451 {
452   ushort i;
453   for( i = 0; i < nNodes; i++ )
454   {
455     // Fix wildcard such as All:5020/All to All:All/All etc.
456     if( Node[i].addr.z == WILDVALUE )
457       Node[i].addr.n = WILDVALUE;
458     if( Node[i].addr.n == WILDVALUE )
459       Node[i].addr.f = WILDVALUE;
460     ushort MaxQuality, MaxQualityIdx, cmp;
461     MaxQuality = 0;
462 
463     // Try to route unrouted items to nearest wildcard
464     if( Node[i].idx == WILDVALUE && !DirectLink( i ) )  // not routed
465     {
466       ushort j;
467       for( j = 0; j < nNodes; j++ )
468         if( Node[j].idx != WILDVALUE )  // is routed
469           if( ( cmp = TestCmpQuality( Node[i].addr, Node[j].addr ) ) > MaxQuality )
470           {
471             MaxQuality = cmp;
472             MaxQualityIdx = j;
473           }
474       if( MaxQuality > 0 )      // found correct match
475       {
476         boolean deadlock = false;
477         ushort idx = MaxQualityIdx;
478 
479         // Try to recognize route-loop such as 2:5020/50 <= 2:5020/All
480         for( j = 0; j < DEADLOCK_DEPTH && !deadlock; j++ )
481           if( i == idx )        // We catch the same node
482             deadlock = true;
483 
484           else if( idx != WILDVALUE )   // Catch unrouted
485             idx = Node[idx].idx;
486 
487           else                  // idx == WILDVALUE - unrouted (may be direct)
488             break;
489         if( !deadlock )
490           Node[i].idx = MaxQualityIdx;
491       }
492     }
493   }
494 
495   // Fixup my downlinks if they are undefined as Direct links
496   for( i = 0; i < nNodes; i++ ) // Look for my downlinks
497   {
498     if( Node[i].idx != WILDVALUE && IsMyNode( Node[Node[i].idx].addr ) && !DirectLink( i ) )
499     {
500       Link[nLinks].addr = Node[i].addr;
501       Link[nLinks].flavor = DefaultFlavor;
502       nLinks++;
503       ErrorS( ErrMissDirect, StrNode( Node[i].addr ) );
504     }
505   }
506 
507   // Make the tree one-leveled
508   for( i = 0; i < nNodes; i++ )
509   {
510     if( Node[i].idx != WILDVALUE )      // routed
511     {
512       nodeaddr Orig = Node[i].addr;
513       while( !( Node[Node[i].idx].idx == WILDVALUE ||
514                 ( DirectLink( Node[i].idx ) && Node[Node[i].idx].addr.f != 0xFFFF ) ) )
515       {
516         Node[i].idx = Node[Node[i].idx].idx;
517         if( Node[Node[i].idx].addr == Orig )    // Loop detected
518         {
519           ErrorS( ErrLoop, StrNode( Node[Node[i].idx].addr ) );
520           Node[Node[i].idx].idx = WILDVALUE;
521           break;
522         }
523       }
524     }
525   }
526 }
527 
IsWild(nodeaddr n)528 static boolean IsWild( nodeaddr n )
529 {
530   return ( n.z == WILDVALUE || n.n == WILDVALUE || n.f == WILDVALUE ) ? true : false;
531 }
532 
CmpWild(void const * l1,void const * l2)533 int CmpWild( void const *l1, void const *l2 )
534 {
535   if( ( ( listitem * ) l1 )->addr.z > ( ( listitem * ) l2 )->addr.z )
536     return 1;
537 
538   else if( ( ( listitem * ) l1 )->addr.z < ( ( listitem * ) l2 )->addr.z )
539     return -1;
540 
541   else if( ( ( listitem * ) l1 )->addr.n > ( ( listitem * ) l2 )->addr.n )
542     return 1;
543 
544   else if( ( ( listitem * ) l1 )->addr.n < ( ( listitem * ) l2 )->addr.n )
545     return -1;
546 
547   else if( ( ( listitem * ) l1 )->addr.f > ( ( listitem * ) l2 )->addr.f )
548     return 1;
549 
550   else if( ( ( listitem * ) l1 )->addr.f < ( ( listitem * ) l2 )->addr.f )
551     return -1;
552 
553   else
554     return 0;
555 }
556 
RemoveUnnecessary(void)557 static void RemoveUnnecessary( void )
558 {
559   ushort i, j;
560 
561   // Remove double-routed nodes if it's up-wild routed by the same way
562   if( MinMode )
563   {
564     WildNode = ( listitem * ) calloc( MAXWILD, sizeof( listitem ) );
565     if( WildNode != NULL )
566     {
567       for( i = 0; i < nNodes; i++ )
568         if( IsWild( Node[i].addr ) )
569           WildNode[nWilds++] = Node[i];
570       qsort( WildNode, nWilds, sizeof( listitem ), CmpWild );
571       for( i = 0; i < nNodes; i++ )
572       {
573         if( Node[i].idx != WILDVALUE )  // routed
574         {
575           for( j = 0; j < nWilds; j++ )
576           {
577             if( !( Node[i].addr == WildNode[j].addr ) &&
578                 TestCmpQuality( Node[i].addr, WildNode[j].addr ) > 0 )
579             {
580               if( Node[i].idx == WildNode[j].idx && !DirectLink( i ) )
581                 Node[i].idx = 0xFFFE;
582               break;
583             }
584           }
585         }
586       }
587       free( WildNode );
588     }
589     else
590       Error( WarnNoMin );
591   }
592 }
593 
GetFlavor(link * pLink,const char * Flav[])594 static const char *GetFlavor( link * pLink, const char *Flav[] )
595 {
596   if( pLink->flavor & CRASH_FLAVOR )
597     return Flav[0];
598 
599   else if( pLink->flavor & DIRECT_FLAVOR )
600     return Flav[1];
601 
602   else if( pLink->flavor & HOLD_FLAVOR )
603     return Flav[2];
604 
605   else
606     return Flav[3];
607 }
608 
609 const char *SqFlavors[] = {
610   "Crash ", "Direct", "Hold  ", "Normal"
611 };
612 
MakeSqPrefix(link * pLink,char * out)613 static void MakeSqPrefix( link * pLink, char *out )
614 {
615   strcpy( out, "Route " );
616   strcat( out, GetFlavor( pLink, SqFlavors ) );
617   if( pLink->flavor & FILE_FLAVOR )
618     strcat( out, " file" );
619   else
620     strcat( out, "     " );
621 
622   if( pLink->flavor & NOARC_FLAVOR )
623     strcat( out, " NoArc" );
624   else
625     strcat( out, "      " );
626 
627   WriteNode( pLink->addr, out, 1 );
628   strcat( out, " " );
629 }
630 
PutDirects(ushort mask,ushort pattern,const char * Pfix)631 static void PutDirects( ushort mask, ushort pattern, const char *Pfix )
632 {
633   int i;
634   PrevNode = *MyNode;           // Main aka
635   strcpy( Buff, Pfix );
636   strcpy( Prefix, Pfix );
637   for( i = 0; i < nLinks; i++ )
638   {
639     if( ( Link[i].flavor & mask ) == pattern )
640       if( WriteNode( Link[i].addr, Buff, 0 ) >= MAX_ROUTE_LEN )
641       {
642         Spit( Buff );           // Spit out
643         strcpy( Buff, Prefix );
644         PrevNode = *MyNode;     // Main aka
645       }
646   }
647   if( strcmp( Buff, Prefix ) != 0 )
648     Spit( Buff );
649 }
650 
PutDownLinksGeneric(ushort UpIdx,ushort type,ushort (* wrtnode)(nodeaddr,char *,ushort))651 static void PutDownLinksGeneric( ushort UpIdx, ushort type,
652                                  ushort( *wrtnode ) ( nodeaddr, char *, ushort ) )
653 {
654   ushort i;
655   for( i = 0; i < nNodes; i++ )
656   {
657     if( Node[i].idx == UpIdx && !DirectLink( i ) && !IsMyNode( Node[i].addr ) &&
658         ( ( UpIdx != WILDVALUE && Node[i].idx != i ) ||
659           ( UpIdx == WILDVALUE && Node[i].is_uplink ) ) )
660     {
661       if( wrtnode( Node[i].addr, Buff, type ) >= MAX_ROUTE_LEN )
662       {
663         if( UpNode.z != 0 )
664         {
665           wrtnode( UpNode, Buff, 1 );
666           PrevNode = *MyNode;
667         }
668         Spit( Buff );           // Spit out
669         strcpy( Buff, Prefix );
670         if( UpIdx != WILDVALUE && UpNode.z == 0 )
671           PrevNode = Node[UpIdx].addr;
672       }
673       if( FillRoute )           // Prevents duplication in 'Unrouted'
674         Node[i].idx = 0;
675       else
676         PutDownLinksGeneric( i, type, wrtnode );
677     }
678   }
679 }
680 
PutDownLinks(ushort UpIdx,ushort type)681 static void PutDownLinks( ushort UpIdx, ushort type )
682 {
683   ushort i;
684   for( i = 0; i < nNodes; i++ )
685   {
686     if( Node[i].idx == UpIdx && !DirectLink( i ) && !IsMyNode( Node[i].addr ) &&
687         ( ( UpIdx != WILDVALUE && Node[i].idx != i ) ||
688           ( UpIdx == WILDVALUE && Node[i].is_uplink ) ) )
689     {
690       if( WriteNode( Node[i].addr, Buff, type ) >= MAX_ROUTE_LEN )
691       {
692         if( UpNode.z != 0 )
693         {
694           WriteNode( UpNode, Buff, 1 );
695           PrevNode = *MyNode;
696         }
697         Spit( Buff );           // Spit out
698         strcpy( Buff, Prefix );
699         if( UpIdx != WILDVALUE && UpNode.z == 0 )
700           PrevNode = Node[UpIdx].addr;
701       }
702 
703       if( FillRoute )           // Prevents duplication in 'Unrouted'
704         Node[i].idx = 0;
705       else
706         PutDownLinks( i, type );
707     }
708   }
709 }
710 
711 static const char *RouteType[] = {
712   "Nodes", "Nets", "Zones", "Default"
713 };
714 
DirectsSQ(void)715 static void DirectsSQ( void )
716 {
717   PutDirects( CRASH_FLAVOR | NOARC_FLAVOR, CRASH_FLAVOR, "Send Crash  " );
718   PutDirects( DIRECT_FLAVOR | NOARC_FLAVOR, DIRECT_FLAVOR, "Send Direct " );
719   PutDirects( HOLD_FLAVOR | NOARC_FLAVOR, HOLD_FLAVOR, "Send Hold   " );
720   PutDirects( NORMAL_FLAVOR | NOARC_FLAVOR, NORMAL_FLAVOR, "Send Normal " );
721   PutDirects( CRASH_FLAVOR | NOARC_FLAVOR, CRASH_FLAVOR | NOARC_FLAVOR, "Send Crash  NoArc " );
722   PutDirects( DIRECT_FLAVOR | NOARC_FLAVOR, DIRECT_FLAVOR | NOARC_FLAVOR, "Send Direct NoArc " );
723   PutDirects( HOLD_FLAVOR | NOARC_FLAVOR, HOLD_FLAVOR | NOARC_FLAVOR, "Send Hold   NoArc " );
724   PutDirects( NORMAL_FLAVOR | NOARC_FLAVOR, NORMAL_FLAVOR | NOARC_FLAVOR, "Send Normal NoArc " );
725 }
726 
PutRoutingSq(void)727 static void PutRoutingSq( void )
728 {
729   StarWild = false;
730   AddPoint = false;
731   DefaultFromMe = false;
732   FullAddr = false;
733   FillRoute = false;
734   WithSlash = false;
735   fprintf( NewRoute, CREATED, ';', "Squish", MyNode->z, MyNode->n, MyNode->f,
736            ';', ctime( &currtime ), ';' );
737   Spit( "; *** Direct links" EOLCHR ";" );
738   DirectsSQ(  );
739   Spit( ";" EOLCHR "; *** Route" EOLCHR ";" );
740   for( level = 0; level < 4; level++ )
741   {
742     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
743     if( level )
744       DirectsSQ(  );
745     for( ushort i = 0; i < nLinks; i++ )
746     {
747       MakeSqPrefix( Link + i, Prefix );
748       strcpy( Buff, Prefix );
749       PutDownLinks( InMemory( Link[i].addr ), 0 );
750       if( strcmp( Buff, Prefix ) != 0 )
751         Spit( Buff );           // Spit short but significant line
752     }
753   }
754 }
755 
756 
757 // Make Routing for ITrack
758 const char *ItrFlavors[] = {
759   "Crash", "Dir  ", "Hold ", "     "
760 };
761 
PutRoutingItr(void)762 static void PutRoutingItr( void )
763 {
764   StarWild = true;
765   AddPoint = true;
766   DefaultFromMe = false;
767   FullAddr = true;
768   FillRoute = false;
769   WithSlash = false;
770   fprintf( NewRoute, CREATED, ';', "iTrack", MyNode->z, MyNode->n, MyNode->f,
771            ';', ctime( &currtime ), ';' );
772   for( level = 0; level < 4; level++ )
773   {
774     int i;
775     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
776     for( i = 0; i < nLinks; i++ )
777     {
778       strcpy( Prefix, ( char * ) GetFlavor( Link + i, ItrFlavors ) );
779       WriteNode( Link[i].addr, Prefix, 1 );
780       strcat( Prefix, "  " );
781       strcpy( Buff, Prefix );
782       WriteNode( Link[i].addr, Buff, 0 );
783       PutDownLinks( InMemory( Link[i].addr ), 0 );
784       if( strcmp( Buff, Prefix ) != 0 ) // We added any downlinks
785         Spit( Buff );           // Spit short but significant line
786     }
787   }
788 }
789 
790 
791 // Make Routing for T-mail
DirectsTmail(void)792 static void DirectsTmail( void )
793 {
794   AddPoint = true;
795   PrevNode = *MyNode;           // Main AKA
796   PutDirects( CRASH_FLAVOR, CRASH_FLAVOR, "Direct " );
797   PutDirects( DIRECT_FLAVOR, DIRECT_FLAVOR, "Direct " );
798   PutDirects( NORMAL_FLAVOR, NORMAL_FLAVOR, "Direct " );
799   PutDirects( HOLD_FLAVOR, HOLD_FLAVOR, "Direct " );
800   AddPoint = false;
801   PutDirects( CRASH_FLAVOR, CRASH_FLAVOR, "Priority " );
802   PutDirects( HOLD_FLAVOR, HOLD_FLAVOR, "Hold " );
803 }
804 
PutRoutingTmail(void)805 static void PutRoutingTmail( void )
806 {
807   StarWild = true;
808   AddPoint = false;
809   DefaultFromMe = true;
810   FullAddr = false;
811   FillRoute = false;
812   WithSlash = true;
813   fprintf( NewRoute, CREATED, ';', "T-mail", MyNode->z, MyNode->n, MyNode->f,
814            ';', ctime( &currtime ), ';' );
815   Spit( "; *** Direct links" );
816   DirectsTmail(  );
817   for( level = 0; level < 4; level++ )
818   {
819     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
820     if( level )
821       DirectsTmail(  );
822     int i;
823     for( i = 0; i < nLinks; i++ )
824     {
825       if( TmailAddFor )
826         strcpy( Prefix, "Mail-For  " );
827       else
828         strcpy( Prefix, "Mail  " );
829       strcpy( Buff, Prefix );
830       UpNode = Link[i].addr;
831       PutDownLinks( InMemory( Link[i].addr ), 0 );
832       if( strcmp( Buff, Prefix ) != 0 )
833       {
834         WriteNode( UpNode, Buff, 1 );
835         Spit( Buff );           // Spit short but significant line
836       }
837       // 'Files'
838       if( Link[i].flavor & FILE_FLAVOR )
839       {
840         if( TmailAddFor )
841           strcpy( Prefix, "Files-For " );
842         else
843           strcpy( Prefix, "Files " );
844         strcpy( Buff, Prefix );
845         UpNode = Link[i].addr;
846         PutDownLinks( InMemory( Link[i].addr ), 0 );
847         if( strcmp( Buff, Prefix ) != 0 )
848         {
849           WriteNode( UpNode, Buff, 1 );
850           Spit( Buff );         // Spit short but significant line
851         }
852       }
853     }
854   }
855 }
856 
857 
858 // Make Routing for BPACK
DirectsBpack(void)859 static void DirectsBpack( void )
860 {
861   PrevNode = *MyNode;
862   PutDirects( CRASH_FLAVOR, CRASH_FLAVOR, "Direct crash  " );
863   PutDirects( DIRECT_FLAVOR, DIRECT_FLAVOR, "Direct direct " );
864   PutDirects( NORMAL_FLAVOR, NORMAL_FLAVOR, "Direct        " );
865   PutDirects( HOLD_FLAVOR, HOLD_FLAVOR, "Direct hold   " );
866   PutDirects( NOARC_FLAVOR, NOARC_FLAVOR, "NoArcSend     " );
867 }
868 
PutRoutingBpack(void)869 static void PutRoutingBpack( void )
870 {
871   StarWild = true;
872   AddPoint = false;
873   DefaultFromMe = false;
874   FullAddr = true;
875   FillRoute = false;
876   WithSlash = false;
877   fprintf( NewRoute, CREATED, ';', "BPack", MyNode->z, MyNode->n, MyNode->f,
878            ';', ctime( &currtime ), ';' );
879   Spit( "; *** Direct links" );
880   DirectsBpack(  );
881   for( level = 0; level < 4; level++ )
882   {
883     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
884     if( level )
885       DirectsBpack(  );
886     int i;
887     for( i = 0; i < nLinks; i++ )
888     {
889       strcpy( Prefix, "Route " );
890       strcat( Prefix, GetFlavor( Link + i, SqFlavors ) );
891       WriteNode( Link[i].addr, Prefix, 1 );
892       strcat( Prefix, " " );
893       strcpy( Buff, Prefix );
894       PutDownLinks( InMemory( Link[i].addr ), 0 );
895       if( strcmp( Buff, Prefix ) != 0 )
896         Spit( Buff );           // Spit short but significant line
897     }
898   }
899 }
900 
901 
902 // Make Routing for IMBINK
PutRoutingImb(void)903 static void PutRoutingImb( void )
904 {
905   StarWild = true;
906   AddPoint = true;
907   DefaultFromMe = false;
908   FullAddr = false;
909   FillRoute = false;
910   WithSlash = false;
911   CmntSym = '#';
912   fprintf( NewRoute, CREATED, '#', "Imbink", MyNode->z, MyNode->n, MyNode->f,
913            '#', ctime( &currtime ), '#' );
914   PutDirects( FILE_FLAVOR, FILE_FLAVOR, "FSENDTO " );
915   PutDirects( NOARC_FLAVOR, 0, "Compress ZIP " );
916   for( level = 0; level < 4; level++ )
917   {
918     fprintf( NewRoute, "# *** %s" EOLCHR "", RouteType[level] );
919     int i;
920     for( i = 0; i < nLinks; i++ )
921     {
922       strcpy( Prefix, "Static " );
923       strcat( Prefix, GetFlavor( Link + i, SqFlavors ) );
924       WriteNode( Link[i].addr, Prefix, 1 );
925       strcat( Prefix, "  " );
926       strcpy( Buff, Prefix );
927       WriteNode( Link[i].addr, Buff, 0 );
928       PutDownLinks( InMemory( Link[i].addr ), 0 );
929       if( strcmp( Buff, Prefix ) != 0 )
930         Spit( Buff );           // Spit short but significant line
931     }
932   }
933 }
934 
935 
936 // Make Routing for XMAIL
PutRoutingXmail(void)937 static void PutRoutingXmail( void )
938 {
939   StarWild = false;
940   AddPoint = false;
941   DefaultFromMe = false;
942   FullAddr = true;
943   FillRoute = false;
944   WithSlash = false;
945   CmntSym = ';';
946   fprintf( NewRoute, CREATED, ';', "Xmail", MyNode->z, MyNode->n, MyNode->f,
947            ';', ctime( &currtime ), ';' );
948   fprintf( NewRoute, "; *** Directs" EOLCHR "" );
949   level = 0;
950   int i;
951   for( i = 0; i < nLinks; i++ )
952   {
953     Buff[0] = 0;
954     WriteNode( Link[i].addr, Buff, 0 );
955     if( Buff[0] )
956       Spit( Buff + 1 );
957   }
958   for( level = 0; level < 4; level++ )
959   {
960     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
961     ushort i;
962     if( level )
963     {
964       for( i = 0; i < nLinks; i++ )
965       {
966         Buff[0] = 0;
967         WriteNode( Link[i].addr, Buff, 0 );
968         if( Buff[0] )
969           Spit( Buff + 1 );
970       }
971     }
972     for( i = 0; i < nNodes; i++ )
973     {
974       Buff[0] = 0;
975       if( Node[i].idx != WILDVALUE && Node[i].idx != ( WILDVALUE - 1 ) && !DirectLink( i ) )
976       {
977         WriteNode( Node[i].addr, Buff, 0 );
978         if( Buff[0] )
979         {
980           strcat( Buff, " VIA " );
981           WriteNode( Node[Node[i].idx].addr, Buff, 1 );
982           strcat( Buff, " /NC" );
983           Spit( Buff + 1 );
984         }
985       }
986     }
987   }
988 }
989 
990 
991 // Make Routing for ifmail
GetIfFlavor(link * pLink)992 static const char *GetIfFlavor( link * pLink )
993 {
994   if( pLink->flavor & CRASH_FLAVOR )
995     return "c";
996 
997   else if( pLink->flavor & DIRECT_FLAVOR )
998     return "n";
999 
1000   else if( pLink->flavor & HOLD_FLAVOR )
1001     return "h";
1002 
1003   else
1004     return "n";
1005 }
1006 
AddInt(char * where,ushort value)1007 static char *AddInt( char *where, ushort value )
1008 {
1009   itoa( value, where, 10 );
1010   return ( where + strlen( where ) );
1011 }
1012 
WriteIfNode(nodeaddr Node,char * out,ushort wmode)1013 static boolean WriteIfNode( nodeaddr Node, char *out, ushort wmode )
1014 {
1015   char *p = out + strlen( out );
1016   ushort wildlevel = 0;
1017   if( Node.f == WILDVALUE )
1018     wildlevel++;
1019   if( Node.n == WILDVALUE )
1020     wildlevel++;
1021   if( Node.z == WILDVALUE )
1022     wildlevel++;
1023   if( wildlevel == level || wmode )
1024   {
1025     if( Node.f != WILDVALUE )
1026     {
1027       *p++ = 'f';
1028       p = AddInt( p, Node.f );
1029       *p = '.';
1030       *( ++p ) = '\0';
1031     }
1032     if( Node.n != WILDVALUE )
1033     {
1034       *p++ = 'n';
1035       p = AddInt( p, Node.n );
1036       *p = '.';
1037       *( ++p ) = '\0';
1038     }
1039     if( Node.z != WILDVALUE )
1040     {
1041       *p++ = 'z';
1042       p = AddInt( p, Node.z );
1043       *p++ = '.';
1044     }
1045     strcpy( p, "fidonet.org" );
1046     return true;
1047   }
1048   else
1049     return false;
1050 }
1051 
PutRoutingIfmail(void)1052 static void PutRoutingIfmail( void )
1053 {
1054   StarWild = false;
1055   AddPoint = false;
1056   DefaultFromMe = false;
1057   FullAddr = true;
1058   FillRoute = false;
1059   WithSlash = false;
1060   CmntSym = '#';
1061   fprintf( NewRoute, CREATED, '#', "sendmail", MyNode->z, MyNode->n,
1062            MyNode->f, '#', ctime( &currtime ), '#' );
1063   for( level = 0; level < 4; level++ )
1064   {
1065     fprintf( NewRoute, "# *** %s" EOLCHR "", RouteType[level] );
1066     ushort i;
1067     for( i = 0; i < nNodes; i++ )
1068     {
1069       Buff[0] = 0;
1070       if( Node[i].idx != WILDVALUE &&   // routed
1071           Node[i].idx != ( WILDVALUE - 1 ) &&   // not joined with wildcard
1072           ( Node[Node[i].idx].idx != WILDVALUE &&
1073             Node[Node[i].idx].idx != WILDVALUE - 1 ||
1074             DirectLink( Node[i].idx ) ) && !IsMyNode( Node[Node[i].idx].addr ) || DirectLink( i ) )
1075       {
1076         strcpy( Buff, "." );
1077         if( WriteIfNode( Node[i].addr, Buff, 0 ) )
1078         {
1079           listitem Dest;
1080           strcat( Buff, "\tifmail-" );
1081           Dest = DirectLink( i ) ? Node[i] : Node[Node[i].idx];
1082           int j;
1083           for( j = 0; j < nLinks; j++ )
1084             if( Link[j].addr == Dest.addr )
1085               strcat( Buff, GetIfFlavor( Link + j ) );
1086           strcat( Buff, ":" );
1087           WriteIfNode( Dest.addr, Buff, 1 );
1088           if( !level )
1089             Spit( Buff + 1 );
1090           Spit( Buff );
1091         }
1092       }
1093     }
1094   }
1095 }
1096 
1097 
1098 // Make Routing for BiP
1099 const char *BipFlavors[] = {
1100   "Crash", "Dir  ", "Hold ", "Norm "
1101 };
1102 
PutRoutingBip(void)1103 static void PutRoutingBip( void )
1104 {
1105   StarWild = true;
1106   AddPoint = true;
1107   DefaultFromMe = true;
1108   FullAddr = false;
1109   FillRoute = false;
1110   WithSlash = false;
1111   fprintf( NewRoute, CREATED, ';', "BiP", MyNode->z, MyNode->n, MyNode->f,
1112            ';', ctime( &currtime ), ';' );
1113   for( level = 3; level != 0xFFFF; level-- )
1114   {
1115     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
1116     int i;
1117     for( i = 0; i < nLinks; i++ )
1118     {
1119       strcpy( Prefix, "Route" );
1120       strcat( Prefix, ( char * ) GetFlavor( Link + i, BipFlavors ) );
1121       WriteNode( Link[i].addr, Prefix, 1 );
1122       strcat( Prefix, "  " );
1123       strcpy( Buff, Prefix );
1124       WriteNode( Link[i].addr, Buff, 0 );
1125       PutDownLinks( InMemory( Link[i].addr ), 0 );
1126       if( strcmp( Buff, Prefix ) != 0 )
1127         Spit( Buff );           // Spit short but significant line
1128       if( Link[i].flavor & FILE_FLAVOR )
1129       {
1130         strcpy( Prefix, "File" );
1131         strcat( Prefix, GetFlavor( Link + i, BipFlavors ) );
1132         WriteNode( Link[i].addr, Prefix, 1 );
1133         strcat( Prefix, "  " );
1134         strcpy( Buff, Prefix );
1135         WriteNode( Link[i].addr, Buff, 0 );
1136         PutDownLinks( InMemory( Link[i].addr ), 0 );
1137         if( strcmp( Buff, Prefix ) != 0 )
1138           Spit( Buff );         // Spit short but significant line
1139       }
1140     }
1141   }
1142 }
1143 
1144 
1145 // Make Routing for Unimail
PutRoutingUnimail(void)1146 static void PutRoutingUnimail( void )
1147 {
1148   StarWild = true;
1149   AddPoint = true;
1150   DefaultFromMe = false;
1151   FullAddr = true;
1152   FillRoute = false;
1153   WithSlash = false;
1154   fprintf( NewRoute, CREATED, ';', "Unimail", MyNode->z, MyNode->n, MyNode->f,
1155            ';', ctime( &currtime ), ';' );
1156   Spit( ";" EOLCHR "; *** Route" EOLCHR ";" );
1157   for( level = 0; level < 4; level++ )
1158   {
1159     fprintf( NewRoute, "; *** %s" EOLCHR "", RouteType[level] );
1160     int i;
1161     for( i = 0; i < nLinks; i++ )
1162     {
1163       strcpy( Prefix, "Route" );
1164       strcat( Prefix, GetFlavor( Link + i, SqFlavors ) );
1165       WriteNode( Link[i].addr, Prefix, 1 );
1166       strcpy( Buff, Prefix );
1167       WriteNode( Link[i].addr, Buff, 0 );
1168       PutDownLinks( InMemory( Link[i].addr ), 0 );
1169       if( strcmp( Buff, Prefix ) != 0 )
1170         Spit( Buff );           // Spit short but significant line
1171     }
1172   }
1173 }
1174 
1175 
1176 // Make Routing for QECHO
WriteNodeQecho(nodeaddr Node,char * out,ushort addrtype)1177 ushort WriteNodeQecho( nodeaddr Node, char *out, ushort addrtype )
1178 {
1179   char tmp[20];
1180   ushort wildlevel = 0;
1181   if( Node.f == WILDVALUE )
1182     wildlevel++;
1183   if( Node.n == WILDVALUE )
1184     wildlevel++;
1185   if( Node.z == WILDVALUE )
1186     wildlevel++;
1187   if( wildlevel == level || addrtype == 1 )
1188   {
1189     if( wildlevel == 3 )
1190     {
1191       strcat( out, "1: 2: 3: 4: 5: 6: 7:" );
1192     }
1193     else
1194     {
1195       strcat( out, " " );
1196       strcat( out, itoa( Node.z, tmp, 10 ) );
1197       strcat( out, ":" );
1198       if( wildlevel < 2 )
1199       {
1200         strcat( out, itoa( Node.n, tmp, 10 ) );
1201       }
1202       if( wildlevel < 1 )
1203       {
1204         strcat( out, "/" );
1205         strcat( out, itoa( Node.f, tmp, 10 ) );
1206       }
1207     }
1208   }
1209   return ushort( strlen( out ) );
1210 }
1211 
PutRoutingQecho(void)1212 static void PutRoutingQecho( void )
1213 {
1214   StarWild = false;
1215   AddPoint = false;
1216   DefaultFromMe = false;
1217   FullAddr = true;
1218   FillRoute = false;
1219   WithSlash = false;
1220   CmntSym = '#';
1221   MAX_ROUTE_LEN = 100;
1222   fprintf( NewRoute, CREATED, '#', "QECHO", MyNode->z, MyNode->n, MyNode->f,
1223            '#', ctime( &currtime ), '#' );
1224   Spit( "#" EOLCHR "# *** Route" EOLCHR "#" );
1225   for( level = 0; level < 3; level++ )
1226   {
1227     fprintf( NewRoute, "# *** %s" EOLCHR "", RouteType[level] );
1228     int i;
1229     for( i = 0; i < nLinks; i++ )
1230     {
1231       sprintf( Prefix, "RouteVia\t%d:%d/%d@fidonet" EOLCHR "RouteFor\t",
1232                Link[i].addr.z, Link[i].addr.n, Link[i].addr.f );
1233       strcpy( Buff, Prefix );
1234       if( level == 0 )
1235       {
1236         WriteNodeQecho( Link[i].addr, Buff, 1 );
1237       }
1238       PutDownLinksGeneric( InMemory( Link[i].addr ), 0, WriteNodeQecho );
1239       if( strcmp( Buff, Prefix ) != 0 )
1240       {
1241         Spit( Buff );           // Spit non-empty line
1242       }
1243     }
1244   }
1245 }
1246 
1247 
1248 // Make Routing for Fidogate
1249 const char *FidogateFlavors[] = {
1250   "crash ", "direct", "hold  ", "normal"
1251 };
1252 
MakeFidogatePrefix(link * pLink,char * out)1253 static void MakeFidogatePrefix( link * pLink, char *out )
1254 {
1255   strcpy( out, "route " );
1256   strcat( out, ( char * ) GetFlavor( pLink, FidogateFlavors ) );
1257 
1258   if( pLink->flavor & FILE_FLAVOR )
1259     strcat( out, " file" );
1260   else
1261     strcat( out, "     " );
1262 
1263   if( pLink->flavor & NOARC_FLAVOR )
1264     strcat( out, " noarc" );
1265   else
1266     strcat( out, "      " );
1267 
1268   WriteNode( pLink->addr, out, 1 );
1269   strcat( out, " " );
1270 }
1271 
DirectsFidogate(void)1272 static void DirectsFidogate( void )
1273 {
1274   PutDirects( CRASH_FLAVOR, CRASH_FLAVOR, "send crash  " );
1275   PutDirects( DIRECT_FLAVOR, DIRECT_FLAVOR, "send direct " );
1276   PutDirects( HOLD_FLAVOR, HOLD_FLAVOR, "send hold   " );
1277   PutDirects( NORMAL_FLAVOR, NORMAL_FLAVOR, "send normal " );
1278 }
1279 
PutRoutingFidogate(void)1280 static void PutRoutingFidogate( void )
1281 {
1282   StarWild = false;
1283   AddPoint = false;
1284   DefaultFromMe = false;
1285   FullAddr = true;
1286   FillRoute = false;
1287   WithSlash = false;
1288   CmntSym = '#';
1289   fprintf( NewRoute, CREATED, CmntSym, "Fidogate", MyNode->z, MyNode->n,
1290            MyNode->f, '#', ctime( &currtime ), '#' );
1291   Spit( "# *** Direct links" EOLCHR "#" );
1292   DirectsFidogate(  );
1293   Spit( "#" EOLCHR "# *** Route" EOLCHR "#" );
1294   for( level = 0; level < 4; level++ )
1295   {
1296     fprintf( NewRoute, "# *** %s" EOLCHR "", RouteType[level] );
1297     if( level )
1298       DirectsFidogate(  );
1299     for( ushort i = 0; i < nLinks; i++ )
1300     {
1301       MakeFidogatePrefix( Link + i, Prefix );
1302       strcpy( Buff, Prefix );
1303       PutDownLinks( InMemory( Link[i].addr ), 0 );
1304       if( strcmp( Buff, Prefix ) != 0 )
1305         Spit( Buff );           // Spit short but significant line
1306     }
1307   }
1308 }
1309 
1310 // Make Routing for FTRACK
1311 static int counter = 0;
WriteNodeFtrack(nodeaddr Node,char * out,ushort addrtype)1312 ushort WriteNodeFtrack( nodeaddr Node, char *out, ushort addrtype )
1313 {
1314   static const char *prefix = "Mask: * * * ";
1315   static const char *postfix = " * *";
1316   ushort wildlevel = 0;
1317   if( Node.f == WILDVALUE )
1318     wildlevel++;
1319   if( Node.n == WILDVALUE )
1320     wildlevel++;
1321   if( Node.z == WILDVALUE )
1322     wildlevel++;
1323   if( wildlevel == level || addrtype == 1 )
1324   {
1325     counter++;
1326     strcpy( out, prefix );
1327     if( level == 3 )
1328       strcat( out, "*" );
1329     else
1330       WriteNode( Node, out + strlen( prefix ), addrtype );
1331     strcat( out, postfix );
1332   }
1333   else if( wildlevel == 1 && addrtype == 0 && level == 0 )
1334   {
1335     strcpy( out, prefix );
1336     WriteNode( Node, out + strlen( prefix ), 1 );
1337     strcat( out, postfix );
1338   }
1339   return ushort( strlen( out ) );
1340 }
1341 
PutRoutingFtrack(void)1342 static void PutRoutingFtrack( void )
1343 {
1344   StarWild = true;
1345   AddPoint = true;
1346   DefaultFromMe = true;
1347   FullAddr = true;
1348   FillRoute = false;
1349   WithSlash = true;
1350   CmntSym = '\\';
1351   Prefix[0] = CmntSym;
1352   Prefix[1] = 0;
1353   nodeaddr tmpNode;
1354   MAX_ROUTE_LEN = 10;
1355   fprintf( NewRoute, CREATED, CmntSym, "Ftrack", MyNode->z, MyNode->n,
1356            MyNode->f, CmntSym, ctime( &currtime ), CmntSym );
1357   for( level = 0; level < 4; level++ )
1358   {
1359     counter = 0;
1360     fprintf( NewRoute, "%c *** %s" EOLCHR "", CmntSym, RouteType[level] );
1361     int i;
1362     for( i = 0; i < nLinks; i++ )
1363     {
1364       counter = 0;
1365       Buff[0] = 0;
1366       if( level == 0 )
1367       {
1368         WriteNodeFtrack( Link[i].addr, Buff, 0 );
1369         Spit( Buff );
1370         counter++;
1371         Buff[0] = 0;
1372       }
1373       PutDownLinksGeneric( InMemory( Link[i].addr ), 0, WriteNodeFtrack );
1374       if( counter )
1375       {
1376         sprintf( Buff, "Action: Route %s", GetFlavor( Link + i, SqFlavors ) );
1377         AddPoint = false;
1378         tmpNode = Link[i].addr;
1379         if( DirectLink( tmpNode ) && MyNode->z == tmpNode.z && MyNode->n == tmpNode.n
1380             && tmpNode.f == WILDVALUE )
1381         {
1382           strcat( Buff, "%.0" );
1383         }
1384         else
1385         {
1386           WriteNode( Link[i].addr, Buff, 1 );
1387         }
1388         AddPoint = true;
1389         strcat( Buff, "\n\\" );
1390         Spit( Buff );
1391       }
1392     }
1393   }
1394 }
1395 
1396 // Make Routing for HPT
1397 const char *HuskyFlavors[] = {
1398   "crash", "direct", "hold", "normal"
1399 };
1400 
PutRoutingHusky(void)1401 static void PutRoutingHusky( void )
1402 {
1403   StarWild = true;
1404   AddPoint = true;
1405   DefaultFromMe = false;
1406   FullAddr = true;
1407   FillRoute = false;
1408   WithSlash = false;
1409   CmntSym = '#';
1410   fprintf( NewRoute, CREATED, '#', "Husky", MyNode->z, MyNode->n, MyNode->f,
1411            '#', ctime( &currtime ), '#' );
1412   for( level = 0; level < 4; level++ )
1413   {
1414     fprintf( NewRoute, "# *** %s" EOLCHR "", RouteType[level] );
1415     int i;
1416     for( i = 0; i < nLinks; i++ )
1417     {
1418       strcpy( Prefix, "route " );
1419       strcat( Prefix, ( char * ) GetFlavor( Link + i, HuskyFlavors ) );
1420       WriteNode( Link[i].addr, Prefix, 1 );
1421       strcpy( Buff, Prefix );
1422       WriteNode( Link[i].addr, Buff, 0 );
1423       PutDownLinks( InMemory( Link[i].addr ), 0 );
1424       if( strcmp( Buff, Prefix ) != 0 )
1425         Spit( Buff );
1426     }
1427   }
1428 }
1429 
1430 //-----------------------------------------------------------------
PutUnRouted(void)1431 static void PutUnRouted( void )
1432 {
1433   FillRoute = true;
1434   FullAddr = true;
1435   fprintf( NewRoute,
1436            "%c" EOLCHR "%c !!! Undefined !!!" EOLCHR "%c ----------------"
1437            EOLCHR "", CmntSym, CmntSym, CmntSym );
1438   level = 0;
1439   Prefix[0] = CmntSym;
1440   Prefix[1] = 0;
1441   strcat( Prefix, " >>> " );
1442   strcpy( Buff, Prefix );
1443   PutDownLinks( WILDVALUE, 0 );
1444   if( strcmp( Buff, Prefix ) != 0 )
1445     Spit( Buff );               // Spit short but significant line
1446 }
1447 
1448 
1449 // Config parser
LoadAddress(char * p,void *)1450 static boolean LoadAddress( char *p, void * )
1451 {
1452   MyNode[nAKAs++] = ScanNode( &p );
1453   return true;
1454 }
1455 
GetRouteType(char * p,void *)1456 static boolean GetRouteType( char *p, void * )
1457 {
1458   if( strnicmp( p, "squish", 6 ) == 0 )
1459     RouteMode = SQUISH;
1460 
1461   else if( strnicmp( p, "itrack", 6 ) == 0 )
1462     RouteMode = ITRACK;
1463 
1464   else if( strnicmp( p, "tmail", 5 ) == 0 )
1465   {
1466     RouteMode = TMAIL;
1467     if( ( strnicmp( p, "tmailn", 6 ) == 0 ) )
1468       TmailAddFor = true;
1469     else
1470       TmailAddFor = false;
1471   }
1472 
1473   else if( strnicmp( p, "bpack", 5 ) == 0 )
1474     RouteMode = BPACK;
1475 
1476   else if( strnicmp( p, "imbink", 6 ) == 0 )
1477     RouteMode = IMBINK;
1478 
1479   else if( strnicmp( p, "xmail", 5 ) == 0 )
1480     RouteMode = XMAIL;
1481 
1482   else if( strnicmp( p, "ifmail", 6 ) == 0 )
1483     RouteMode = IFMAIL;
1484 
1485   else if( strnicmp( p, "bip", 3 ) == 0 )
1486     RouteMode = BIP;
1487 
1488   else if( strnicmp( p, "unimail", 7 ) == 0 )
1489     RouteMode = UNIMAIL;
1490 
1491   else if( strnicmp( p, "qecho", 5 ) == 0 )
1492     RouteMode = QECHO;
1493 
1494   else if( strnicmp( p, "fidogate", 8 ) == 0 )
1495     RouteMode = FIDOGATE;
1496 
1497   else if( strnicmp( p, "ftrack", 6 ) == 0 )
1498     RouteMode = FTRACK;
1499 
1500   else if( strnicmp( p, "husky", 5 ) == 0 )
1501     RouteMode = HUSKY;
1502 
1503   else
1504   {
1505     ErrorL( ErrUnknownRouteType );
1506     return false;
1507   }
1508   return true;
1509 }
1510 
GetBoolean(char * p,void * target)1511 static boolean GetBoolean( char *p, void *target )
1512 {
1513   if( strnicmp( p, "yes", 3 ) == 0 || strnicmp( p, "on", 2 ) == 0 || strnicmp( p, "1", 1 ) == 0 )
1514     *( ushort * ) target = 1;
1515 
1516   else if( strnicmp( p, "no", 2 ) == 0 || strnicmp( p, "off", 3 ) == 0
1517            || strnicmp( p, "0", 1 ) == 0 )
1518     *( ushort * ) target = 0;
1519 
1520   else
1521   {
1522     ErrorL( ErrUnknownMinType );
1523     return false;
1524   }
1525   return true;
1526 }
1527 
GetFile(char * p,void * Name)1528 static boolean GetFile( char *p, void *Name )
1529 {
1530   char *p1 = ( char * ) Name;
1531   while( !isspace( *p ) )
1532     *( p1++ ) = *( p++ );
1533   *p1 = 0;
1534   return true;
1535 }
1536 
GetQuotedString(char * p,void * str)1537 static boolean GetQuotedString( char *p, void *str )
1538 {
1539   char *p1 = ( char * ) str;
1540   if( *p == '\"' )
1541   {
1542     p++;
1543     while( *p != '\"' )
1544     {
1545       if( *p == '\n' || *p == '\0' )
1546       {
1547         ErrorL( ErrQuoteString );
1548         return false;
1549       }
1550       else
1551         *( p1++ ) = *( p++ );
1552     }
1553     *p1 = 0;
1554   }
1555   return true;
1556 }
1557 
GetDestFile(char * p,void * Name)1558 static boolean GetDestFile( char *p, void *Name )
1559 {
1560   GetFile( p, Name );
1561   if( ( OldRoute = fopen( ( char * ) Name, "rt" ) ) == NULL )
1562   {
1563     Error( ErrOpenDest );
1564     return false;
1565   }
1566 
1567   if( TempFile[0] == '\0' )
1568   {
1569 #if !defined(__GNUC__)
1570     fnsplit( ( char * ) Name, OutDrv, OutDir, OutName, OutExt );
1571     fnmerge( TempFile, OutDrv, OutDir, "MK$ROUTE", "$$$" );
1572 #else
1573     strcpy( TempFile, ( char * ) Name );
1574     strcat( TempFile, ".$$$" );
1575 #endif
1576   }
1577 
1578   if( ( NewRoute = fopen( TempFile, "wt" ) ) == NULL )
1579   {
1580 //  Error(ErrOpenTmp);
1581     ErrorS( ErrOpenTmpX, TempFile );
1582     return false;
1583   }
1584   boolean ReplaceArea = false;
1585   size_t beglen = strlen( RouteBegin );
1586   size_t endlen = strlen( RouteEnd );
1587   while( fgets( Buff, BUFFLEN - 1, OldRoute ) )
1588   {
1589     if( !ReplaceArea )
1590       fputs( Buff, NewRoute );
1591     if( strncmp( Buff, RouteBegin, beglen ) == 0 )
1592       ReplaceArea = true;
1593     if( ReplaceArea && ( strncmp( Buff, RouteEnd, endlen ) == 0 ) )
1594       return true;
1595   }
1596   Error( ReplaceArea ? ErrNoReplEnd : ErrNoReplBeg );
1597   fclose( OldRoute );
1598   fclose( NewRoute );
1599   unlink( TempFile );
1600   return false;
1601 }
1602 
GetFlavor(char * p,void * mask)1603 static boolean GetFlavor( char *p, void *mask )
1604 {
1605   while( *p != '\n' && *p != '\0' && *p != ';' )
1606   {
1607     if( tolower( *p ) == 'd' )
1608       *( ushort * ) mask |= DIRECT_FLAVOR;
1609 
1610     else if( tolower( *p ) == 'c' )
1611       *( ushort * ) mask |= CRASH_FLAVOR;
1612 
1613     else if( tolower( *p ) == 'h' )
1614       *( ushort * ) mask |= HOLD_FLAVOR;
1615 
1616     else if( tolower( *p ) == 'n' )
1617       *( ushort * ) mask |= NORMAL_FLAVOR;
1618 
1619     else if( tolower( *p ) == 'f' )
1620       *( ushort * ) mask |= FILE_FLAVOR;
1621 
1622     else if( tolower( *p ) == 'a' )
1623       *( ushort * ) mask |= NOARC_FLAVOR;
1624     p++;
1625   }
1626   if( ( *( ushort * ) mask & ( DIRECT_FLAVOR | CRASH_FLAVOR | HOLD_FLAVOR ) ) == 0 )
1627     *( ushort * ) mask |= NORMAL_FLAVOR;
1628   return true;
1629 }
1630 
GetLink(char * p,void *)1631 static boolean GetLink( char *p, void * )
1632 {
1633   memset( Link + nLinks, 0, sizeof( Link[0] ) );
1634   Link[nLinks].addr = ScanNode( &p );
1635   GetFlavor( p, &Link[nLinks].flavor );
1636   if( InMemory( Link[nLinks].addr ) == WILDVALUE )      // Not in Node[]
1637   {
1638     Node[nNodes].addr = Link[nLinks].addr;
1639     Node[nNodes++].idx = WILDVALUE;
1640   }
1641   nLinks++;
1642   return true;
1643 }
1644 
StoreUplink(nodeaddr tmpNode)1645 static ushort StoreUplink( nodeaddr tmpNode )
1646 {
1647   ushort Uplink = InMemory( tmpNode );
1648   if( Uplink == WILDVALUE )     // Not in memory yet
1649   {
1650     Uplink = nNodes;
1651     Node[nNodes].addr = tmpNode;
1652     Node[nNodes].is_uplink = true;
1653     Node[nNodes++].idx = WILDVALUE;
1654   }
1655   return Uplink;
1656 }
1657 
StoreDownLink(ushort Uplink,nodeaddr tmpNode)1658 static void StoreDownLink( ushort Uplink, nodeaddr tmpNode )
1659 {
1660   if( !IsMyNode( tmpNode ) )
1661   {
1662     ushort Downlink = InMemory( tmpNode );
1663     if( !( Downlink == Uplink ) )
1664     {
1665       if( Downlink == WILDVALUE )       // New node
1666       {
1667         Downlink = nNodes;
1668         Node[nNodes].addr = tmpNode;
1669         Node[nNodes++].idx = Uplink;
1670       }
1671       else
1672       {
1673         if( Node[Downlink].idx != WILDVALUE &&  // Already routed
1674             Node[Downlink].idx != Uplink )      // differently
1675         {
1676           ErrorS( ErrReroute, StrNode( tmpNode ) );
1677         }
1678         Node[Downlink].idx = Uplink;
1679       }
1680       Node[Downlink].is_uplink = false;
1681     }
1682   }
1683 }
1684 
GetRouteStr(char * p,void *)1685 static boolean GetRouteStr( char *p, void * )
1686 {
1687   boolean ViaRoute;
1688   skipws( &p );
1689   if( !( *p == ';' || *p == '\n' || *p == '\0' ) )
1690   {
1691     PrevNode = *MyNode;         // Main AKA
1692     if( *p == '>' )             // 'via'-routing
1693     {
1694       p++;
1695       skipws( &p );
1696       ViaRoute = true;
1697     }
1698     else
1699       ViaRoute = false;
1700     nodeaddr tmpNode = ScanNode( &p );
1701     if( ViaRoute )
1702     {
1703       if( IsMyNode( tmpNode ) )
1704       {
1705         tmpNode = ScanNode( &p );       // skip myself
1706         StoreDownLink( StoreUplink( MyNode[0] ), tmpNode );
1707       }
1708       else if( KillTransit )
1709       {
1710         ScanNode( &p );         // skip transit node
1711       }
1712     }
1713     ushort Uplink = StoreUplink( tmpNode );
1714     while( *p != '\n' && *p != '\0' && *p != ';' )
1715     {
1716       tmpNode = ScanNode( &p );
1717       StoreDownLink( Uplink, tmpNode );
1718       skipws( &p );
1719     }
1720   }
1721   return true;
1722 }
1723 
GetRouteFile(char * p,void *)1724 static boolean GetRouteFile( char *p, void * )
1725 {
1726   char Name[100];
1727   GetFile( p, Name );
1728   FILE *nodes;
1729   if( ( nodes = fopen( Name, "rt" ) ) != NULL )
1730   {
1731     fprintf( stderr, "" EOLCHR "Scanning route file %s...", Name );
1732     while( fgets( Buff, BUFFLEN, nodes ) )
1733       GetRouteStr( Buff, NULL );
1734     fclose( nodes );
1735     return true;
1736   }
1737   else
1738   {
1739     ErrorL( ErrNoFile );
1740     return false;
1741   }
1742 }
1743 
GetTrustStr(char * p,void *)1744 static boolean GetTrustStr( char *p, void * )
1745 {
1746   if( !( *p == ';' || *p == '\n' || *p == '\0' ) )
1747   {
1748     PrevNode = *MyNode;         // Main AKA
1749     nodeaddr tmpNode = ScanNode( &p );  // scan network
1750     while( *p != '\n' && *p != '\0' && *p != ';' )
1751     {
1752       nodeaddr TrustedNode = ScanNode( &p );
1753       if( DirectLink( TrustedNode ) )
1754       {
1755         ushort idx = StoreUplink( TrustedNode );
1756         StoreDownLink( idx, tmpNode );
1757       }
1758       skipws( &p );
1759     }
1760   }
1761   return true;
1762 }
1763 
GetTrustFile(char * p,void *)1764 static boolean GetTrustFile( char *p, void * )
1765 {
1766   char Name[100];
1767   GetFile( p, Name );
1768   FILE *nodes;
1769   if( ( nodes = fopen( Name, "rt" ) ) != NULL )
1770   {
1771     fprintf( stderr, "" EOLCHR "Scanning route file %s...", Name );
1772     while( fgets( Buff, BUFFLEN, nodes ) )
1773       GetTrustStr( Buff, NULL );
1774     fclose( nodes );
1775     return true;
1776   }
1777   else
1778   {
1779     ErrorL( ErrNoFile );
1780     return false;
1781   }
1782 }
1783 
1784 const char *Dash = "-/|\\";
1785 static ushort DashCnt = 0;
1786 
DrawDash(void)1787 static void DrawDash( void )
1788 {
1789   putc( Dash[DashCnt++], stderr );
1790   putc( '\b', stderr );
1791   DashCnt &= 3;
1792 }
1793 
GetHubRoute(char * p,void *)1794 static boolean GetHubRoute( char *p, void * )
1795 {
1796   char Name[MAXPATH];
1797   FILE *ndl;
1798   strcpy( Name, strtok( p, " \t" ) );
1799 
1800 #if !defined(__GNUC__)
1801   fnsplit( Name, OutDrv, OutDir, OutName, OutExt );
1802 #endif
1803 
1804   if( strchr( Name, '?' ) || strchr( Name, '*' ) )
1805   {
1806     short maxext = ( -1 );
1807 
1808 #if defined (__TSC__)
1809     short ext;
1810     int rc;
1811     ffblk ff;
1812     for( rc = findfirst( Name, &ff, 0 ); rc != ( -1 ); rc = findnext( &ff ) )
1813     {
1814       char bb[MAXFILE];
1815       strcpy( bb, ff.ff_name );
1816       *( strrchr( bb, '.' ) ) = '\0';
1817       char *p1 = bb;
1818       char *p2 = bb + strlen( bb ) + 1;
1819       ext = atoi( p2 );
1820       if( ext > maxext )
1821       {
1822         maxext = ext;
1823         strcpy( OutName, p1 );
1824         strcpy( OutExt, p2 );
1825       }
1826     }
1827 #elif defined (__MSVC__)
1828     long handle;
1829     int rc;
1830     struct _finddata_t fdata;
1831     short ext;
1832     if((handle = _findfirst( Name, &fdata )) != -1L)
1833     {
1834       do
1835       {
1836         char bb[MAXFILE];
1837         strcpy( bb, fdata.name );
1838         *( strrchr( bb, '.' ) ) = '\0';
1839         char *p1 = bb;
1840         char *p2 = bb + strlen( bb ) + 1;
1841         ext = (short)atoi( p2 );
1842         if( ext > maxext )
1843         {
1844           maxext = ext;
1845           strcpy( OutName, p1 );
1846           strcpy( OutExt, p2 );
1847         }
1848         rc = _findnext( handle, &fdata );
1849       } while(rc != -1);
1850     }
1851 #elif defined (__WATCOMC__)
1852     short ext;
1853     DIR *ff;
1854     if( ( ff = opendir( Name ) ) != 0 )
1855     {
1856       while( readdir( ff ) != NULL )
1857       {
1858         char bb[MAXFILE];
1859         strcpy( bb, ff->d_name );
1860         *( strrchr( bb, '.' ) ) = '\0';
1861         char *p1 = bb;
1862         char *p2 = bb + strlen( bb ) + 1;
1863         ext = ( short ) atoi( p2 );
1864         if( ext > maxext )
1865         {
1866           maxext = ext;
1867           strcpy( OutName, p1 );
1868           strcpy( OutExt, p2 );
1869         }
1870       }
1871       closedir( ff );
1872     }
1873 #endif
1874 
1875 #if defined (__GNUC__)
1876     if( !glob( Name, GLOB_ERR, NULL, &globbuf ) )
1877       maxext = 0;
1878 #endif
1879 
1880     if( maxext > ( -1 ) )       // found!
1881 #if !defined(__GNUC__)
1882       fnmerge( Name, OutDrv, OutDir, OutName, OutExt );
1883 #else
1884     {
1885       strcpy( Name, globbuf.gl_pathv[globbuf.gl_pathc - 1] );
1886       globfree( &globbuf );
1887     }
1888 #endif
1889     else
1890     {
1891       ErrorL( ErrNoFile );
1892       return false;
1893     }
1894   }
1895   if( ( ndl = fopen( Name, "rt" ) ) == NULL )
1896   {
1897     ErrorL( ErrNoFile );
1898     return false;
1899   }
1900   else
1901   {
1902     setvbuf( ndl, NULL, _IOFBF, 0x8000 );       // Max buffering for speed
1903     char *p1 = strtok( NULL, " \t" );   // possible ndl type
1904     if( strlen( p1 ) != 1 )
1905     {
1906       ErrorL( ErrBadNdlType );
1907       fclose( ndl );
1908       return false;
1909     }
1910     else
1911     {
1912       ushort level, found = 0, z, n, f, Uplink;
1913       switch ( toupper( *p1 ) )
1914       {
1915       case 'Z':
1916         level = 0;
1917         break;
1918       case 'R':
1919       case 'N':
1920         level = 1;
1921         found = 1;
1922         break;
1923       default:
1924         ErrorL( ErrBadNdlType );
1925         fclose( ndl );
1926         return false;
1927       }
1928       p1 = strtok( NULL, " \t" );
1929       if( p1 == NULL )
1930       {
1931         ErrorL( ErrBadNdlType );
1932         fclose( ndl );
1933         return false;
1934       }
1935       ushort mz = ( ushort ) atoi( p1 );
1936       p1 = strtok( NULL, " \t" );
1937       if( p1 == NULL )
1938       {
1939         ErrorL( ErrBadNdlType );
1940         fclose( ndl );
1941         return false;
1942       }
1943       ushort mn = ( ushort ) atoi( p1 );
1944       fprintf( stderr, "" EOLCHR "Scanning nodelist %s for %d:%d hubroute...", Name, mz, mn );
1945       ushort count = 0;
1946       ushort step = level ? 20 : 1000;
1947       while( fgets( Buff, BUFFLEN, ndl ) != NULL )
1948       {
1949         if( ++count > step )
1950         {
1951           DrawDash(  );
1952           count = 0;
1953         }
1954         if( Buff[0] != ';' )
1955         {
1956           if( level == 0 && strnicmp( Buff, "zone", 4 ) == 0 )
1957           {
1958             found = 0;
1959             if( ( z = ( ushort ) atoi( Buff + 5 ) ) == mz )
1960               found |= 0x01;
1961           }
1962           else if( ( found & 0x01 ) && strnicmp( Buff, "region", 6 ) == 0 )
1963           {
1964             found &= 0x01;
1965             if( ( n = ( ushort ) atoi( Buff + 7 ) ) == mn )
1966               found |= 0x02;
1967           }
1968           else if( ( found & 0x01 ) && strnicmp( Buff, "host", 4 ) == 0 )
1969           {
1970             found &= 0x01;
1971             if( ( n = ( ushort ) atoi( Buff + 5 ) ) == mn )
1972               found |= 0x02;
1973           }
1974           else if( ( found & 0x3 ) == 3 && strnicmp( Buff, "hub", 3 ) == 0 )
1975           {
1976             found &= 0x03;
1977             f = ( ushort ) atoi( Buff + 4 );
1978             found |= 0x04;
1979           }
1980           else if( ( found & 0x03 ) == 3 )
1981           {
1982             found |= 0x08;
1983             if( strnicmp( Buff, "pvt", 3 ) == 0 )
1984               f = ( ushort ) atoi( Buff + 4 );
1985             else if( ( strnicmp( Buff, "hold", 4 ) == 0 ) || ( strnicmp( Buff, "down", 4 ) == 0 ) )
1986               f = ( ushort ) atoi( Buff + 5 );
1987             else if( Buff[0] == ',' )
1988               f = ( ushort ) atoi( Buff + 1 );
1989             else
1990             {
1991               found &= 7;
1992               continue;
1993             }
1994           }
1995           if( found == 3 )      // host routing
1996             Uplink = StoreUplink( nodeaddr( level ? mz : z, n, 0 ) );
1997           else if( found == 7 ) // hub routing
1998             Uplink = StoreUplink( nodeaddr( level ? mz : z, n, f ) );
1999           else if( found >= 0x0B )      // node
2000             StoreDownLink( Uplink, nodeaddr( level ? mz : z, n, f ) );
2001         }
2002       }
2003     }
2004   }
2005   fclose( ndl );
2006   return true;
2007 }
2008 
2009 
2010 #define CFG_PASSES 6
2011 static CfgValue CfgTab[] = {
2012   {"Address", NULL, 1, LoadAddress}
2013   ,
2014   {"Hubroute", NULL, 3, GetHubRoute}
2015   ,
2016   {"RouteFile", NULL, 3, GetRouteFile}
2017   ,
2018   {"TrustFile", NULL, 4, GetTrustFile}
2019   ,
2020   {"RouteType", &RouteMode, 1, GetRouteType}
2021   ,
2022   {"WriteTo", WriteTo, 2, GetDestFile}
2023   ,
2024   {"Minimize", &MinMode, 1, GetBoolean}
2025   ,
2026   {"KillTransit", &KillTransit, 1, GetBoolean}
2027   ,
2028   {"DefaultFlavor", &DefaultFlavor, 2, GetFlavor}
2029   ,
2030   {"DefaultRoute", NULL, 5, GetRouteStr}
2031   ,
2032   {"Link", NULL, 2, GetLink}
2033   ,
2034   {"RouteBegin", RouteBegin, 1, GetQuotedString}
2035   ,
2036   {"RouteEnd", RouteEnd, 1, GetQuotedString}
2037   ,
2038   {"TempFile", TempFile, 1, GetFile}
2039 };
2040 
PassOK(ushort Pass)2041 static boolean PassOK( ushort Pass )
2042 {
2043   switch ( Pass )
2044   {
2045   case 0:
2046     break;
2047   case 1:
2048     // Existing main address
2049     if( MyNode->z == 0 || MyNode->n == 0 )
2050     {
2051       Error( ErrMissMainAddr );
2052       return false;
2053     }
2054     // Existing RouteType keyword
2055     if( !RouteMode )
2056     {
2057       Error( ErrMissRouteType );
2058       return false;
2059     }
2060     // Existing "Minimize"
2061     if( MinMode == 2 )
2062       Error( ErrMissMinType );
2063     break;
2064   case 2:
2065   case 3:
2066   case 4:
2067     break;
2068   case 5:
2069     fprintf( stderr, EOLCHR "Adjusting routing..." );
2070     FixWildcard(  );
2071     RemoveUnnecessary(  );
2072     break;
2073   }
2074   return true;
2075 }
2076 
LoadConfig(void)2077 static boolean LoadConfig( void )
2078 {
2079   FILE *cfg;
2080   boolean KeyWordFailed;
2081   if( ( cfg = fopen( CfgFile, "rt" ) ) != 0 )
2082   {
2083     char tmp[50];
2084     fprintf( stderr, "" EOLCHR "Scanning config file... " );
2085     ushort i;
2086     for( i = 0; i < CFG_PASSES; i++ )
2087     {
2088       CfgLine = 0;
2089       KeyWordFailed = false;
2090       while( fgets( Buff, BUFFLEN - 1, cfg ) )
2091       {
2092         CfgLine++;
2093         char *p = Buff;
2094         skipws( &p );
2095         if( *p == '#' || *p == ';' || *p == '\n' || *p == '\0' )
2096           continue;             // skip blank line or comment
2097         char *p1 = tmp;
2098         while( !isspace( *p ) )
2099           *( p1++ ) = *( p++ );
2100         *p1 = 0;
2101         unsigned int j;
2102         for( j = 0; j < ItemNum( CfgTab ); j++ )
2103         {
2104           if( CfgTab[j].Pass == i && stricmp( CfgTab[j].Name, tmp ) == 0 )
2105           {
2106             skipws( &p );
2107             KeyWordFailed |= !CfgTab[j].LoadVal( p, CfgTab[j].Value );
2108           }
2109         }
2110       }
2111       if( KeyWordFailed || !PassOK( i ) )
2112       {
2113         fclose( cfg );
2114         return false;
2115       }
2116       rewind( cfg );
2117     }
2118     fclose( cfg );
2119     return true;
2120   }
2121   else
2122     Error( ErrOpenCfg );
2123   return false;
2124 }
2125 
main(int argc,char ** argv)2126 int main( int argc, char **argv )
2127 {
2128   char REVISION[] =  "$Revision$";
2129   REVISION[strlen(REVISION)-1]=0;
2130   if( strlen(REVISION) > 10 )
2131     strcpy(REVISION,REVISION+10);
2132   else
2133     REVISION[0]=0;
2134   fprintf( stderr,
2135            "Hubroute generator v." VERSION "(" TARGET ")%s%s" EOLCHR
2136            "Copyright (c) 1994-2003 Yuri Safronov 2:5020/204" EOLCHR
2137            "Copyright (c) 2009-2016 Husky Project development team" EOLCHR,
2138            REVISION[0]?"rev.":"", REVISION );
2139   if( argc > 1 )
2140   {
2141     if( !stricmp( argv[1], "--help" ) || !stricmp( argv[1], "-h" ) || !stricmp( argv[1], "/h" ) )
2142     {
2143       fprintf( stderr, "" EOLCHR "Usage: fidoroute [config.file]" EOLCHR "" );
2144       return 0;
2145     }
2146   }
2147   PrevNode.CleanUp(  );
2148 
2149   // Allocate buffers
2150   Buff = ( char * ) malloc( BUFFLEN );
2151   Prefix = ( char * ) malloc( 500 );
2152   Node = ( listitem * ) calloc( MAXNODES, sizeof( listitem ) );
2153   Link = ( link * ) calloc( MAXLINKS, sizeof( link ) );
2154   CfgFile = ( char * ) calloc( 1, PATHLEN );
2155   MyNode = ( nodeaddr * ) calloc( MAXAKAS, sizeof( nodeaddr ) );
2156   if( Buff == NULL || Prefix == NULL || Node == NULL || Link == NULL
2157       || CfgFile == NULL || MyNode == NULL )
2158   {
2159     Error( ErrNoMemory );
2160     return 2;
2161   }
2162   else
2163   {
2164     nNodes = 0;
2165     nLinks = 0;
2166     TempFile[0] = '\0';
2167     if( argc == 1 )
2168 #if defined(__DJGPP__) || defined(__OS2__) || defined(__NT__)
2169       strcpy( CfgFile, "fidoroute.cfg" );
2170 #else
2171       strcpy( CfgFile, "fidoroute.conf" );
2172 #endif
2173     else
2174       strcpy( CfgFile, argv[1] );
2175     if( LoadConfig(  ) )
2176     {
2177       fprintf( stderr, "" EOLCHR "Writing routing... " );
2178       time( &currtime );
2179       switch ( RouteMode )
2180       {
2181       case SQUISH:
2182         PutRoutingSq(  );
2183         break;
2184       case ITRACK:
2185         PutRoutingItr(  );
2186         break;
2187       case TMAIL:
2188         PutRoutingTmail(  );
2189         break;
2190       case BPACK:
2191         PutRoutingBpack(  );
2192         break;
2193       case IMBINK:
2194         PutRoutingImb(  );
2195         break;
2196       case XMAIL:
2197         PutRoutingXmail(  );
2198         break;
2199       case IFMAIL:
2200         PutRoutingIfmail(  );
2201         break;
2202       case BIP:
2203         PutRoutingBip(  );
2204         break;
2205       case UNIMAIL:
2206         PutRoutingUnimail(  );
2207         break;
2208       case QECHO:
2209         PutRoutingQecho(  );
2210         break;
2211       case FIDOGATE:
2212         PutRoutingFidogate(  );
2213         break;
2214       case FTRACK:
2215         PutRoutingFtrack(  );
2216         break;
2217       case HUSKY:
2218         PutRoutingHusky(  );
2219         break;
2220       }
2221       PutUnRouted(  );
2222       Spit( RouteEnd );
2223       while( fgets( Buff, BUFFLEN - 1, OldRoute ) )
2224         fputs( Buff, NewRoute );
2225       fclose( OldRoute );
2226       fclose( NewRoute );
2227       unlink( WriteTo );
2228       rename( TempFile, WriteTo );
2229       fprintf( stderr, "" EOLCHR "Done - %d rules for %d links." EOLCHR "", nNodes, nLinks );
2230       return 0;
2231     }
2232     else
2233       return 1;
2234   }
2235 }
2236