1 /*
2 * hptlink - areas linker for Highly Portable Tosser (hpt)
3 * by Serguei Revtov 2:5021/11.10 || 2:5021/19.1
4 * Some code was taken from hpt/src/link.c by Kolya Nesterov
5 *
6 * This file is part of HPT.
7 *
8 * HPT is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * HPT is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HPT; see the file COPYING. If not, write to the Free
20 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 *****************************************************************************
22 * $Id$
23 */
24
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33
34 #include <huskylib/compiler.h>
35
36 #ifdef HAS_IO_H
37 #include <io.h>
38 #endif
39
40 #ifdef HAS_UNISTD_H
41 #include <unistd.h>
42 #endif
43
44 #ifdef HAS_SHARE_H
45 #include <share.h>
46 #endif
47
48 #include <smapi/msgapi.h>
49 #include <fidoconf/common.h>
50 #include <huskylib/xstr.h>
51
52 #include <version.h>
53 #include <areafix/areafix.h>
54 #include <global.h>
55 #include "cvsdate.h"
56
57
58 /* internal structure holding msg's related to link information */
59 /* used by linkArea */
60 struct msginfo {
61 char *replyId;
62 char *msgId;
63 char *subject;
64 UMSGID replyToPos;
65 UMSGID replies[MAX_REPLY];
66 UMSGID treeId;
67 int freeReply;
68 UMSGID msgPos;
69
70 };
71 typedef struct msginfo s_msginfo;
72
73 #define reply1st replies[0]
74 #define replyNxt replies[1]
75
76
77 struct origlinks {
78 UMSGID replyToPos;
79 UMSGID replies[MAX_REPLY];
80 };
81 typedef struct origlinks s_origlinks;
82
83 #define LOGFILENAME "hptlink.log"
84
85 s_log *hptlink_log = NULL;
86 s_fidoconfig *config;
87
88 int singleRepl = 1;
89 int hardSearch = 0;
90 int useSubj = 1;
91 int useReplyId = 1;
92 int loglevel = 10;
93 int linkNew = 0;
94 HAREA harea;
95 int maxreply;
96
97
98 long links_msgid=0L;
99 long links_replid=0L;
100 long links_subj=0L;
101 long links_revmsgid=0L;
102 long links_total=0L;
103 long links_ignored=0L;
104
105 char *versionStr;
106
skipReSubj(char * subjstr)107 char *skipReSubj ( char *subjstr )
108 {
109 char *ptr;
110
111 if ( !subjstr ) return (NULL);
112
113 if ( *subjstr != 'R' && *subjstr != 'r' ) return (NULL);
114 subjstr++;
115
116 if ( *subjstr != 'e' && *subjstr != 'E' ) return (NULL);
117 subjstr++;
118
119 if ( *subjstr == '^' ) {
120 subjstr++;
121 while ( isdigit (*subjstr) ) subjstr++;
122 }
123
124 if ( *subjstr != ':' ) return (NULL);
125 subjstr++;
126
127 while ( *subjstr == ' ' ) subjstr++;
128
129 if ( (ptr = skipReSubj ( subjstr )) != NULL ) subjstr = ptr;
130
131 return (subjstr);
132
133 }
134
cmpMsgIdReply(register char * str1,register char * str2)135 int cmpMsgIdReply (register char *str1, register char *str2)
136 {
137 while (*str1==*str2 && *str1) {
138 if (*str1=='@') while (*str1 && *str1!=' ') str1++; /* skip domain */
139 if (*str1) str1++;
140 if (*str2=='@') while (*str2 && *str2!=' ') str2++; /* skip domain */
141 if (*str2) str2++;
142 }
143 if (*str1=='\0' && *str2=='\0') return 0;
144 return 1;
145 }
146
linkMsgs(s_msginfo * crepl,s_msginfo * srepl,dword i,dword j,s_msginfo * replmap)147 void linkMsgs ( s_msginfo *crepl, s_msginfo *srepl, dword i, dword j, s_msginfo *replmap )
148 {
149 dword linkTo;
150
151 if (crepl -> msgId && srepl -> msgId &&
152 strcmp ( crepl -> msgId, srepl -> msgId) == 0) {
153 w_log( LL_WARN, "Warning: msg %ld is dupe to %ld", (long)i, (long)j);
154 links_ignored++;
155 return;
156 }
157
158 if (maxreply == MAX_REPLY) { /* Squish */
159 if (crepl -> freeReply >= maxreply)
160 {
161 w_log( LL_WARN, "replies count for msg %ld exceeds %d, rest of the replies won't be linked", (long)j, maxreply);
162 links_ignored++;
163 } else {
164 links_total++;
165 (crepl -> replies)[(crepl -> freeReply)++] = srepl->msgPos;
166 srepl -> replyToPos = crepl->msgPos;
167 }
168
169 } else { /* Jam, maybe something else? */
170
171 if(srepl -> replyToPos) {
172 w_log( LL_WARN, "Thread linking broken because of dupes");
173 links_ignored++;
174 return;
175 }
176
177 srepl -> replyToPos = crepl->msgPos;
178 links_total++;
179 if (crepl->reply1st == 0) {
180 crepl->reply1st = srepl->msgPos;
181 (crepl -> freeReply)++;
182 } else {
183 linkTo = MsgUidToMsgn(harea, crepl->reply1st, UID_EXACT) - 1;
184 if(linkTo == (dword)-1) {
185 w_log( LL_WARN, "Thread linking broken. MsgUidToMsgn() returned -1");
186 links_ignored++;
187 return;
188 }
189
190 while (replmap[linkTo].replyNxt) {
191 linkTo = MsgUidToMsgn(harea, replmap[linkTo].replyNxt, UID_EXACT) - 1;
192 if(linkTo == (dword)-1) {
193 w_log( LL_WARN, "Thread linking broken. MsgUidToMsgn() returned -1");
194 links_ignored++;
195 return;
196 }
197 }
198 replmap[linkTo].replyNxt = srepl->msgPos;
199 replmap[linkTo].freeReply++;
200 }
201 }
202 }
203
GetCtrlValue(char * ctl,char * kludge)204 static char *GetCtrlValue (char *ctl, char *kludge)
205 {
206 char *value, *end, *out, *p;
207
208 if ( !ctl || !kludge ) return (NULL);
209
210 if ( (value = strstr( ctl, kludge)) == NULL ) return (NULL);
211
212 if ( value[-1] != '\001') return (NULL);
213
214 value += strlen(kludge); /* skip kludge name (i.e. MSGID: or REPLY:) */
215
216 for (end = value; *end != '\001' && *end; end++);
217
218 if ((end - value) <= 0) return (NULL);
219
220 out = (char *) smalloc((size_t) (end - value) + 1 );
221 if (out == NULL) return (NULL);
222
223 memcpy(out, value, (size_t) (end - value));
224 out[(size_t) (end - value)] = '\0';
225
226 /* fix for upper case msgids */
227 strLower(out);
228 /* remove .0 from node address */
229 if (NULL!=(p=strstr(out,".0 "))) memmove(p,p+2,strlen(p+2)+1);
230
231 return out;
232
233 }
234
235
linkArea(s_area * area)236 void linkArea(s_area *area)
237 {
238 byte *ctl = NULL;
239 dword ctlen_curr=0;
240 dword ctlen;
241 dword highMsg;
242 dword i, j, linkTo;
243 dword newStart=0;
244 HMSG hmsg;
245 XMSG xmsg;
246 s_msginfo *replmap;
247 s_msginfo *crepl, *srepl;
248 s_origlinks *links;
249 s_origlinks *linksptr;
250 dword treeLinks=0;
251 int replFound;
252 int replDone;
253 char *ptr;
254
255 if ((area->msgbType & MSGTYPE_PASSTHROUGH) == MSGTYPE_PASSTHROUGH) {
256 w_log( LL_LINKING, "PASSTHROUGH area %s, skip", area->areaName);
257 return;
258 }
259
260 if (area->nolink) {
261 w_log( LL_LINKING, "area %s has nolink option, skip", area->areaName);
262 return;
263 }
264
265 w_log( LL_LINKING, "linking area %s...", area->areaName);
266
267 if (area->msgbType & MSGTYPE_JAM || area->msgbType & MSGTYPE_SDM) {
268 maxreply = 2;
269 } else {
270 maxreply = MAX_REPLY;
271 }
272
273 harea = MsgOpenArea((byte *) area->fileName, MSGAREA_NORMAL, (word)area->msgbType);
274
275 if (harea)
276 {
277 highMsg = MsgGetHighMsg(harea);
278
279 if ( highMsg < 2 ) {
280 w_log( LL_LINKING, "nothing to link (%ld messages)", (long)highMsg);
281 MsgCloseArea(harea);
282 return;
283 }
284
285 if ( (replmap = (s_msginfo *) scalloc (highMsg, sizeof(s_msginfo))) == NULL){
286 w_log( LL_CRIT,"Out of memory. Want %ld bytes", (long) sizeof(s_msginfo)*highMsg);
287 MsgCloseArea(harea);
288 closeLog();
289 disposeConfig(config);
290 exit(EX_SOFTWARE);
291 }
292
293 if ( (links = (s_origlinks *) scalloc (highMsg, sizeof(s_origlinks))) == NULL){
294 w_log( LL_CRIT, "Out of memory: can't get %ld bytes", (long) sizeof(s_origlinks)*highMsg);
295 MsgCloseArea(harea);
296 closeLog();
297 disposeConfig(config);
298 exit(EX_SOFTWARE);
299 }
300
301 /* Pass 1: read all message information in memory */
302 w_log( LL_LINKPASS, "Pass 1 - reading");
303
304 for (i = 1, crepl=replmap, linksptr=links; i <= highMsg; i++, crepl++, linksptr++)
305 {
306 hmsg = MsgOpenMsg(harea, MOPEN_READ, i);
307 if (hmsg){
308 ctlen = MsgGetCtrlLen(hmsg);
309 if( ctlen == 0 )
310 {
311 w_log( LL_WARN, "msg %ld has no control information", (long) i);
312 MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL);
313
314 } else {
315 if( ctl==NULL || ctlen_curr < ctlen + 1) {
316 ctl = (byte *) srealloc(ctl, ctlen + 1);
317 if (ctl == NULL) {
318 w_log( LL_CRIT,"out of memory while linking on msg %ld", (long) i);
319 MsgCloseArea(harea);
320 closeLog();
321 disposeConfig(config);
322 exit(EX_SOFTWARE);
323 }
324
325 ctlen_curr = ctlen + 1;
326 }
327 MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, ctlen, ctl);
328
329 ctl[ctlen] = '\0';
330
331 if ( useReplyId ) {
332 crepl -> replyId = (char *) GetCtrlValue( (char *)ctl, "REPLY:");
333 crepl -> msgId = (char *) GetCtrlValue( (char *)ctl, "MSGID:");
334 }
335
336 }
337
338 if ( useSubj && xmsg.subj != NULL) {
339 if ( (ptr=skipReSubj((char*)xmsg.subj)) == NULL)
340 ptr = (char*) xmsg.subj;
341 crepl -> subject = sstrdup(ptr);
342 }
343
344 crepl->msgPos = MsgMsgnToUid(harea, i);
345
346 /* Save data for comparing */
347 if (area->msgbType & MSGTYPE_JAM || area->msgbType & MSGTYPE_SDM) {
348 linksptr->reply1st = xmsg.xmreply1st;
349 linksptr->replyNxt = xmsg.xmreplynext;
350 } else {
351 memcpy(linksptr->replies, xmsg.replies, sizeof(UMSGID) * MAX_REPLY);
352 }
353 linksptr->replyToPos = xmsg.replyto;
354
355 if (linkNew) {
356 if (area->msgbType & MSGTYPE_JAM || area->msgbType & MSGTYPE_SDM) {
357 if (xmsg.replyto || xmsg.xmreply1st || xmsg.xmreplynext) {
358 newStart = i+1;
359 crepl->replyToPos = xmsg.replyto;
360 crepl->reply1st = xmsg.xmreply1st;
361 crepl->replyNxt = xmsg.xmreplynext;
362 }
363
364 } else {
365
366 if (xmsg.replyto || xmsg.replies[0]) {
367 newStart = i+1;
368 memcpy(crepl->replies, xmsg.replies, sizeof(UMSGID) * MAX_REPLY);
369 crepl->replyToPos = xmsg.replyto;
370 for (j=0; j < MAX_REPLY && xmsg.replies[j]; j++);
371 crepl->freeReply = j;
372 }
373 }
374 }
375
376 MsgCloseMsg(hmsg);
377 }
378 }
379
380 /* Pass 2: building relations tree, & filling tree IDs */
381 if ( loglevel >= 11 ) {
382 if (linkNew)
383 w_log(LL_LINKPASS, "Pass 2: building relations for %ld messages, new from %ld", (long) i-1, (long) newStart);
384 else
385 w_log(LL_LINKPASS, "Pass 2: building relations for %ld messages", (long) i-1);
386 }
387
388 for (i = 1, crepl=replmap; i < highMsg; i++, crepl++) {
389 if (
390 crepl -> replyId ||
391 crepl -> msgId ||
392 crepl -> subject
393 ) {
394
395 replDone = 0;
396
397 j=i+1;
398 srepl=crepl+1;
399 if (newStart > j) {
400 j=newStart;
401 srepl = &(replmap[j-1]);
402 }
403 for (; j <= highMsg && !replDone; j++, srepl++ ) {
404
405 replFound = 0;
406
407 if (!replFound &&
408 (crepl -> msgId) && (srepl -> replyId) &&
409 cmpMsgIdReply (crepl -> msgId, srepl -> replyId) == 0 ) {
410
411 replFound++;
412 links_msgid++;
413
414 if ( ! crepl -> treeId ) { /* *crepl isn't linked */
415 if (srepl -> treeId ) { /* *srepl linked already */
416 crepl -> treeId = srepl -> treeId;
417 } else {
418 crepl -> treeId = i; /* top of new tree */
419 }
420 }
421 srepl -> treeId = crepl -> treeId;
422
423 if (singleRepl) {
424 treeLinks++;
425 } else {
426 linkMsgs ( crepl, srepl, i, j, replmap );
427 }
428 }
429
430 if ( !replFound &&
431 (crepl -> treeId == 0 || srepl -> treeId == 0) &&
432 crepl -> replyId && srepl -> replyId) {
433 if ( cmpMsgIdReply (crepl -> replyId, srepl -> replyId) == 0 &&
434 strcmp(crepl -> replyId, " ffffffff")) {
435
436 replFound++;
437 links_replid++;
438
439 if ( ! crepl -> treeId ) { /* *crepl isn't linked */
440 if (srepl -> treeId ) { /* *srepl linked already */
441 crepl -> treeId = srepl -> treeId;
442 } else {
443 crepl -> treeId = i; /* top of new tree */
444 }
445 }
446 srepl -> treeId = crepl -> treeId;
447
448 treeLinks++;
449 }
450 }
451
452 if (!replFound && (srepl -> msgId) && (crepl -> replyId)) {
453 if ( cmpMsgIdReply (srepl -> msgId, crepl -> replyId) == 0 ) {
454 replFound++;
455 links_revmsgid++;
456
457 if ( ! crepl -> treeId ) { /* *crepl isn't linked */
458 if (srepl -> treeId ) { /* *srepl linked already */
459 crepl -> treeId = srepl -> treeId;
460 } else {
461 crepl -> treeId = i; /* top of new tree */
462 }
463 }
464 srepl -> treeId = crepl -> treeId;
465
466 if (singleRepl) {
467 treeLinks++;
468 } else {
469 linkMsgs ( srepl, crepl, j, i, replmap );
470 }
471 }
472 }
473
474 if ( !replFound &&
475 (srepl -> treeId == 0) &&
476 crepl -> subject && srepl -> subject ) {
477
478 if ( strcmp ( crepl -> subject, srepl -> subject ) == 0 ) {
479
480 replFound++;
481 links_subj++;
482
483 if ( ! crepl -> treeId ) { /* *crepl isn't linked */
484 if (srepl -> treeId ) { /* *srepl linked already */
485 crepl -> treeId = srepl -> treeId;
486 } else {
487 crepl -> treeId = i; /* top of new tree */
488 }
489 }
490 srepl -> treeId = crepl -> treeId;
491
492 treeLinks++;
493
494 }
495 }
496
497 if (replFound && singleRepl && !hardSearch ) replDone++;
498
499 }
500 }
501 }
502
503 /* Pass 3: finding unlinked messages with filled tree IDs, and link
504 * them to the tree where possible
505 */
506 w_log(LL_LINKPASS, "Pass 3: buildng relations by treeIds");
507
508 for (i = 1, crepl=replmap; i <= highMsg && treeLinks; i++, crepl++) {
509 if ( crepl->replyToPos == 0 && crepl->freeReply == 0 &&
510 crepl->treeId && i != crepl->treeId ) {
511 /* Link unlinked message */
512
513 linkTo = (replmap[crepl -> treeId -1 ]).treeId;
514 if (linkTo > highMsg || linkTo <= 0 ) {
515 w_log(LL_CRIT,"Programming error 1 while linking linkTo=%ld", (long)linkTo);
516 closeLog();
517 disposeConfig(config);
518 exit(EX_SOFTWARE);
519 }
520
521 if (maxreply == MAX_REPLY) { /* Find place to put link for Squish */
522 while ( (replmap[linkTo-1]).freeReply >= maxreply) {
523 linkTo = MsgUidToMsgn(harea,(replmap[linkTo-1]).replies[0], UID_EXACT );
524 if (linkTo > highMsg || linkTo <= 0 ) {
525 w_log(LL_CRIT,"Programming error 2 while linking linkTo=%ld", (long)linkTo);
526 closeLog();
527 disposeConfig(config);
528 exit(EX_SOFTWARE);
529 }
530 }
531 }
532 linkMsgs ( &(replmap[linkTo-1]), crepl, linkTo, i , replmap );
533 (replmap[crepl -> treeId - 1]).treeId = i; /* where to link next message */
534 treeLinks--;
535 }
536 }
537
538
539 /* Pass 4: write information back to msgbase */
540 w_log(LL_LINKPASS, "Pass 4: writing");
541
542 for (i = 1, crepl=replmap, linksptr=links; i <= highMsg; i++, crepl++, linksptr++) {
543
544 if (area->msgbType & MSGTYPE_JAM || area->msgbType & MSGTYPE_SDM) {
545
546 if( (linksptr->replyToPos != crepl->replyToPos) ||
547 (linksptr->reply1st != crepl->reply1st) ||
548 (linksptr->replyNxt != crepl->replyNxt) ) {
549
550 hmsg = MsgOpenMsg(harea, MOPEN_RW, i);
551
552 if (hmsg) {
553
554 MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL);
555 xmsg.replyto = crepl->replyToPos;
556 xmsg.xmreply1st = crepl->reply1st;
557 xmsg.xmreplynext = crepl->replyNxt;
558 if( 0!=MsgWriteMsg(hmsg, 0, &xmsg, NULL, 0, 0, 0, NULL) )
559 w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
560 MsgCloseMsg(hmsg);
561 }
562 }
563
564 } else { /* Not Jam */
565
566 if ((linksptr->replyToPos != crepl->replyToPos) ||
567 memcmp(linksptr->replies, crepl->replies, sizeof(UMSGID) * maxreply)) {
568
569 hmsg = MsgOpenMsg(harea, MOPEN_RW, i);
570
571 if (hmsg) {
572
573 MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL);
574 memcpy(xmsg.replies, crepl->replies, sizeof(UMSGID) * maxreply);
575 xmsg.replyto = crepl->replyToPos;
576 if( 0!=MsgWriteMsg(hmsg, 0, &xmsg, NULL, 0, 0, 0, NULL) )
577 w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
578 MsgCloseMsg(hmsg);
579 }
580 }
581 }
582
583 if(crepl -> replyId) nfree(crepl -> replyId);
584 if(crepl -> subject) nfree(crepl -> subject);
585 if(crepl -> msgId ) nfree(crepl -> msgId );
586 }
587
588 MsgCloseArea(harea);
589
590 nfree(ctl);
591 nfree(replmap);
592 nfree(links);
593
594 w_log( LL_LINKING, "Linking area \"%s\" done", area->areaName);
595 } else {
596 w_log( LL_ERR, "Could not open area %s", area->areaName);
597 }
598 }
599
usage(void)600 void usage(void) {
601
602 printf( "Usage: hptlink [options] [areaname ...]\n"
603 "Options: -t\t- build reply TREE\n"
604 "\t -s\t- do not use Subject\n"
605 "\t -a\t- search in all messages (for singlethread only)\n"
606 "\t -r\t- do not use REPLY:/MSGID:\n"
607 "\t -n\t- link with 'new' messages only ('new' from last linked + 1)\n"
608 );
609 }
610
main(int argc,char ** argv)611 int main(int argc, char **argv) {
612
613 unsigned int i;
614 int j;
615 struct _minf m;
616 char **argareas=NULL;
617 char *line=NULL;
618 int nareas=0;
619 int found;
620 FILE *f;
621 s_area *area;
622
623 setvar("module", "hpt");
624 xscatprintf(&line, "%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
625 setvar("version", line);
626 nfree(line);
627 SetAppModule(M_HPT);
628
629 versionStr = GenVersionStr( "hptlink", VER_MAJOR, VER_MINOR, VER_PATCH,
630 VER_BRANCH, cvs_date );
631
632 printf("%s\n\n", versionStr);
633
634 for (j=1; j<argc; j++) {
635 if ( argv[j][0] == '-' ) {
636 switch (argv[j][1])
637 {
638 case 't': /* Tree mode */
639 case 'T':
640 singleRepl = 0;
641 break;
642
643 case 's': /* do NOT use Subject field */
644 case 'S':
645 useSubj = 0;
646 break;
647 case 'a': /* search in all messages */
648 case 'A':
649 hardSearch = 1;
650 break;
651 case 'r': /* do NOT use REPLY:/MSGID: fields */
652 case 'R':
653 useReplyId = 0;
654 break;
655 case 'l':
656 case 'L':
657 break; /* obsolete */
658 case 'n': /* link with 'new' messages only */
659 case 'N':
660 linkNew = 1;
661 break;
662 default:
663 usage();
664 exit(EX_USAGE);
665 }
666 } else {
667 /* AreaName(s) specified by args */
668 nareas++;
669 argareas = (char **)srealloc ( argareas, nareas*sizeof(char *));
670 argareas[nareas-1] = argv[j];
671 }
672 }
673
674 config = readConfig(NULL);
675
676 if (!config) {
677 fprintf(stderr, "Could not read fido config!\n");
678 return (1);
679 }
680
681 if (config->logFileDir) {
682 xstrscat(&line, config->logFileDir, LOGFILENAME, NULLP);
683 initLog(config->logFileDir, config->logEchoToScreen, config->loglevels, config->screenloglevels);
684 hptlink_log = openLog(line, versionStr);
685 nfree(line);
686 }
687
688 w_log(LL_PRG, "%s", versionStr);
689
690 m.req_version = 0;
691 m.def_zone = (UINT16) config->addr[0].zone;
692 if (MsgOpenApi(&m)!= 0) {
693 w_log(LL_CRIT, "MsgOpenApi Error.");
694 closeLog();
695 disposeConfig(config);
696 exit(EX_SOFTWARE);
697 }
698
699 if ( argareas )
700 {
701 /* link only specified areas */
702 w_log(LL_LINKING, "Link areas specified by args");
703
704 for ( j=0; j<nareas; j++) {
705
706 found=0;
707
708 /* EchoAreas */
709 for (i=0, area=config->echoAreas;
710 i < config->echoAreaCount && !found;
711 i++, area++) {
712 if (stricmp(area->areaName, argareas[j])==0){
713 if (!area->scn) {
714 linkArea(area);
715 area->scn=1;
716 }
717 found++;
718 }
719 }
720
721 /* Local Areas */
722 for (i=0, area=config->localAreas;
723 i < config->localAreaCount && !found;
724 i++, area++) {
725 if (stricmp(area->areaName, argareas[j])==0){
726 if (!area->scn) {
727 linkArea(area);
728 area->scn=1;
729 }
730 found++;
731 }
732 }
733
734 /* NetMail areas */
735 for (i=0, area=config->netMailAreas;
736 i < config->netMailAreaCount && !found;
737 i++, area++) {
738 if (stricmp(area->areaName, argareas[j])==0){
739 if (!area->scn) {
740 linkArea(area);
741 area->scn=1;
742 }
743 found++;
744 }
745 }
746
747 if(!found) w_log(LL_WARN, "Couldn't find area \"%s\"", argareas[j]);
748 }
749
750 } else {
751
752 if (config->LinkWithImportlog != lwiNo){
753 f = fopen(config->importlog, "r");
754 } else {
755 f = NULL;
756 }
757
758 if ( f ) {
759 w_log(LL_INFO, "Using importlogfile -> linking only listed Areas");
760 while (!feof(f)) {
761 line = readLine(f);
762
763 if (line) {
764
765 found=0;
766 /* EchoAreas */
767 for (i=0, area=config->echoAreas;
768 i < config->echoAreaCount && !found;
769 i++, area++) {
770 if (stricmp(area->areaName, line)==0){
771 if (!area->scn) {
772 linkArea(area);
773 area->scn=1;
774 }
775 found++;
776 }
777 }
778 /* Local Areas */
779 for (i=0, area=config->localAreas;
780 i < config->localAreaCount && !found;
781 i++, area++) {
782 if (stricmp(area->areaName, line)==0){
783 if (!area->scn) {
784 linkArea(area);
785 area->scn=1;
786 }
787 found++;
788 }
789 }
790
791 /* NetMail areas */
792 for (i=0, area=config->netMailAreas;
793 i < config->netMailAreaCount && !found;
794 i++, area++) {
795 if (stricmp(area->areaName, line)==0){
796 if (!area->scn) {
797 linkArea(area);
798 area->scn=1;
799 }
800 found++;
801 }
802 }
803
804 if(!found) w_log(LL_ERR, "Couldn't find area \"%s\"", line);
805 nfree(line);
806 }
807
808 }
809 fclose(f);
810 if (config->LinkWithImportlog == lwiKill) remove(config->importlog);
811 } else {
812 /* importlog does not exist link all areas */
813 w_log(LL_INFO, "No ImportLog file, linking all Areas");
814
815 /* NetMails */
816 for (i = 0; i < config -> netMailAreaCount; i++)
817 linkArea (&(config->netMailAreas[i]));
818
819 /* EchoAreas */
820 for (i=0; i < config->echoAreaCount; i++) linkArea(&(config->echoAreas[i]));
821
822 /* Local Areas */
823 for (i=0; i < config->localAreaCount; i++) linkArea(&(config->localAreas[i]));
824 }
825 }
826
827 w_log(LL_STAT, "Linked by msgid/reply: %ld, replid: %ld, subj: %ld, revmsgid: %ld", (long)links_msgid, (long)links_replid, (long)links_subj, (long)links_revmsgid);
828 if (links_ignored)
829 w_log(LL_SUMMARY, "Linked total: %ld, Ignored: %ld", (long) links_total, (long) links_ignored);
830 else
831 w_log(LL_SUMMARY, "Linked total: %ld", (long) links_total);
832
833 w_log(LL_STOP, "Done");
834
835 MsgCloseApi();
836 closeLog();
837 disposeConfig(config);
838 return (0);
839 }
840