1 /*****************************************************************************
2  * AreaFix library for Husky (FTN Software Package) supplemental file
3  *****************************************************************************
4  * Copyright (C) 1998-2003
5  *
6  * val khokhlov (Fido: 2:550/180), Kiev, Ukraine
7  *
8  * Based on original HPT code by Max Chernogor 2:464/108
9  *
10  * This file is part of libareafix.
11  *
12  * libareafix is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation; either version 2, or (at your option) any
15  * later version.
16  *
17  * This library is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with libareafix; see the file COPYING.  If not, write to the Free
24  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25  *****************************************************************************/
26 /* $Id$ */
27 
28 /* libc */
29 #include <stdio.h>
30 #include <time.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <errno.h>
35 
36 /* compiler.h */
37 #include <huskylib/compiler.h>
38 #include <huskylib/huskylib.h>
39 
40 #ifdef HAS_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #ifdef HAS_DOS_H
45 #include <dos.h>
46 #endif
47 
48 /* smapi */
49 
50 /* fidoconf */
51 #include <fidoconf/fidoconf.h>
52 #include <fidoconf/common.h>
53 #include <huskylib/xstr.h>
54 #include <fidoconf/areatree.h>
55 #include <fidoconf/afixcmd.h>
56 #include <fidoconf/arealist.h>
57 
58 /* hpt */
59 /*
60 #include <global.h>
61 #include <toss.h>
62 */
63 
64 #define DLLEXPORT
65 #include <huskylib/huskyext.h>
66 #include <areafix.h>
67 #include <query.h>
68 #include <afglobal.h>
69 #include <callback.h>
70 
71 static  time_t  tnow;
72 const   long    secInDay = 3600*24;
73 const char czFreqArea[] = "freq";
74 const char czIdleArea[] = "idle";
75 const char czKillArea[] = "kill";
76 const char czChangFlg_hpt[]   = "changed.qfl";
77 const char czChangFlg_htick[] = "filefix.qfl";
78 s_query_areas *queryAreasHead = NULL;
79 
80 extern char       *af_versionStr;
81 
escapeConfigWord(char * src)82 char *escapeConfigWord(char *src)
83 /* Replace special characters with escape-sequiences: [ -> [[], ` -> [`], " -> ["], ...
84  * Return new string (malloc)
85 */
86 {
87   int c=1;
88   char *dst, *pp;
89 
90   if( !src ) return NULL;
91 
92   for( pp=src; *pp; pp++ )
93   {
94     switch( *pp )
95     {
96       case '"':
97       case '\'':
98       case '`':
99       case '[':
100                 c+=2;
101     }
102   }
103 
104   if( c<2 )
105     return sstrdup(src);
106 
107   dst=smalloc(c+sstrlen(src));
108   for( pp=src, c=0; *pp; pp++ )
109   {
110     switch( *pp )
111     {
112       case '"':
113       case '\'':
114       case '`':
115       case '[':
116                 dst[c++]='[';
117                 dst[c++]=*pp;
118                 dst[c++]=']';
119                 break;
120       default:
121                 dst[c++]=*pp;
122     }
123   }
124   return dst;
125 }
126 
checkRefuse(char * areaName)127 int checkRefuse(char *areaName)
128 {
129     FILE *fp;
130     char *line;
131 
132     if (af_robot->newAreaRefuseFile == NULL)
133         return 0;
134 
135     fp = fopen(af_robot->newAreaRefuseFile, "r+b");
136     if (fp == NULL) {
137         w_log(LL_ERR, "Can't open newAreaRefuseFile \"%s\" : %d\n",
138               af_robot->newAreaRefuseFile, strerror(errno));
139         return 0;
140     }
141     while((line = readLine(fp)) != NULL)
142     {
143         line = trimLine(line);
144         if (patimat(areaName, line)) {
145             fclose(fp);
146             return 1;
147         }
148     }
149     fclose(fp);
150     return 0;
151 }
152 
del_tok(char ** ac,char * tok)153 void del_tok(char **ac, char *tok) {
154     char *p, *q;
155 
156     q = fc_stristr(*ac,tok);
157     if (q) {
158 	p = q+strlen(tok);
159 	while (*p && !isspace(*p)) p++;
160 	if (*p) memmove(q, p+1, strlen(p+1)+1); /*  begin or middle */
161 	else {
162 	    if (q > *ac) *(q-1)='\0'; /*  end */
163 	    else *q='\0'; /*  "-token" defaults */
164 	}
165     }
166 }
167 
makeAreaParam(s_link * creatingLink,s_link_robot * r,char * c_area,char * msgbDir)168 char* makeAreaParam(s_link *creatingLink, s_link_robot *r, char* c_area, char* msgbDir)
169 {
170     char *msgbFileName=NULL;
171     char *msgbtype, *newAC=NULL, *desc, *quote_areaname;
172     char *cp, *buff=NULL, *d_area;                    /* temp. usage */
173 
174     msgbFileName = makeMsgbFileName(af_config, c_area);
175 
176     /*  translating name of the area to lowercase/uppercase */
177     if (af_config->createAreasCase == eUpper) strUpper(c_area);
178     else strLower(c_area);
179 
180     /*  translating filename of the area to lowercase/uppercase */
181     if (af_config->areasFileNameCase == eUpper) strUpper(msgbFileName);
182     else strLower(msgbFileName);
183 
184     if (r->autoCreateDefaults)
185       xstrscat(&newAC, " ", r->autoCreateDefaults, NULLP);
186 
187     msgbtype = fc_stristr(newAC, "-b ");
188 
189     if(!msgbDir)
190         msgbDir = creatingLink->areafix.baseDir ? creatingLink->areafix.baseDir : af_config->msgBaseDir;
191 
192     quote_areaname = strchr(TRUE_COMMENT " \"", *c_area) ? "\"" : "";
193     d_area = escapeConfigWord(c_area);
194 
195     if (stricmp(msgbDir, "passthrough")!=0 && NULL==fc_stristr(newAC,"passthrough"))
196     {
197         /*  we have to find a file name */
198         int need_dos_file;
199 
200 #ifndef MSDOS
201         need_dos_file = fc_stristr(newAC, "-dosfile")!=NULL;
202 #else
203         need_dos_file = 1;
204 #endif
205         if (creatingLink->autoAreaCreateSubdirs && !need_dos_file)
206         {
207              /* "subdirify" the message base path if the */
208              /* user wants this. this currently does not */
209              /* work with the -dosfile option */
210             for (cp = msgbFileName; *cp; cp++)
211             {
212                 if (*cp == '.')
213                 {
214                     *cp = PATH_DELIM;
215                 }
216             }
217         }
218         if (!need_dos_file)
219             xscatprintf(&buff, "EchoArea %s%s%s %s%s",
220             quote_areaname, d_area, quote_areaname,
221             msgbDir, msgbFileName);
222         else {
223             sleep(1); /*  to prevent time from creating equal numbers */
224             xscatprintf(&buff,"EchoArea %s%s%s %s%8lx",
225                 quote_areaname, d_area, quote_areaname,
226                 msgbDir, (long)time(NULL));
227         }
228 
229     } else {
230         /*  passthrough */
231         xscatprintf(&buff, "EchoArea %s%s%s passthrough",
232 	    quote_areaname, d_area, quote_areaname);
233 
234         del_tok(&newAC, "passthrough");
235         del_tok(&newAC, "-b ");  /*  del "-b msgbtype" from autocreate defaults */
236         del_tok(&newAC, "-$m "); /*  del "-$m xxx" from autocreate defaults */
237         del_tok(&newAC, "-p ");  /*  del "-p xxx" from autocreate defaults */
238 
239         del_tok(&newAC, "-killsb");
240         del_tok(&newAC, "-nokillsb");
241         del_tok(&newAC, "-tinysb");
242         del_tok(&newAC, "-notinysb");
243         del_tok(&newAC, "-pack");
244         del_tok(&newAC, "-nopack");
245         del_tok(&newAC, "-link");
246         del_tok(&newAC, "-nolink");
247         del_tok(&newAC, "-killread");
248         del_tok(&newAC, "-nokillread");
249         del_tok(&newAC, "-keepunread");
250         del_tok(&newAC, "-nokeepunread");
251     }
252 
253     nfree(msgbFileName);
254     if (creatingLink->LinkGrp) {
255         if (fc_stristr(newAC, " -g ")==NULL)
256             xscatprintf(&buff, " -g %s", creatingLink->LinkGrp);
257     }
258 
259     if (IsAreaAvailable(c_area, r->fwdFile, &desc,1)==1) {
260         if (desc) {
261             if (fc_stristr(newAC, " -d ")==NULL)
262                 xscatprintf(&buff, " -d \"%s\"", desc);
263             nfree(desc);
264         }
265     }
266     if (newAC && (*newAC)) xstrcat(&buff, newAC);
267     nfree(newAC);
268     nfree(d_area);
269     return buff;
270 }
271 
autoCreate(char * c_area,char * descr,hs_addr pktOrigAddr,ps_addr forwardAddr)272 e_BadmailReasons autoCreate(char *c_area, char *descr, hs_addr pktOrigAddr, ps_addr forwardAddr)
273 {
274     FILE *f;
275     char *fileName, *fileechoFileName;
276     char *buff=NULL, *hisaddr=NULL;
277     char *msgbDir=NULL, *bDir=NULL;
278     s_link *creatingLink;
279     s_area *area;
280     s_query_areas* areaNode=NULL;
281     size_t i=0;
282     unsigned int j;
283     char pass[] = "passthrough";
284     char CR;
285     s_link_robot *r;
286 
287     w_log( LL_FUNC, "%s::autoCreate() begin", __FILE__ );
288 
289     if(c_area == NULL)
290     {
291         w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_NO_AREATAG);
292         return BM_NO_AREATAG;
293     }
294 
295 	if (isPatternLine(c_area)) {
296          w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_ILLEGAL_CHARS);
297          return BM_ILLEGAL_CHARS;
298     }
299     if (call_isValid) {
300       int rc = (*call_isValid)(c_area);
301       if (rc != 0) {
302          w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, rc );
303          return rc;
304       }
305     }
306 
307     if (checkRefuse(c_area))
308     {
309         w_log(LL_WARN, "Can't create %s %s : refused by %s newAreaRefuseFile\n", af_robot->strA, c_area, af_robot->name);
310         return BM_DENY_NEWAREAREFUSEFILE;
311     }
312 
313     creatingLink = getLinkFromAddr(af_config, pktOrigAddr);
314 
315     if (creatingLink == NULL) {
316 	w_log(LL_ERR, "creatingLink == NULL !!!");
317         w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_SENDER_NOT_FOUND );
318 	return BM_SENDER_NOT_FOUND;
319     }
320 
321     r = (*call_getLinkRobot)(creatingLink);
322     fileName = r->autoCreateFile ? r->autoCreateFile : (af_cfgFile ? af_cfgFile : getConfigFileName());
323 
324     f = fopen(fileName, "a+b");
325     if (f == NULL) {
326       w_log( LL_ERR, "%s::autoCreate(): cannot open config file \"%s\", link %s, OS error: \"%s\", please check configuration (and run tparser!)",
327              __FILE__, fileName, aka2str5d(creatingLink->hisAka), strerror(errno) );
328 //    fprintf(stderr, "autocreate: cannot open af_config file\n");
329       w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_CANT_OPEN_CONFIG);
330       return BM_CANT_OPEN_CONFIG;
331     }
332     /*  setting up msgbase dir */
333     if (af_config->createFwdNonPass == 0 && forwardAddr)
334         msgbDir = pass;
335     else
336         msgbDir = r->baseDir;
337 
338     if (af_robot->queueFile)
339     {
340         areaNode = af_CheckAreaInQuery(c_area, &pktOrigAddr, NULL, FIND);
341         if( areaNode ) /*  if area in query */
342         {
343             if( stricmp(areaNode->type,czKillArea) == 0 ){
344                 w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_AREA_KILLED );
345                 return BM_AREA_KILLED;  /*  area already unsubscribed */
346             }
347             if( stricmp(areaNode->type,czFreqArea) == 0 &&
348                 addrComp(pktOrigAddr, areaNode->downlinks[0])!=0)
349             {
350                 w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_WRONG_LINK_TO_AUTOCREATE );
351                 return BM_WRONG_LINK_TO_AUTOCREATE;  /*  wrong link to autocreate from */
352             }
353             if( stricmp(areaNode->type,czFreqArea) == 0 )
354             {
355                 /*  removinq area from query. it is autocreated now */
356                 queryAreasHead->nFlag = 1; /*  query was changed */
357                 areaNode->type[0] = '\0';  /*  mark as deleted */
358             }
359             if (af_config->createFwdNonPass == 0)
360                msgbDir = pass;
361             /*  try to find our aka in links of queried area */
362             /*  if not foun area will be passthrough */
363             for (i = 1; i < areaNode->linksCount; i++)
364                 for(j = 0; j < af_config->addrCount; j++)
365                     if (addrComp(areaNode->downlinks[i],af_config->addr[j])==0)
366                     {
367                         bDir = (creatingLink->filefix.baseDir) ? creatingLink->filefix.baseDir : af_config->fileAreaBaseDir;
368                         msgbDir = creatingLink->areafix.baseDir;
369                         break;
370                     }
371         }
372     }
373 
374     /*  making address of uplink */
375     xstrcat(&hisaddr, aka2str(pktOrigAddr));
376 
377     /* HPT stuff */
378     if (af_app->module == M_HPT) {
379       buff = makeAreaParam(creatingLink, r, c_area, msgbDir);
380     }
381     /* HTICK stuff */
382     else if (af_app->module == M_HTICK) {
383       char *NewAutoCreate = NULL;
384 
385       fileechoFileName = makeMsgbFileName(af_config, c_area);
386       /*  translating name of the area to lowercase/uppercase */
387       if (af_config->createAreasCase == eUpper) strUpper(c_area);
388       else strLower(c_area);
389       /*  translating filename of the area to lowercase/uppercase */
390       if (af_config->areasFileNameCase == eUpper) strUpper(fileechoFileName);
391       else strLower(fileechoFileName);
392 
393       if (bDir==NULL)
394           bDir = (creatingLink->filefix.baseDir) ? creatingLink->filefix.baseDir : af_config->fileAreaBaseDir;
395 
396       if( strcasecmp(bDir,"passthrough") )
397       {
398           if (creatingLink->autoFileCreateSubdirs)
399           {
400               char *cp;
401               for (cp = fileechoFileName; *cp; cp++)
402               {
403                   if (*cp == '.')
404                   {
405                       *cp = PATH_DELIM;
406                   }
407               }
408           }
409           xscatprintf(&buff,"%s%s",bDir,fileechoFileName);
410           if (_createDirectoryTree(buff))
411           {
412               w_log(LL_ERROR, "cannot make all subdirectories for %s\n",
413                   fileechoFileName);
414               nfree(buff);
415               w_log( LL_FUNC, "%s::autoCreate() rc=%d", __FILE__, BM_CANT_CREATE_PATH );
416               return BM_CANT_CREATE_PATH;
417           }
418 #if defined (__UNIX__)
419           if(af_config->fileAreaCreatePerms && chmod(buff, af_config->fileAreaCreatePerms))
420               w_log(LL_ERR, "Cannot chmod() for newly created filearea directory '%s': %s",
421               sstr(buff), strerror(errno));
422 #endif
423           nfree(buff);
424       }
425 
426       /* write new line in config file */
427       { char *d_area = escapeConfigWord(c_area);
428         xscatprintf(&buff, "FileArea %s %s%s -a %s ",
429           d_area, bDir,
430           (strcasecmp(bDir,"passthrough") == 0) ? "" : fileechoFileName,
431           aka2str(*(creatingLink->ourAka))
432           );
433         nfree(d_area);
434       }
435 
436       if ( creatingLink->LinkGrp &&
437           !( r->autoCreateDefaults && fc_stristr(r->autoCreateDefaults, "-g ") )
438           )
439       {
440           xscatprintf(&buff,"-g %s ",creatingLink->LinkGrp);
441       }
442 
443       if (r->fwdFile && !descr)
444           /* try to find description in forwardFileRequestFile */
445           IsAreaAvailable(c_area, r->fwdFile, &descr, 1);
446 
447       if (r->autoCreateDefaults) {
448           NewAutoCreate = sstrdup(r->autoCreateDefaults);
449           if ((fileName=strstr(NewAutoCreate,"-d ")) !=NULL ) {
450               if (descr) {
451                   *fileName = '\0';
452                   xscatprintf(&buff,"%s -d \"%s\"",NewAutoCreate,descr);
453               } else {
454                   xstrcat(&buff, NewAutoCreate);
455               }
456           } else {
457               if (descr)
458                   xscatprintf(&buff,"%s -d \"%s\"",NewAutoCreate,descr);
459               else
460                   xstrcat(&buff, NewAutoCreate);
461           }
462           nfree(NewAutoCreate);
463       }
464       else if (descr)
465       {
466           xscatprintf(&buff,"-d \"%s\"",descr);
467       }
468     } /* end of HTICK stuff */
469 
470     /* add newly created echo to af_config in memory */
471     parseLine(buff, af_config);
472     if (af_app->module == M_HTICK) RebuildFileAreaTree(af_config);
473     else RebuildEchoAreaTree(af_config);
474 
475     /*  subscribe uplink if he is not subscribed */
476     area = &( (*af_robot->areas)[ *(af_robot->areaCount)-1 ] );
477     if ( !isLinkOfArea(creatingLink,area) ) {
478 	xscatprintf(&buff, " %s", hisaddr);
479 	Addlink(af_config, creatingLink, area);
480         if (af_config->createAddUplink) {
481           xstrcat(&buff, " -def");
482           if (area) area->downlinks[area->downlinkCount-1]->defLink = 1;
483         }
484     }
485 
486     /*  subscribe downlinks if present */
487     if(areaNode) { /*  areaNode == NULL if areafixQueueFile isn't used */
488         /*  prevent subscribing of defuault links */
489         /*  or not existing links */
490         for(i = 1; i < areaNode->linksCount; i++) {
491             if( ( isAreaLink( areaNode->downlinks[i],area ) == -1 ) &&
492                 ( getLinkFromAddr(af_config,areaNode->downlinks[i])) &&
493                 ( !isOurAka(af_config,areaNode->downlinks[i]) )
494             ) {
495               xstrcat( &buff, " " );
496               xstrcat( &buff, aka2str(areaNode->downlinks[i]) );
497               Addlink(af_config, getLinkFromAddr(af_config,areaNode->downlinks[i]), area);
498             }
499         }
500     }
501 
502     /* subscribe links with autoSubscribe "on" */
503     for(i = 0; i < af_config->linkCount; i++)
504     {
505         r = (*call_getLinkRobot)(af_config->links[i]);
506         if(r->autoSubscribe && !isLinkOfArea(af_config->links[i], area))
507         {
508             xscatprintf(&buff, " %s", aka2str(af_config->links[i]->hisAka));
509             Addlink(af_config, af_config->links[i], area);
510         }
511     }
512 
513     /*  fix if dummys del \n from the end of file */
514     if( fseek (f, -2L, SEEK_END) == 0)
515     {
516         CR = getc (f); /*   may be it is CR aka '\r'  */
517         if (getc(f) != '\n') {
518             fseek (f, 0L, SEEK_END);  /*  not neccesary, but looks better ;) */
519             fputs (cfgEol(), f);
520         } else {
521             fseek (f, 0L, SEEK_END);
522         }
523         i = ftell(f); /* af_config length */
524         /* correct EOL in memory */
525         if(CR == '\r')
526             xstrcat(&buff,"\r\n"); /* DOS EOL */
527         else
528             xstrcat(&buff,"\n");   /* UNIX EOL */
529     }
530     else
531     {
532         xstrcat(&buff,cfgEol());   /* af_config depended EOL */
533     }
534 
535     /*  add line to af_config */
536     if ( fprintf(f, "%s", buff) != (int)(strlen(buff)) || fflush(f) != 0)
537     {
538         w_log(LL_ERR, "Error creating area %s, config write failed: %s!",
539             c_area, strerror(errno));
540         fseek(f, i, SEEK_SET);
541         setfsize(fileno(f), i);
542     }
543     fclose(f);
544     nfree(buff);
545 
546     /*  echoarea addresses changed by safe_reallocating of af_config->echoAreas[] */
547     if (af_app->module == M_HPT) carbonNames2Addr(af_config);
548 
549     w_log(LL_AUTOCREATE, "%s %s autocreated by %s", af_robot->strA, c_area, hisaddr);
550 
551     if (hook_onAutoCreate) (*hook_onAutoCreate)(c_area, descr, pktOrigAddr, forwardAddr);
552 
553     /* check if downlinks are already paused, pause area if it is so */
554     /* skip if forwardAddr is NULL: will be checked in subscribe() */
555     if (af_robot->autoAreaPause && area->msgbType == MSGTYPE_PASSTHROUGH && forwardAddr == NULL) {
556       if (pauseArea(ACT_PAUSE, NULL, area)) sendAreafixMessages();
557     }
558 
559     nfree(hisaddr);
560 
561     /* val: update perl structures */
562     if (hook_onConfigChange) (*hook_onConfigChange)(PERL_CONF_AREAS);
563 
564     /*  create flag */
565     if (af_robot->autoCreateFlag) {
566 	if (NULL == (f = fopen(af_robot->autoCreateFlag, "a")))
567 	    w_log(LL_ERR, "Could not open autoAreaCreate flag: %s", af_robot->autoCreateFlag);
568 	else {
569 	    w_log(LL_FLAG, "Created autoAreaCreate flag: %s", af_robot->autoCreateFlag);
570 	    fclose(f);
571 	}
572     }
573 
574     w_log( LL_FUNC, "%s::autoCreate() end", __FILE__ );
575     return BM_MAIL_OK;
576 }
577 
578 
579 s_query_areas*  af_AddAreaListNode(char *areatag, const char *type);
580 void            af_DelAreaListNode(s_query_areas* node);
581 void            af_AddLink(s_query_areas* node, ps_addr link);
582 
af_CheckAreaInQuery(char * areatag,ps_addr uplink,ps_addr dwlink,e_query_action act)583 s_query_areas* af_CheckAreaInQuery(char *areatag, ps_addr uplink, ps_addr dwlink, e_query_action act)
584 {
585     size_t i = 0;
586     int bFind = 0;
587     s_query_areas *areaNode = NULL;
588     s_query_areas *tmpNode  = NULL;
589 
590     if( !queryAreasHead ) af_OpenQuery();
591     tmpNode = queryAreasHead;
592     while(tmpNode->next && !bFind)
593     {
594         if( tmpNode->next->name && !stricmp(areatag, tmpNode->next->name) )
595             bFind = 1;
596         tmpNode = tmpNode->next;
597     }
598 
599     switch( act )
600     {
601     case FIND: /* Find area in query list */
602         if( !bFind || tmpNode == queryAreasHead )
603             tmpNode = NULL;
604         break;
605     case FINDFREQ: /* Find area with "freq" or "idle" state in query list (query-in-progress area) */
606         if( !bFind || tmpNode == queryAreasHead || stricmp(tmpNode->type,czKillArea) == 0 )
607             tmpNode = NULL;
608         break;
609     case ADDFREQ: /* Add downlink-node into existing query in list */
610         if( bFind ) {
611             if( stricmp(tmpNode->type,czKillArea) == 0 &&
612                 uplink && addrComp(tmpNode->downlinks[0],*uplink) != 0 )
613             {
614                 memcpy( &(tmpNode->downlinks[0]), uplink, sizeof(hs_addr) );
615             }
616             if( stricmp(tmpNode->type,czFreqArea) == 0 )
617             {
618                 i = 1;
619                 while( i < tmpNode->linksCount && addrComp(*dwlink, tmpNode->downlinks[i])!=0)
620                     i++;
621                 if(i == tmpNode->linksCount) {
622                     af_AddLink( tmpNode, dwlink ); /*  add link to queried area */
623                     tmpNode->eTime = tnow + af_robot->forwardRequestTimeout*secInDay;
624                 } else {
625                     tmpNode = NULL;  /*  link already in query */
626                 }
627             } else {
628                 strcpy(tmpNode->type,czFreqArea); /*  change state to @freq" */
629                 af_AddLink( tmpNode, dwlink );
630                 tmpNode->eTime = tnow + af_robot->forwardRequestTimeout*secInDay;
631             }
632         } else { /*  area not found, so add it */
633             areaNode = af_AddAreaListNode( areatag, czFreqArea );
634             if(strlen( areatag ) > queryAreasHead->linksCount) /* max areanane lenght */
635                 queryAreasHead->linksCount = strlen( areatag );
636             af_AddLink( areaNode, uplink );
637             af_AddLink( areaNode, dwlink );
638             areaNode->eTime = tnow + af_robot->forwardRequestTimeout*secInDay;
639             tmpNode =areaNode;
640         }
641         break;
642     case ADDIDLE: /* Create idle forward request for area into query list */
643         if( bFind ) {
644         } else {
645             areaNode = af_AddAreaListNode( areatag, czIdleArea );
646             if(strlen( areatag ) > queryAreasHead->linksCount)
647                 queryAreasHead->linksCount = strlen( areatag );
648             af_AddLink( areaNode, uplink );
649             areaNode->eTime = tnow + af_robot->idlePassthruTimeout*secInDay;
650             w_log(LL_AREAFIX, "%s: make request idle for area: %s", af_robot->name, areaNode->name);
651             tmpNode =areaNode;
652         }
653         break;
654     case DELIDLE: /* Remove idle forward request to area from query list */
655         if( bFind && stricmp(tmpNode->type,czIdleArea) == 0 )
656         {
657             queryAreasHead->nFlag = 1;
658             tmpNode->type[0] = '\0';
659             w_log( LL_AREAFIX, "%s: idle request for %s removed from queue file", af_robot->name, tmpNode->name);
660         }
661         break;
662 
663     }
664     return tmpNode;
665 }
666 
af_Req2Idle(char * areatag,char * report,hs_addr linkAddr)667 char* af_Req2Idle(char *areatag, char* report, hs_addr linkAddr)
668 {
669     size_t i;
670     s_query_areas *tmpNode  = NULL;
671     s_query_areas *areaNode  = NULL;
672     if( !queryAreasHead ) af_OpenQuery();
673     tmpNode = queryAreasHead;
674     while(tmpNode->next)
675     {
676         areaNode = tmpNode->next;
677         if( ( areaNode->name ) &&
678             ( stricmp(areaNode->type,czFreqArea) == 0 ) &&
679             ( patimat(areaNode->name,areatag)==1) )
680         {
681             i = 1;
682             while( i < areaNode->linksCount)
683             {
684                   if( addrComp(areaNode->downlinks[i],linkAddr) == 0)
685                       break;
686                   i++;
687             }
688             if( i < areaNode->linksCount )
689             {
690                 if( i != areaNode->linksCount-1 )
691                     memmove(&(areaNode->downlinks[i]),&(areaNode->downlinks[i+1]),
692                     sizeof(hs_addr)*(areaNode->linksCount-i));
693                 areaNode->linksCount--;
694                 queryAreasHead->nFlag = 1; /*  query was changed */
695                 if(areaNode->linksCount == 1)
696                 {
697 					ps_link UPlink;
698                     strcpy(areaNode->type,czIdleArea);
699                     areaNode->bTime = tnow;
700                     areaNode->eTime = tnow + af_robot->idlePassthruTimeout*secInDay;
701                     w_log(LL_AREAFIX, "%s: make request idle for area: %s", af_robot->name, areaNode->name);
702                     /* send unsubscribe message to uplink when moving from freq to idle
703                      * because the last link waiting in queue cancelled its request */
704                     UPlink = getLinkFromAddr(af_config, areaNode->downlinks[0]);
705                     if (UPlink) forwardRequestToLink(areaNode->name, UPlink, NULL, 1);
706                 }
707                 xscatprintf(&report, " %s %s  request canceled\r",
708                     areaNode->name,
709                     print_ch(49-strlen(areaNode->name), '.'));
710                 w_log(LL_AREAFIX, "%s: request canceled for [%s] area: %s", af_robot->name, aka2str(linkAddr),
711                     areaNode->name);
712             }
713         }
714         tmpNode = tmpNode->next;
715     }
716     return report;
717 }
718 
af_GetQFlagName()719 char* af_GetQFlagName()
720 {
721     char *chanagedflag = NULL;
722     char *logdir       = NULL;
723     const char *czChangFlg   = af_app->module == M_HTICK ? czChangFlg_htick : czChangFlg_hpt;
724 
725 #ifdef DEBUG_HPT
726 w_log(LL_FUNC, "af_GetQFlagName(): begin");
727 #endif
728     if (af_config->lockfile)
729     {
730        logdir = dirname(af_config->lockfile);  /* slash-trailed */
731        xstrscat(&chanagedflag,logdir,(char*)czChangFlg,NULLP);
732        nfree(logdir);
733     }
734     else if (af_config->echotosslog)
735     {
736        logdir = dirname(af_config->echotosslog);  /* slash-trailed */
737        xstrscat(&chanagedflag,logdir,(char*)czChangFlg,NULLP);
738        nfree(logdir);
739     }
740     else if (af_config->semaDir)
741     {
742        logdir = dirname(af_config->echotosslog);  /* slash-trailed */
743        xstrscat(&chanagedflag,logdir,(char*)czChangFlg,NULLP);
744        nfree(logdir);
745     }
746     else
747     {
748         chanagedflag = (*call_sstrdup)(czChangFlg);
749     }
750 
751     w_log(LL_FUNC, "af_GetQFlagName(): end");
752 
753     return chanagedflag;
754 }
755 
af_QueueReport()756 void af_QueueReport()
757 {
758     s_query_areas *tmpNode  = NULL;
759     const char rmask[]="%-37.37s %-4.4s %11.11s %-16.16s %-7.7s\r";
760     char type[5]="\0\0\0\0";
761     char state[8]= "\0\0\0\0\0\0\0";
762     char link1[17]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
763     char link2[17]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
764     char* report = NULL;
765     char* header = NULL;
766     int netmail=0;
767     char *reportFlg = NULL;
768     s_message *msg = NULL;
769     char *ucStrA;
770 
771     w_log(LL_FUNC, "af_QueueReport(): begin");
772 
773     if( !af_robot->queueFile ){
774       w_log(LL_WARN, "queueFile for %s not defined in af_config", af_robot->name);
775       w_log(LL_FUNC, "af_QueueReport(): end");
776       return;
777     }
778 
779     w_log(LL_DEBUGU, __FILE__ ":%u:af_QueueReport()", __LINE__);
780 
781     reportFlg = af_GetQFlagName();
782 
783     w_log(LL_DEBUGU, __FILE__ ":%u:af_QueueReport()", __LINE__);
784 
785     if(!fexist(reportFlg))
786     {
787         w_log(LL_STOP, "Queue file hasn't been changed. Exiting...");
788         nfree(reportFlg);
789         return;
790     }
791 
792     w_log(LL_DEBUGU, __FILE__":%u:af_QueueReport()", __LINE__);
793 
794     if( !queryAreasHead ) af_OpenQuery();
795 
796     tmpNode = queryAreasHead;
797 
798     w_log(LL_DEBUGU, __FILE__":%u:af_QueueReport() tmpNode=%X", __LINE__, tmpNode);
799 
800     ucStrA = sstrdup(af_robot->strA);
801     ucStrA[0] = (char) toupper(ucStrA[0]);
802 
803     while(tmpNode->next)
804     {
805 
806     w_log(LL_DEBUGU, __FILE__":%u:af_QueueReport() tmpNode=%X", __LINE__, tmpNode);
807 
808         tmpNode = tmpNode->next;
809         strcpy(link1,aka2str(tmpNode->downlinks[0]));
810         strcpy(type,tmpNode->type);
811         if( stricmp(tmpNode->type,czFreqArea) == 0 )
812         {
813             strcpy(link2,aka2str(tmpNode->downlinks[1]));
814             if( strcmp(tmpNode->type,czFreqArea) == 0 )
815             {
816                 queryAreasHead->nFlag = 1;
817                 strUpper(tmpNode->type);
818                 xscatprintf(&report,rmask, tmpNode->name, tmpNode->type,
819                     link1,link2,
820                     "request");
821                 continue;
822             }
823             if (af_report_changes) continue; /* report changes in queue file only */
824             if(tmpNode->eTime < tnow )
825             {
826                 strcpy(state,"rr_or_d");
827             }
828             else
829             {
830                 int days = (tnow - tmpNode->bTime)/secInDay;
831                 sprintf(state,"%2d days",days);
832             }
833             xscatprintf(&report,rmask, tmpNode->name, type,
834                 link1,link2,
835                 state);
836         }
837         if( stricmp(tmpNode->type,czKillArea) == 0 )
838         {
839             if( strcmp(tmpNode->type,czKillArea) == 0 )
840             {
841                 queryAreasHead->nFlag = 1;
842                 strUpper(tmpNode->type);
843                 xscatprintf(&report,rmask, tmpNode->name, tmpNode->type,
844                     link1,"",
845                     "timeout");
846                 continue;
847             }
848             if (af_report_changes) continue;
849             if(tmpNode->eTime < tnow )
850             {
851                 strcpy(state,"to_kill");
852             }
853             else
854             {
855                 int days = (tnow - tmpNode->bTime)/secInDay;
856                 sprintf(state,"%2d days",days);
857             }
858             xscatprintf(&report,rmask, tmpNode->name, type,
859                 link1,"",
860                 state);
861 
862         }
863         if( stricmp(tmpNode->type,czIdleArea) == 0 )
864         {
865             if( strcmp(tmpNode->type,czIdleArea) == 0 )
866             {
867                 queryAreasHead->nFlag = 1;
868                 strUpper(tmpNode->type);
869                 xscatprintf(&report,rmask, tmpNode->name, tmpNode->type,
870                     link1,"",
871                     "timeout");
872                 continue;
873             }
874             if (af_report_changes) continue;
875             if(tmpNode->eTime < tnow )
876             {
877                 strcpy(state,"to_kill");
878             }
879             else
880             {
881                 int days = (tnow - tmpNode->bTime)/secInDay;
882                 sprintf(state,"%2d days",days);
883             }
884             xscatprintf(&report,rmask, tmpNode->name, type,
885                 link1,"",
886                 state);
887         }
888     }
889 
890     if(!report) {
891         nfree(ucStrA);
892         remove(reportFlg);
893         nfree(reportFlg);
894         return;
895     }
896 
897     w_log(LL_START, "Start generating queue report");
898     xscatprintf(&header, rmask,
899                 ucStrA, "Act","From","By","Details");
900     xscatprintf(&header, "%s\r", print_ch(79,'-'));
901     xstrcat(&header, report);
902     report = header;
903     if (af_config->ReportTo) {
904         if (stricmp(af_config->ReportTo,"netmail")==0)                netmail=1;
905         else if (getNetMailArea(af_config, af_config->ReportTo) != NULL) netmail=1;
906     } else netmail=1;
907 
908     msg = makeMessage(&(af_config->addr[0]),&(af_config->addr[0]),
909                                 af_robot->fromName ? af_robot->fromName : af_versionStr,
910                                 netmail ? (af_config->sysop ? af_config->sysop : "Sysop") : "All", "Requests report",
911                                 netmail,
912                                 af_robot->reportsAttr);
913     msg->text = createKludges(af_config,
914                                 netmail ? NULL : af_config->ReportTo,
915                                 &(af_config->addr[0]), &(af_config->addr[0]),
916                                 af_versionStr);
917 
918     msg->recode |= (REC_HDR|REC_TXT);
919 
920     if (af_robot->reportsFlags)
921 	xstrscat( &(msg->text), "\001FLAGS ", af_robot->reportsFlags, "\r", NULLP);
922     xstrcat( &(msg->text), report );
923 
924     w_log(LL_STOP, "End generating queue report");
925 
926     (*call_writeMsgToSysop)(msg);
927     nfree(msg);
928     nfree(ucStrA);
929     remove(reportFlg);
930     nfree(reportFlg);
931     w_log(LL_FUNC, "af_QueueReport(): end");
932 }
933 
af_QueueUpdate()934 void af_QueueUpdate()
935 {
936     s_query_areas *tmpNode  = NULL;
937     s_link *lastRlink = NULL;
938     s_link *dwlink = NULL;
939     s_message **tmpmsg = NULL;
940     size_t i = 0;
941     unsigned int j = 0;
942 
943     tmpmsg = (s_message**) (*call_smalloc)( af_config->linkCount * sizeof(s_message*));
944     for (i = 0; i < af_config->linkCount; i++)
945     {
946         tmpmsg[i] = NULL;
947     }
948 
949     w_log(LL_START, "Start updating queue file");
950     if( !queryAreasHead ) af_OpenQuery();
951 
952     tmpNode = queryAreasHead;
953     while(tmpNode->next)
954     {
955         tmpNode = tmpNode->next;
956         if( tmpNode->eTime > tnow )
957             continue;
958         if( stricmp(tmpNode->type,czFreqArea) == 0 )
959         {
960             if(tmpNode->linksCount >= 1)
961                 lastRlink = getLinkFromAddr(af_config,tmpNode->downlinks[0]);
962             if(tmpNode->linksCount >= 2)
963                 dwlink = getLinkFromAddr(af_config,tmpNode->downlinks[1]);
964 			if(lastRlink == NULL)
965             {
966                 /* TODO: Make appropriate error message and remove (?) line */
967                 continue;
968             }
969             forwardRequestToLink(tmpNode->name, lastRlink, NULL, 2);
970             w_log( LL_AREAFIX, "%s: request for %s is canceled for node %s",
971                    af_robot->name, tmpNode->name, aka2str(lastRlink->hisAka));
972             if(dwlink && !forwardRequest(tmpNode->name, dwlink, &lastRlink))
973             {
974                 tmpNode->downlinks[0] = lastRlink->hisAka;
975                 tmpNode->bTime = tnow;
976                 tmpNode->eTime = tnow + af_robot->forwardRequestTimeout*secInDay;
977                 w_log( LL_AREAFIX, "%s: request for %s is going to node %s",
978                        af_robot->name, tmpNode->name, aka2str(lastRlink->hisAka));
979             }
980             else
981             {
982                 strcpy(tmpNode->type, czKillArea);
983                 tmpNode->bTime = tnow;
984                 tmpNode->eTime = tnow + af_robot->killedRequestTimeout*secInDay;
985                 w_log( LL_AREAFIX, "%s: request for %s is going to be killed", af_robot->name, tmpNode->name);
986 
987                 /* send notification messages */
988                 for (i = 1; i < tmpNode->linksCount; i++)
989                 {
990                     dwlink = getLinkFromAddr(af_config,tmpNode->downlinks[i]);
991                     for (j = 0; j < af_config->linkCount; j++)
992                     {
993                         if ( addrComp(dwlink->hisAka,af_config->links[j]->hisAka)==0 && dwlink->sendNotifyMessages)
994                         {
995                    	    if (tmpmsg[j] == NULL)
996                    	    {
997                                 char *rf = NULL;
998                                 s_link_robot *r = (*call_getLinkRobot)(dwlink);
999                                 rf = r->reportsFlags ? r->reportsFlags : af_robot->reportsFlags;
1000                                 tmpmsg[j] = makeMessage(dwlink->ourAka,
1001                                     &(dwlink->hisAka),
1002                                     af_robot->fromName ? af_robot->fromName : af_versionStr,
1003                                     dwlink->name,
1004                                     "Notification message", 1,
1005                                     r->reportsAttr ? r->reportsAttr : af_robot->reportsAttr);
1006                                 tmpmsg[j]->text = createKludges(af_config, NULL,
1007                                     dwlink->ourAka,
1008                                     &(dwlink->hisAka),
1009                                     af_versionStr);
1010                                     if (rf)
1011                                         xstrscat(&(tmpmsg[j]->text), "\001FLAGS ", rf, "\r", NULLP);
1012 
1013                                   xstrcat(&tmpmsg[j]->text, "\r Your requests for the following areas were forwarded to uplinks,\r");
1014                                 xscatprintf(&tmpmsg[j]->text, " but no messages were received at least in %u days. Your requests\r",af_robot->forwardRequestTimeout);
1015                                     xstrcat(&tmpmsg[j]->text, " are killed by timeout.\r\r");
1016                             }
1017                             xscatprintf(&tmpmsg[j]->text, " %s\r",tmpNode->name);
1018                         }
1019                     }
1020                 }
1021                 tmpNode->linksCount = 1;
1022             }
1023             queryAreasHead->nFlag = 1; /*  query was changed */
1024             continue;
1025         }
1026         if( stricmp(tmpNode->type,czKillArea) == 0 )
1027         {
1028             queryAreasHead->nFlag = 1;
1029             tmpNode->type[0] = '\0';
1030             w_log( LL_AREAFIX, "%s: request for %s removed from queue file", af_robot->name, tmpNode->name);
1031             continue;
1032         }
1033         if( stricmp(tmpNode->type,czIdleArea) == 0 )
1034         {
1035             ps_area delarea;
1036             int mandatoryal=0;
1037             queryAreasHead->nFlag = 1; /*  query was changed */
1038             strcpy(tmpNode->type, czKillArea);
1039             tmpNode->bTime = tnow;
1040             tmpNode->eTime = tnow + af_robot->killedRequestTimeout*secInDay;
1041             w_log( LL_AREAFIX, "%s: request for %s is going to be killed", af_robot->name, tmpNode->name);
1042             if(tmpNode->linksCount >= 1)
1043             {
1044                 dwlink = getLinkFromAddr(af_config, tmpNode->downlinks[0]);
1045                 tmpNode->linksCount = 1;
1046             }
1047             /* TODO: Make sure that all of the following won't crash and will do
1048              * something reasonable when dwlink == NULL */
1049             /* delete area from config, unsubscribe at downlinks */
1050             delarea = (*call_getArea)(tmpNode->name);
1051             if(delarea != NULL && dwlink != NULL)
1052                 mandatoryal=mandatoryCheck(delarea,dwlink);
1053             if (delarea && !mandatoryal) do_delete(dwlink, delarea);
1054             /* unsubscribe at uplink */
1055             if (dwlink && !(delarea && mandatoryal)) forwardRequestToLink(tmpNode->name, dwlink, NULL, 2);
1056         }
1057     }
1058     /* send notification messages */
1059     for (i = 0; i < af_config->linkCount; i++)
1060     {
1061         if (tmpmsg[i])
1062         {
1063             xscatprintf(&tmpmsg[i]->text, "\r\r--- %s %s\r", af_versionStr, af_robot->name);
1064             tmpmsg[i]->textLength = strlen(tmpmsg[i]->text);
1065 /*
1066             processNMMsg(tmpmsg[i], NULL,
1067                 getNetMailArea(af_config,af_config->robotsArea),
1068                 0, MSGLOCAL);
1069             closeOpenedPkt();
1070             freeMsgBuffers(tmpmsg[i]);
1071 */
1072             (*call_sendMsg)(tmpmsg[i]);
1073             w_log( LL_AREAFIX, "%s: write notification msg for %s", af_robot->name, aka2str(af_config->links[i]->hisAka));
1074         }
1075         nfree(tmpmsg[i]);
1076     }
1077     /*  send msg to the links (forward requests to areafix) */
1078     sendAreafixMessages();
1079     w_log(LL_STOP, "End updating queue file");
1080 }
1081 
af_OpenQuery()1082 int af_OpenQuery()
1083 {
1084     FILE *queryFile;
1085     char *line = NULL;
1086     char *token = NULL;
1087     struct  tm tr;
1088     char seps[]   = " \t\n";
1089 
1090     if( queryAreasHead )  /*  list already exists */
1091         return 0;
1092 
1093     time( &tnow );
1094 
1095     queryAreasHead = af_AddAreaListNode("\0","\0");
1096 
1097     if( !af_robot->queueFile ) /* Queue File not defined in af_config */
1098     {
1099         w_log(LL_ERR, "queueFile for %s not defined in af_config", af_robot->name);
1100         return 0;
1101     }
1102 	if ( (queryFile = fopen(af_robot->queueFile,"r")) == NULL ) /* can't open query file */
1103     {
1104        w_log(LL_ERR, "Can't open queueFile %s: %s", af_robot->queueFile, strerror(errno) );
1105        return 0;
1106     }
1107 
1108     while ((line = readLine(queryFile)) != NULL)
1109     {
1110         s_query_areas *areaNode = NULL;
1111         token = strtok( line, seps );
1112         if( token != NULL )
1113         {
1114             areaNode = af_AddAreaListNode(token, "");
1115             if(strlen( areaNode->name ) > queryAreasHead->linksCount)
1116                 queryAreasHead->linksCount = strlen( areaNode->name );
1117             token = strtok( NULL, seps );
1118             strncpy( areaNode->type ,token, 4);
1119             token = strtok( NULL, seps );
1120             memset(&tr, '\0', sizeof(tr));
1121             if(sscanf(token, "%d-%d-%d@%d:%d",
1122                           &tr.tm_year,
1123                           &tr.tm_mon,
1124                           &tr.tm_mday,
1125                           &tr.tm_hour,
1126                           &tr.tm_min
1127                   ) != 5)
1128             {
1129                 af_DelAreaListNode(areaNode);
1130                 continue;
1131             } else {
1132                 tr.tm_year -= 1900;
1133                 tr.tm_mon--;
1134                 tr.tm_isdst =- 1;
1135                 areaNode->bTime = mktime(&tr);
1136             }
1137             token = strtok( NULL, seps );
1138             memset(&tr, '\0', sizeof(tr));
1139             if(sscanf(token, "%d-%d-%d@%d:%d",
1140                           &tr.tm_year,
1141                           &tr.tm_mon,
1142                           &tr.tm_mday,
1143                           &tr.tm_hour,
1144                           &tr.tm_min
1145                   ) != 5)
1146             {
1147                 af_DelAreaListNode(areaNode);
1148                 continue;
1149             } else {
1150                 tr.tm_year -= 1900;
1151                 tr.tm_mon--;
1152                 tr.tm_isdst =- 1;
1153                 areaNode->eTime = mktime(&tr);
1154             }
1155 
1156             token = strtok( NULL, seps );
1157             while( token != NULL )
1158             {
1159 
1160                 areaNode->linksCount++;
1161                 areaNode->downlinks = (*call_srealloc)( areaNode->downlinks,
1162                             sizeof(hs_addr)*areaNode->linksCount );
1163                 memset(&(areaNode->downlinks[areaNode->linksCount-1]), 0, sizeof(hs_addr));
1164                 parseFtnAddrZS(token,
1165                             &(areaNode->downlinks[areaNode->linksCount-1]));
1166                 token = strtok( NULL, seps );
1167             }
1168         }
1169         nfree(line);
1170     }
1171     fclose(queryFile);
1172     return 0;
1173 }
1174 
af_CloseQuery()1175 int af_CloseQuery()
1176 {
1177     char buf[2*1024] = "";
1178     char *p;
1179     int nSpace = 0;
1180     size_t i = 0;
1181     struct  tm t1,t2;
1182     int writeChanges = 0;
1183     FILE *queryFile=NULL;
1184     s_query_areas *delNode = NULL;
1185     s_query_areas *tmpNode  = NULL;
1186     char *chanagedflag = NULL;
1187     FILE *QFlag        = NULL;
1188 
1189     w_log(LL_FUNC, __FILE__ ":%u:af_CloseQuery() begin", __LINE__);
1190 
1191     if( !queryAreasHead ) {  /*  list does not exist */
1192         w_log(LL_FUNC, __FILE__ ":%u:af_CloseQuery() end", __LINE__);
1193         return 0;
1194     }
1195 
1196     if(queryAreasHead->nFlag == 1) {
1197         writeChanges = 1;
1198     }
1199     if (writeChanges)
1200     {
1201         if ((queryFile = fopen(af_robot->queueFile, "w")) == NULL)
1202         {
1203             w_log(LL_ERR,"%s: queueFile not saved", af_robot->name);
1204             writeChanges = 0;
1205         }
1206         else
1207         {
1208             if( (chanagedflag = af_GetQFlagName()) != NULL)
1209             {
1210               if( (QFlag = fopen(chanagedflag,"w")) != NULL)
1211                 fclose(QFlag);
1212               nfree(chanagedflag);
1213             }
1214         }
1215     }
1216 
1217     tmpNode = queryAreasHead->next;
1218     nSpace = queryAreasHead->linksCount+1;
1219     p = buf+nSpace;
1220     while(tmpNode) {
1221         if(writeChanges && tmpNode->type[0] != '\0')    {
1222             memset(buf, ' ' ,nSpace);
1223             memcpy(buf, tmpNode->name, strlen(tmpNode->name));
1224             t1 = *localtime( &tmpNode->bTime );
1225             t2 = *localtime( &tmpNode->eTime );
1226             sprintf( p , "%s %d-%02d-%02d@%02d:%02d\t%d-%02d-%02d@%02d:%02d" ,
1227                 tmpNode->type,
1228                 t1.tm_year + 1900,
1229                 t1.tm_mon  + 1,
1230                 t1.tm_mday,
1231                 t1.tm_hour,
1232                 t1.tm_min,
1233                 t2.tm_year + 1900,
1234                 t2.tm_mon  + 1,
1235                 t2.tm_mday,
1236                 t2.tm_hour,
1237                 t2.tm_min   );
1238             p = p + strlen(p);
1239             for(i = 0; i < tmpNode->linksCount; i++) {
1240                 strcat(p," ");
1241                 strcat(p,aka2str(tmpNode->downlinks[i]));
1242             }
1243             strcat(buf, "\n");
1244             fputs( buf , queryFile );
1245             p = buf+nSpace;
1246         }
1247         delNode = tmpNode;
1248         tmpNode = tmpNode->next;
1249         af_DelAreaListNode(delNode);
1250     }
1251 
1252     nfree(queryAreasHead->name);
1253     nfree(queryAreasHead->downlinks);
1254     nfree(queryAreasHead->report);
1255     nfree(queryAreasHead);
1256 
1257     if(queryFile) fclose(queryFile);
1258 
1259     w_log(LL_FUNC, __FILE__ ":%u:af_CloseQuery() end", __LINE__);
1260     return 0;
1261 }
1262 
af_MakeAreaListNode()1263 s_query_areas* af_MakeAreaListNode()
1264 {
1265     s_query_areas *areaNode =NULL;
1266     areaNode = (s_query_areas*)(*call_smalloc)( sizeof(s_query_areas) );
1267     memset( areaNode ,'\0', sizeof(s_query_areas) );
1268     return areaNode;
1269 }
1270 
af_AddAreaListNode(char * areatag,const char * type)1271 s_query_areas* af_AddAreaListNode(char *areatag, const char *type)
1272 {
1273     s_query_areas *tmpNode      = NULL;
1274     s_query_areas *tmpPrevNode  = NULL;
1275     s_query_areas *newNode  = af_MakeAreaListNode();
1276 
1277     newNode->name = sstrlen(areatag) > 0 ? (*call_sstrdup)(areatag) : NULL;
1278     strcpy( newNode->type ,type);
1279 
1280     tmpPrevNode = tmpNode = queryAreasHead;
1281 
1282     while(tmpNode)
1283     {
1284         if( tmpNode->name && strlen(tmpNode->name) > 0 )
1285             if( stricmp(areatag,tmpNode->name) < 0 )
1286                 break;
1287         tmpPrevNode = tmpNode;
1288         tmpNode = tmpNode->next;
1289     }
1290     if(tmpPrevNode)
1291     {
1292         tmpPrevNode->next = newNode;
1293         newNode->next     = tmpNode;
1294     }
1295     return newNode;
1296 }
1297 
af_DelAreaListNode(s_query_areas * node)1298 void af_DelAreaListNode(s_query_areas* node)
1299 {
1300     s_query_areas* tmpNode = queryAreasHead;
1301 
1302     while(tmpNode->next && tmpNode->next != node)
1303     {
1304         tmpNode = tmpNode->next;
1305     }
1306     if(tmpNode->next)
1307     {
1308         tmpNode->next = node->next;
1309         nfree(node->name);
1310         nfree(node->downlinks);
1311         nfree(node->report);
1312         nfree(node);
1313     }
1314 }
1315 
af_AddLink(s_query_areas * node,ps_addr link)1316 void af_AddLink(s_query_areas* node, ps_addr link)
1317 {
1318     node->linksCount++;
1319     node->downlinks = (*call_srealloc)( node->downlinks, sizeof(hs_addr)*node->linksCount );
1320     memcpy( &(node->downlinks[node->linksCount-1]) ,link, sizeof(hs_addr) );
1321     node->bTime = tnow;
1322     queryAreasHead->nFlag = 1; /*  query was changed */
1323 }
1324 
1325 /* originally from hpt/src/toss.c */
getAreaLink(s_area * area,hs_addr aka)1326 s_arealink *getAreaLink(s_area *area, hs_addr aka)
1327 {
1328     UINT i;
1329 
1330     for (i = 0; i <area->downlinkCount; i++) {
1331         if (addrComp(aka, area->downlinks[i]->link->hisAka)==0) return area->downlinks[i];
1332     }
1333 
1334     return NULL;
1335 }
1336 
1337 /* originally from hpt/src/toss.c */
1338 /*  import: type == 0, export: type != 0 */
1339 /*  return value: 0 if access ok, 3 if import/export off, 4 if not linked, */
1340 /*  15 if area is paused */
checkAreaLink(s_area * area,hs_addr aka,int type)1341 int checkAreaLink(s_area *area, hs_addr aka, int type)
1342 {
1343     s_arealink *arealink = NULL;
1344     int writeAccess = 0;
1345 
1346     arealink = getAreaLink(area, aka);
1347     if (arealink) {
1348 	if (type==0) {
1349 	    if (!arealink->import) writeAccess = BM_DENY_IMPORT;
1350 	} else {
1351 	    if (!arealink->aexport) writeAccess = BM_DENY_IMPORT;
1352 	}
1353     } else {
1354 	if (addrComp(aka, *area->useAka)!=0) writeAccess = BM_NOT_LINKED;
1355     }
1356 
1357     if (writeAccess==0 && area->paused) writeAccess = BM_AREA_IS_PAUSED;
1358 
1359     return writeAccess;
1360 }
1361