1 /******************************************************************************
2 * FIDOCONFIG --- library for fidonet configs
3 ******************************************************************************
4 * afixcmd.c : common areafix commands
5 *
6 * Compiled from hpt/areafix hpt/toss hpt/pkt
7 * by Max Chernogor <mihz@mail.ru>, 2:464/108@fidonet
8 *
9 * This file is part of FIDOCONFIG library (part of the Husky FIDOnet
10 * software project)
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published
14 * by the Free Software Foundation; either version 2, or (at your option)
15 * any later version.
16 *
17 * FIDOCONFIG library is distributed in the hope that it will be useful,
18 * but 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 FIDOCONFIG library; see the file COPYING. If not, write
24 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA
25 *
26 * See also http://www.gnu.org
27 *****************************************************************************
28 * $Id$
29 */
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include <huskylib/huskylib.h>
38
39 #ifdef HAS_UNISTD_H
40 # include <unistd.h>
41 #endif
42
43 #ifdef HAS_IO_H
44 # include <io.h>
45 #endif
46
47 #ifdef HAS_STRINGS_H
48 # include <strings.h>
49 #endif
50
51 /* export functions from DLL */
52 #define DLLEXPORT
53 #include <huskylib/huskyext.h>
54
55 #include "afixcmd.h"
56 #include "common.h"
57
expandCfgLine(char * cfgline)58 char* expandCfgLine(char* cfgline)
59 {
60 cfgline = trimLine(cfgline);
61 cfgline = shell_expand(cfgline);
62 cfgline = vars_expand(cfgline);
63 return cfgline;
64 }
65
FindTokenPos4Link(char ** confName,char * ftoken,char * fftoken,s_link * link,long * start,long * end)66 int FindTokenPos4Link(char **confName, char* ftoken, char *fftoken, s_link *link, long* start, long* end)
67 {
68 char* cfgline, *line, *token, *linkConfName;
69 long linkstart=0;
70
71 *start=0; *end=0;
72
73 if (init_conf(*confName))
74 return 0;
75
76 while ((cfgline = configline()) != NULL) {
77 cfgline = expandCfgLine(cfgline);
78 line = cfgline;
79 token = strseparate(&line, " \t");
80 if (!token || strcasecmp(token, "link")) {
81 nfree(cfgline);
82 continue;
83 }
84 linkliner:
85 nfree(cfgline);
86 for (;;) {
87 if ((cfgline = configline()) == NULL) {
88 close_conf();
89 return 0;
90 }
91 cfgline = expandCfgLine(cfgline);
92 if (!*cfgline) {
93 nfree(cfgline);
94 continue;
95 }
96 line = cfgline;
97 token = strseparate(&line, " \t");
98 if (!token) {
99 nfree(cfgline);
100 continue;
101 }
102 if (stricmp(token, "link") == 0)
103 goto linkliner;
104 if (stricmp(token, "aka") == 0) break;
105 nfree(cfgline);
106 }
107 token = strseparate(&line, " \t");
108 if (!token || testAddr(token, link->hisAka) == 0) {
109 nfree(cfgline);
110 continue;
111 }
112 nfree(cfgline);
113 linkstart = get_hcfgPos();
114 linkConfName = sstrdup(getCurConfName());
115 /* try to find alternative token
116 ex.: areaFixPwd should be inserted after defaultPwd */
117 if (fftoken) {
118 for (;;) {
119 if ((cfgline = configline()) == NULL) {
120 /* !!! val: delete this if no bugs !!!
121 *start = *end = linkstart;
122 *confName = linkConfName;
123 close_conf();
124 return 0;*/
125 fseek(get_hcfg(), linkstart, SEEK_SET);
126 break;
127 }
128 cfgline = expandCfgLine(cfgline);
129 if (!*cfgline) {
130 nfree(cfgline);
131 continue;
132 }
133 line = cfgline;
134 token = strseparate(&line, " \t");
135 if (token && stricmp(token, "link") == 0)
136 {
137 /* !!! val: delete this if no bugs !!!
138 *start = *end = linkstart;
139 *confName = linkConfName;
140 close_conf();
141 return 0;*/
142 fseek(get_hcfg(), linkstart, SEEK_SET);
143 break;
144 }
145 if (token && stricmp(token, fftoken) == 0) break;
146 nfree(cfgline);
147 }
148 nfree(cfgline);
149 linkstart = get_hcfgPos();
150 linkConfName = sstrdup(getCurConfName());
151 }
152 for (;;) {
153 if ((cfgline = configline()) == NULL) {
154 *start = *end = linkstart;
155 *confName = linkConfName;
156 close_conf();
157 return 0;
158 }
159 cfgline = expandCfgLine(cfgline);
160 if (!*cfgline) {
161 nfree(cfgline);
162 continue;
163 }
164 line = cfgline;
165 token = strseparate(&line, " \t");
166 if (token && stricmp(token, "link") == 0)
167 {
168 *start = *end = linkstart;
169 *confName = linkConfName;
170 close_conf();
171 return 0;
172 }
173 if (token && stricmp(token, ftoken) == 0) break;
174 nfree(cfgline);
175 }
176 /* remove line */
177 nfree(cfgline);
178 *start = getCurConfPos();
179 *end = get_hcfgPos();
180 *confName = sstrdup(getCurConfName());
181 close_conf();
182 return 1;
183 }
184 return 0;
185 }
186
InsertCfgLine(char * confName,char * cfgLine,long strbeg,long strend)187 int InsertCfgLine(char *confName, char* cfgLine, long strbeg, long strend)
188 {
189 char *line = NULL, *newname = NULL, *p;
190 FILE *f_conf, *f_newconf;
191 long endpos,curpos,cfglen;
192 int openro = 0;
193
194 f_conf = f_newconf = NULL;
195 if ((strbeg == 0 && strend == 0) || confName == NULL)
196 return 0;
197
198 if ((f_conf = fopen(confName, "r+b")) == NULL) {
199 if ((f_conf = fopen(confName, "rb")) == NULL) {
200 w_log(LL_ERR, "Cannot open config file %s: %s\n", confName, strerror(errno));
201 return 0;
202 }
203 openro = 1;
204 }
205 if (fseek(f_conf, 0L, SEEK_END) != 0) {
206 w_log(LL_ERR, "Cannot seek config file %s: %s\n", confName, strerror(errno));
207 fclose(f_conf);
208 return 0;
209 }
210 endpos = ftell(f_conf);
211 curpos = strend;
212 cfglen = endpos - curpos;
213 newname = (char *)smalloc(strlen(confName) + 5);
214 strcpy(newname, confName);
215 p=strrchr(newname, '.');
216 if (p==NULL || strchr(p, PATH_DELIM))
217 strcat(newname, ".tmp");
218 else
219 strcpy(p, ".tmp");
220 if ( (f_newconf = fopen(newname, "wb")) == NULL ) {
221 /* we have no write access to this directory? */
222 /* change config "in place" */
223 if (openro) {
224 w_log(LL_ERR, "Cannot open temp file %s: %s\n", newname, strerror(errno));
225 nfree(newname);
226 fclose(f_conf);
227 return 0;
228 }
229 nfree(newname);
230 line = (char*) smalloc((size_t) cfglen);
231 fseek(f_conf, curpos, SEEK_SET);
232 if (fread(line, sizeof(char), cfglen, f_conf) != (size_t)cfglen) {
233 w_log(LL_ERR, "Cannot read config file %s: %s\n", confName, strerror(errno));
234 nfree(line);
235 fclose(f_conf);
236 return 0;
237 }
238 fseek(f_conf, strbeg, SEEK_SET);
239 setfsize( fileno(f_conf), strbeg );
240 if (cfgLine) /* line not deleted */
241 {
242 if (fprintf(f_conf, "%s%s", cfgLine, cfgEol()) != (int)(strlen(cfgLine)+strlen(cfgEol())))
243 w_log(LL_ERR, "Cannot write config file %s: %s\n", confName, strerror(errno));
244 }
245 if (fwrite(line, sizeof(char), cfglen, f_conf) != (size_t)cfglen ||
246 fflush(f_conf) != 0)
247 {
248 w_log(LL_ERR, "Cannot write config file %s: %s\n", confName, strerror(errno));
249 }
250 fclose(f_conf);
251 nfree(line);
252 } else {
253 /* make new config-file and rename it */
254 #ifdef __UNIX__
255 struct stat st;
256 if (fstat(fileno(f_conf), &st) == 0)
257 fchmod(fileno(f_newconf), (st.st_mode & 01777) | 0400);
258 #endif
259 line = (char*) smalloc(cfglen > strbeg ? cfglen : strbeg);
260 fseek(f_conf, 0L, SEEK_SET);
261 if (fread(line, sizeof(char), strbeg, f_conf) < (size_t)strbeg) {
262 w_log(LL_ERR, "Cannot read config file %s: %s\n", confName, strerror(errno));
263 errwriteconf:
264 fclose(f_conf);
265 fclose(f_newconf);
266 unlink(newname);
267 nfree(line);
268 nfree(newname);
269 return 0;
270 }
271 if (fwrite(line, sizeof(char), strbeg, f_newconf) < (size_t)strbeg) {
272 w_log(LL_ERR, "Cannot write config file %s: %s\n", newname, strerror(errno));
273 goto errwriteconf;
274 }
275 if (cfgLine) {
276 if (fprintf(f_newconf, "%s%s", cfgLine, cfgEol()) != (int)(strlen(cfgLine)+strlen(cfgEol())))
277 {
278 w_log(LL_ERR, "Cannot write config file %s: %s\n", newname, strerror(errno));
279 goto errwriteconf;
280 }
281 }
282 fseek(f_conf, curpos, SEEK_SET);
283 if (fread(line, sizeof(char), cfglen, f_conf) != (size_t)cfglen) {
284 w_log(LL_ERR, "Cannot read config file %s: %s\n", confName, strerror(errno));
285 goto errwriteconf;
286 }
287 if (fwrite(line, sizeof(char), cfglen, f_newconf) != (size_t)cfglen ||
288 fflush(f_newconf) != 0) {
289 w_log(LL_ERR, "Cannot write config file %s: %s\n", newname, strerror(errno));
290 goto errwriteconf;
291 }
292 fclose(f_newconf);
293 fclose(f_conf);
294 nfree(line);
295 /* save old config as *.bak? */
296 /*
297 #ifndef __UNIX__
298 unlink(confName);
299 #endif
300 */
301 /* if (rename(newname, confName)) { */
302 if (move_file(newname, confName,1)) {
303 w_log(LL_ERR, "Cannot rename config file %s->%s: %s\n", newname, confName, strerror(errno));
304 nfree(newname);
305 return 0;
306 }
307 nfree(newname);
308 }
309 return 1;
310 }
311
312 /* opt = 0 - AreaFix */
313 /* opt = 1 - AutoPause */
Changepause(char * confName,s_link * link,int opt,int type)314 int Changepause(char *confName, s_link *link, int opt, int type)
315 {
316 long strbeg=0;
317 long strend=0;
318
319 FindTokenPos4Link(&confName, "pause", NULL, link, &strbeg, &strend);
320
321 link->Pause ^= type;
322
323 if (link->Pause == NOPAUSE) {
324 if(InsertCfgLine(confName, "Pause off", strbeg, strend))
325 w_log('8', "areafix: system %s set active", aka2str(link->hisAka));
326 } else if(link->Pause == (ECHOAREA|FILEAREA)) {
327 if(InsertCfgLine(confName, "Pause on", strbeg, strend))
328 w_log('8', "%s: system %s set passive",
329 opt ? "autopause" : "areafix", aka2str(link->hisAka));
330 } else if(link->Pause == ECHOAREA) {
331 if(InsertCfgLine(confName, "Pause Earea", strbeg, strend))
332 w_log('8', "%s: system %s set passive only for echoes",
333 opt ? "autopause" : "areafix", aka2str(link->hisAka));
334 } else {
335 if(InsertCfgLine(confName, "Pause Farea", strbeg, strend))
336 w_log('8', "%s: system %s set passive only for file echoes",
337 opt ? "autopause" : "areafix", aka2str(link->hisAka));
338 }
339 nfree(confName);
340 return 1;
341 }
342
testAddr(char * addr,hs_addr hisAka)343 int testAddr(char *addr, hs_addr hisAka)
344 {
345 hs_addr aka = {0};
346 parseFtnAddrZS(addr, &aka);
347 if (addrComp(aka, hisAka)==0) return 1;
348 return 0;
349 }
350
DelLinkFromString(char * line,hs_addr linkAddr)351 int DelLinkFromString(char *line, hs_addr linkAddr)
352 {
353 int rc = 1;
354 char *end = NULL;
355 char *beg = NULL;
356
357 w_log(LL_FUNC, "::DelLinkFromString() begin");
358
359 beg = strrchr(line, '"'); /* seek end comment pointer (quote char) */
360 if(!beg) beg = line; /* if not found then seek from begin */
361 beg++; /* process next token */
362 while(*beg) /* while not end of string */
363 {
364 while(*beg && isspace(*beg)) beg++; /* skip spaces */
365 if(*beg && isdigit(*beg) && testAddr(beg, linkAddr))
366 {
367 rc = 0;
368 break;
369 }
370 while(*beg && !isspace(*beg)) beg++; /* skip token */
371 }
372 if(rc == 0) /* beg points to begin of unsubscribed address */
373 {
374 end = beg;
375 while(*beg && !isspace(*beg)) beg++; /* skip token */
376 while(*beg && !isdigit(*beg)) beg++; /* find for next link */
377 if(beg && *beg)
378 {
379 memmove(end,beg,strlen(beg)+1);
380 }
381 else
382 {
383 end--;
384 *end = '\0';
385 }
386 }
387
388 w_log(LL_FUNC, "%::DelLinkFromString() end");
389 return rc;
390 }
391
IsAreaAvailable(char * areaName,char * fileName,char ** desc,int retd)392 int IsAreaAvailable(char *areaName, char *fileName, char **desc, int retd) {
393 FILE *f;
394 char *line, *token, *running;
395
396 if (fileName==NULL || areaName==NULL) return 0;
397
398 if ((f=fopen(fileName,"r")) == NULL) {
399 w_log('8',"Allfix: cannot open file \"%s\"",fileName);
400 return 0;
401 }
402
403 while ((line = readLine(f)) != NULL) {
404 line = trimLine(line);
405 if (line[0] != '\0') {
406
407 running = line;
408 token = strseparate(&running, " \t\r\n");
409
410 if (token && areaName && stricmp(token, areaName)==0) {
411 /* return description if needed */
412 if (retd) {
413 *desc = NULL;
414 if (running) {
415 /* strip "" at the beginning & end */
416 if (running[0]=='"' && running[strlen(running)-1]=='"') {
417 running++; running[strlen(running)-1]='\0';
418 }
419 /* change " -> ' */
420 token = running;
421 while (*token!='\0') {
422 if (*token=='"') *token='\'';
423 token++;
424 }
425 xstrcat(&(*desc), running);
426 }
427 }
428 nfree(line);
429 fclose(f);
430 return 1;
431 }
432 }
433 nfree(line);
434 }
435 /* not found */
436 fclose(f);
437 return 0;
438 }
439
Addlink(s_fidoconfig * config,s_link * link,s_area * area)440 void Addlink(s_fidoconfig *config, s_link *link, s_area *area)
441 {
442 char *ExclMask;
443 UINT i;
444
445 if(area)
446 {
447 s_arealink *arealink;
448 area->downlinks = srealloc(area->downlinks, sizeof(s_arealink*)*(area->downlinkCount+1));
449 arealink = area->downlinks[area->downlinkCount] = (s_arealink*) scalloc(1, sizeof(s_arealink));
450 arealink->link = link;
451 area->downlinkCount++;
452
453 setLinkAccess(config, area, arealink);
454
455 if (config->readOnlyCount) {
456 for (i=0; i < config->readOnlyCount; i++) {
457 if(config->readOnly[i].areaMask[0] != '!') {
458 if (patimat(area->areaName, config->readOnly[i].areaMask) &&
459 patmat(aka2str(link->hisAka), config->readOnly[i].addrMask)) {
460 arealink->import = 0;
461 }
462 } else {
463 ExclMask = config->readOnly[i].areaMask;
464 ExclMask++;
465 if (patimat(area->areaName, ExclMask) &&
466 patmat(aka2str(link->hisAka), config->readOnly[i].addrMask)) {
467 arealink->import = 1;
468 }
469 }
470 }
471 }
472
473 if (config->writeOnlyCount) {
474 for (i=0; i < config->writeOnlyCount; i++) {
475 if(config->writeOnly[i].areaMask[0] != '!') {
476 if (patimat(area->areaName, config->writeOnly[i].areaMask) &&
477 patmat(aka2str(link->hisAka), config->writeOnly[i].addrMask)) {
478 arealink->aexport = 0;
479 }
480 } else {
481 ExclMask = config->writeOnly[i].areaMask;
482 ExclMask++;
483 if (patimat(area->areaName, ExclMask) &&
484 patmat(aka2str(link->hisAka), config->writeOnly[i].addrMask)) {
485 arealink->aexport = 1;
486 }
487 }
488 }
489 }
490 }
491 }
492
RemoveLink(s_link * link,s_area * area)493 void RemoveLink(s_link *link, s_area *area)
494 {
495 if(area) /* remove link from echoarea */
496 {
497 int i = isAreaLink(link->hisAka, area);
498 if (i != -1) {
499 nfree(area->downlinks[i]);
500 area->downlinks[i] = area->downlinks[area->downlinkCount-1];
501 area->downlinkCount--;
502 }
503 }
504 }
505
506
507 /* ---------------- areafix checking stuff --------------*/
508
509 /* test area-link pair to mandatory */
mandatoryCheck(s_area * area,s_link * link)510 int mandatoryCheck(s_area *area, s_link *link)
511 {
512 int i;
513
514 w_log(LL_FUNC, __FILE__ "::mandatoryCheck()");
515
516 if (grpInArray(area->group,link->optGrp,link->numOptGrp)&&link->mandatory){
517 w_log(LL_FUNC, __FILE__ "::mandatoryCheck() rc=1");
518 return 1;
519 }
520 if (link->numOptGrp==0 && link->mandatory){
521 w_log(LL_FUNC, __FILE__ "::mandatoryCheck() rc=1");
522 return 1;
523 }
524 if (area->mandatory){
525 w_log(LL_FUNC, __FILE__ "::mandatoryCheck() rc=1");
526 return 1;
527 }
528 if ((i=isAreaLink(link->hisAka, area))!=-1){
529 w_log(LL_FUNC, __FILE__ "::mandatoryCheck() rc=%d", area->downlinks[i]->mandatory);
530 return area->downlinks[i]->mandatory;
531 }
532 w_log(LL_FUNC, __FILE__ "::mandatoryCheck() rc=0");
533 return 0;
534 }
535
536 /* test area-link pair to manual */
manualCheck(s_area * area,s_link * link)537 int manualCheck(s_area *area, s_link *link)
538 {
539 int i;
540
541 w_log(LL_FUNC, __FILE__ "::manualCheck()");
542
543 if (grpInArray(area->group,link->optGrp,link->numOptGrp)&&link->manual){
544 w_log(LL_FUNC, __FILE__ "::manualCheck() rc=1");
545 return 1;
546 }
547 if (link->numOptGrp==0 && link->manual){
548 w_log(LL_FUNC, __FILE__ "::manualCheck() rc=1");
549 return 1;
550 }
551 if (area->manual) {
552 w_log(LL_FUNC, __FILE__ "::manualCheck() rc=1");
553 return 1;
554 }
555 if ((i=isAreaLink(link->hisAka, area))!=-1){
556 w_log(LL_FUNC, __FILE__ "::manualCheck() rc=%d", area->downlinks[i]->manual);
557 return area->downlinks[i]->manual;
558 }
559 w_log(LL_FUNC, __FILE__ "::manualCheck() rc=0");
560 return 0;
561 }
562
subscribeCheck(s_area * area,s_link * link)563 int subscribeCheck(s_area *area, s_link *link)
564 {
565 int found = 0;
566 s_fidoconfig *config = theApp.config;
567
568 w_log( LL_FUNC, "%s::subscribeCheck() begin", __FILE__ );
569
570 if (isLinkOfArea(link, area)) return 0;
571
572 if (area->group) {
573 if (config->numPublicGroup)
574 found = grpInArray(area->group,config->PublicGroup,config->numPublicGroup);
575 if (!found && link->numAccessGrp)
576 found = grpInArray(area->group,link->AccessGrp,link->numAccessGrp);
577 } else found = 1;
578
579 if ((area->levelwrite > link->level) && (area->levelread > link->level))
580 found = 0;
581
582 if (!found){
583 w_log( LL_FUNC, "%s::subscribeCheck() end, rc=2", __FILE__ );
584 return 2;
585 }
586 if (area->hide) return 3;
587
588 w_log( LL_FUNC, "%s::subscribeCheck() end, rc=1", __FILE__ );
589 return 1;
590 }
591
subscribeAreaCheck(s_area * area,char * areaname,s_link * link)592 int subscribeAreaCheck(s_area *area, char *areaname, s_link *link)
593 {
594 int rc=4;
595
596 w_log( LL_SRCLINE, "%s::subscribeAreaCheck()", __FILE__ );
597
598 if( (!areaname)||(!areaname[0]) ){
599 w_log( LL_SRCLINE, "%s::subscribeAreaCheck() Failed (areaname empty) rc=%d", __FILE__, rc );
600 return rc;
601 }
602 if (patimat(area->areaName,areaname)==1) {
603 rc=subscribeCheck(area, link);
604 /* 0 - already subscribed / linked */
605 /* 1 - need subscribe / not linked */
606 /* 2 - no access */
607 /* 3 - area is hidden */
608 }
609 /* else: this is another area */
610 w_log( LL_SRCLINE, "%s::subscribeAreaCheck() end rc=%d", __FILE__, rc );
611 return rc;
612 }
613
614 /* test link for areas quantity limit exceed
615 * return 0 if not limit exceed
616 * else return not zero
617 */
limitCheck(s_link * link)618 int limitCheck(s_link *link) {
619 register unsigned int i,n;
620 unsigned echoLimit = 0;
621 unsigned areaCount = 0;
622 ps_area areas = NULL;
623
624 if (theApp.module == M_HPT) {
625 echoLimit = link->areafix.echoLimit;
626 areaCount = theApp.config->echoAreaCount;
627 areas = theApp.config->echoAreas;
628 }
629 else if (theApp.module == M_HTICK) {
630 echoLimit = link->filefix.echoLimit;
631 areaCount = theApp.config->fileAreaCount;
632 areas = theApp.config->fileAreas;
633 }
634 w_log(LL_FUNC, __FILE__ "::limitCheck()");
635
636 if (echoLimit==0) return 0;
637
638 for (i=n=0; i < areaCount; i++)
639 if (isLinkOfArea(link, &(areas[i])))
640 n++;
641
642 i = n >= echoLimit ;
643
644 w_log(LL_FUNC, __FILE__ "::limitCheck() rc=%u", i);
645 return i;
646 }
647