1 /*****************************************************************************
2  * HPT --- FTN NetMail/EchoMail Tosser
3  *****************************************************************************
4  * Copyright (C) 1997-1999
5  *
6  * Matthias Tichy
7  *
8  * Fido:     2:2433/1245 2:2433/1247 2:2432/605.14
9  * Internet: mtt@tichy.de
10  *
11  * Grimmestr. 12         Buchholzer Weg 4
12  * 33098 Paderborn       40472 Duesseldorf
13  * Germany               Germany
14  *
15  * Copyright (c) 1999-2001
16  * Max Levenkov, sackett@mail.ru
17  *
18  * This file is part of HPT.
19  *
20  * HPT is free software; you can redistribute it and/or modify it
21  * under the terms of the GNU General Public License as published by the
22  * Free Software Foundation; either version 2, or (at your option) any
23  * later version.
24  *
25  * HPT is distributed in the hope that it will be useful, but
26  * WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28  * General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with HPT; see the file COPYING.  If not, write to the Free
32  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
33  *****************************************************************************
34  * $Id$
35  */
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <ctype.h>
43 
44 /* compiler.h */
45 #include <huskylib/compiler.h>
46 /* huskylib */
47 #include <huskylib/huskylib.h>
48 
49 
50 #ifdef HAS_PROCESS_H
51 #  include <process.h>
52 #endif
53 
54 #ifdef HAS_UNISTD_H
55 #include <unistd.h>
56 #endif
57 
58 #ifdef HAS_IO_H
59 #include <io.h>
60 #endif
61 
62 /* smapi */
63 #include <smapi/msgapi.h>
64 
65 /* fidoconf */
66 #include <fidoconf/fidoconf.h>
67 #include <fidoconf/common.h>
68 #include <huskylib/xstr.h>
69 #include <fidoconf/afixcmd.h>
70 #include <huskylib/temp.h>
71 #include <huskylib/recode.h>
72 #include <huskylib/log.h>
73 
74 #include <areafix/areafix.h>
75 
76 /* hpt */
77 #include <fcommon.h>
78 #include <pkt.h>
79 #include <scan.h>
80 #include <global.h>
81 #include "version.h"
82 #include <toss.h>
83 
84 #ifdef DO_PERL
85 #include <hptperl.h>
86 #endif
87 
88 s_statScan statScan;
89 
convertMsgHeader(XMSG xmsg,s_message * msg)90 void convertMsgHeader(XMSG xmsg, s_message *msg)
91 {
92    /*  convert header */
93    msg->attributes  = xmsg.attr;
94 
95    msg->origAddr.zone  = xmsg.orig.zone;
96    msg->origAddr.net   = xmsg.orig.net;
97    msg->origAddr.node  = xmsg.orig.node;
98    msg->origAddr.point = xmsg.orig.point;
99 
100    msg->destAddr.zone  = xmsg.dest.zone;
101    msg->destAddr.net   = xmsg.dest.net;
102    msg->destAddr.node  = xmsg.dest.node;
103    msg->destAddr.point = xmsg.dest.point;
104 
105    strcpy((char *)msg->datetime, (char *) xmsg.__ftsc_date);
106    xstrcat(&(msg->subjectLine), (char *) xmsg.subj);
107    xstrcat(&(msg->toUserName), (char *) xmsg.to);
108    xstrcat(&(msg->fromUserName), (char *) xmsg.from);
109 
110    /*  recoding subjectLine to TransportCharset */
111    if ((config->recodeMsgBase) && (config->outtab != NULL)) {
112        recodeToTransportCharset((char*)msg->subjectLine);
113        recodeToTransportCharset((char*)msg->fromUserName);
114        recodeToTransportCharset((char*)msg->toUserName);
115    }
116 
117    /*  set netmail flag */
118    msg->netMail = 1;
119 }
120 
convertMsgText(HMSG SQmsg,s_message * msg)121 void convertMsgText(HMSG SQmsg, s_message *msg)
122 {
123    UCHAR   *ctrlBuff;
124    UINT32  ctrlLen;
125 
126    /*  get kludge lines */
127    ctrlLen = MsgGetCtrlLen(SQmsg);
128    ctrlBuff = (unsigned char *) safe_malloc(ctrlLen+1);
129    MsgReadMsg(SQmsg, NULL, 0, 0, NULL, ctrlLen, ctrlBuff);
130    /* MsgReadMsg does not do zero termination! */
131    ctrlBuff[ctrlLen] = '\0';
132    msg->text = (char *) CvtCtrlToKludge(ctrlBuff);
133    nfree(ctrlBuff);
134 
135    /*  make text */
136    msg->textLength = MsgGetTextLen(SQmsg); /*  including zero termination??? */
137 
138    ctrlLen = strlen(msg->text);
139    xstralloc(&(msg->text), msg->textLength + ctrlLen);
140 
141    MsgReadMsg(SQmsg, NULL, 0, msg->textLength, (UCHAR *) msg->text+ctrlLen, 0, NULL);
142    /* MsgReadMsg doesn't do zero termination! */
143    msg->text[msg->textLength+ctrlLen] = '\0';
144    msg->textLength += ctrlLen-1;
145 
146    /*  recoding text to TransportCharSet */
147    if ((config->recodeMsgBase) && (config->outtab != NULL)) recodeToTransportCharset((char*)msg->text);
148 }
149 
addViaToMsg(s_message * msg,hs_addr ourAka)150 void addViaToMsg(s_message *msg, hs_addr ourAka) {
151 	time_t  tm;
152 	struct tm *dt;
153         char buf[2];
154 
155 #ifdef DO_PERL
156 	if (skip_addvia) return;
157 #endif
158 
159 	time(&tm);
160 	dt = gmtime(&tm);
161 
162         /*
163          * OG: If the last char of the message isn't a \r, so it is a good
164 	 * idea to add the \r.
165         */
166         buf[0] = buf[1] = 0;
167         if (msg->text && msg->text[0])
168         {
169           if (msg->text[strlen(msg->text)-1] != '\r')
170              buf[0] = '\r';
171         }
172 
173 	if (ourAka.point==0)
174 	xscatprintf(&(msg->text),"%s\001Via %u:%u/%u @%04u%02u%02u.%02u%02u%02u.UTC %s\r",
175 				buf, ourAka.zone, ourAka.net, ourAka.node,
176 				dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
177 				dt->tm_hour, dt->tm_min, dt->tm_sec, versionStr);
178 	else
179 	xscatprintf(&(msg->text),"%s\001Via %u:%u/%u.%u @%04u%02u%02u.%02u%02u%02u.UTC %s\r",
180 				buf, ourAka.zone, ourAka.net, ourAka.node, ourAka.point,
181 				dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
182 				dt->tm_hour, dt->tm_min, dt->tm_sec, versionStr);
183 }
184 
makePktHeader(s_link * link,s_pktHeader * header)185 void makePktHeader(s_link *link, s_pktHeader *header)
186 {
187    if (link != NULL) {
188       header->origAddr = *(link->ourAka);
189       header->destAddr = link->hisAka;
190    }
191    header->minorProductRev = (UCHAR)VER_MINOR;
192    header->majorProductRev = (UCHAR)VER_MAJOR;
193    header->hiProductCode   = 0;
194    header->loProductCode   = 0xfe;
195    memset(header->pktPassword, '\0', sizeof(header->pktPassword)); /*  no password */
196    if (link != NULL && link->pktPwd != NULL) {
197       if (strlen(link->pktPwd) > 8)
198          strncpy(header->pktPassword, link->pktPwd, 8);
199       else
200          strcpy(header->pktPassword, link->pktPwd);
201    }
202    time(&(header->pktCreated));
203    header->capabilityWord  = 1;
204    header->prodData        = 0;
205 }
206 
findSelfRouteForNetmail(s_message * msg)207 static s_route *findSelfRouteForNetmail(s_message *msg)
208 {
209     char *addrStr=NULL;
210     UINT i;
211 
212     xscatprintf(&addrStr, "%u:%u/%u.%u",
213 		msg->destAddr.zone, msg->destAddr.net,
214 		msg->destAddr.node, msg->destAddr.point);
215 
216     for (i=0; i < config->routeCount; i++) {
217 	if ((msg->attributes & MSGFILE) == MSGFILE) { /*  routeFile */
218 	    if (config->route[i].id == id_routeFile)
219 		if (patmat(addrStr, config->route[i].pattern))
220 		    break;
221 	} else {
222 	    if (config->route[i].id != id_routeFile) /*  route & routeMail */
223 		if (patmat(addrStr, config->route[i].pattern))
224 		    break;
225 	}
226     }
227 
228     nfree(addrStr);
229 
230     return (i==config->routeCount) ? NULL : &(config->route[i]);
231 }
232 
findRouteForNetmail(s_message * msg)233 s_route *findRouteForNetmail(s_message *msg)
234 {
235 	s_route *route;
236 
237 	route = findSelfRouteForNetmail(msg);
238 
239 #ifdef DO_PERL
240 	{ s_route *sroute;
241 	  if ((sroute = perlroute(msg, route)) != NULL)
242 		return sroute;
243 	}
244 #endif
245 
246 	return route;
247 }
248 
getLinkForRoute(s_route * route,s_message * msg)249 s_link *getLinkForRoute(s_route *route, s_message *msg) {
250    static s_link tempLink;
251    s_link *getLink = NULL;
252 
253    if (route==NULL) return NULL;
254 
255    if (route->target == NULL) {
256       memset(&tempLink, '\0', sizeof(s_link));
257 
258       tempLink.hisAka = msg->destAddr;
259       tempLink.ourAka = &(config->addr[0]);
260 
261       switch (route->routeVia) {
262 
263 	  case route_zero:
264 		  break;
265 
266 	  case host:
267 		  tempLink.hisAka.node  = 0;
268 		  tempLink.hisAka.point = 0;
269 		  break;
270 
271 	  case boss:
272 		  tempLink.hisAka.point = 0;
273 		  break;
274 
275 	  case noroute:
276 		  break;
277 
278 	  case nopack:
279 		  break;
280 
281 	  case hub:
282 		  tempLink.hisAka.node -= (tempLink.hisAka.node % 100);
283 		  tempLink.hisAka.point = 0;
284 		  break;
285 
286 	  case route_extern:
287 		  parseFtnAddrZS(route->viaStr, &tempLink.hisAka);
288 		  break;
289       }
290 
291       getLink = getLinkFromAddr(config, tempLink.hisAka);
292 
293       if (getLink != NULL) return getLink;
294       else return &tempLink;
295 
296    } else return route->target;
297 }
298 
processAttachs(s_link * link,s_message * msg,unsigned int attr)299 void processAttachs(s_link *link, s_message *msg, unsigned int attr)
300 {
301    FILE *flo = NULL;
302    char **outbounds[4];
303    char *p = NULL, *running = NULL, *token = NULL, *flags = NULL;
304    char *newSubjectLine = NULL;
305    int i, def = -1, replace = 0;
306    char *path = NULL;
307 
308    /* init outbounds */
309    outbounds[0] = &tossDir;
310    outbounds[1] = &config->protInbound;
311    outbounds[2] = &config->inbound;
312    outbounds[3] = NULL;
313    for (i=3; i>=0; i--) if (outbounds[i] && *outbounds[i]) { def=i; break; }
314    flo = fopen(link->floFile, "a");
315 
316    xstrcat(&running, msg->subjectLine);
317 
318    while ((token = strseparate(&running, ", \t")) != NULL) {
319       if (newSubjectLine!=NULL) xstrcat(&newSubjectLine, " ");
320 /* val: try to find file in inbounds if there are no path delimiter
321         if _there is_ a delimeter, then message is local so don't change it
322 */
323       if ((p = strrchr(token, PATH_DELIM)) == NULL) {
324     	    xstrcat(&newSubjectLine, token);
325             path = NULL;
326             for (i=0; i<4; i++) {
327 		if (path != NULL) nfree(path);
328 		if (outbounds[i] && *outbounds[i]) {
329                     if (def < 0) def = i;
330                     xscatprintf(&path, "%s%s", *outbounds[i], token);
331 		    if (fexist(path)) break;
332 #ifdef __UNIX__
333                     /*strLower(path + strlen(*outbounds[i]));*/
334 		    adaptcase(path);
335 		    if (fexist(path)) break;
336 #endif
337                 }
338     	    }
339             if (path == NULL) {
340                 if (def < 0) continue; /* file not found; no outbounds */
341                 else xscatprintf(&path, "%s%s", *outbounds[def], token);
342             }
343             token = path;
344       }
345       else {
346             replace = 1;
347     	    xstrcat(&newSubjectLine, p+1);
348 #ifdef __UNIX__
349             /*if (!fexist(token)) strLower(token);*/
350             if (!fexist(token)) adaptcase(token);
351 #endif
352       }
353       if (flo != NULL) {
354 	  if (msg->text) flags =
355              (char *) GetCtrlToken((byte *)msg->text,(byte *)"FLAGS");
356           if ((flags && strstr(flags, "KFS")) ||
357 	      (config->keepTrsFiles==0 && (attr & MSGFWD)==MSGFWD))
358 	      fprintf(flo, "^%s\n", token);
359           else if (flags && strstr(flags, "TFS"))
360 	      fprintf(flo, "#%s\n", token);
361           else
362 	      fprintf(flo, "%s\n", token);
363 	  nfree(flags);
364       }
365    }
366 
367    if (flo!= NULL) {
368       fclose(flo);
369    } else w_log(LL_ERR, "Could not open FloFile");
370 
371    /*  replace subjectLine */
372    if (replace) {
373       nfree(msg->subjectLine);
374       msg->subjectLine = newSubjectLine;
375    }
376    else nfree(newSubjectLine);
377 }
378 
processRequests(s_link * link,s_message * msg)379 void processRequests(s_link *link, s_message *msg)
380 {
381    FILE *flo = NULL;
382    char *running = NULL;
383    char *token = NULL;
384 
385    flo = fopen(link->floFile, "ab");
386 
387    running = msg->subjectLine;
388    token = strseparate(&running, " \t");
389 
390    while (token != NULL) {
391      if (flo != NULL) fprintf(flo, "%s\015\012", token); /*  #13#10 to create dos LFCR which ends a line */
392 
393       token = strseparate(&running, " \t");
394    }
395    if (flo!= NULL) {
396       fclose(flo);
397    } else w_log(LL_ERR, "Could not open FloFile");
398 
399 }
400 
packMsg(HMSG SQmsg,XMSG * xmsg,s_area * area)401 int packMsg(HMSG SQmsg, XMSG *xmsg, s_area *area)
402 {
403    FILE        *pkt = NULL;
404    e_flavour   prio = flNormal;
405    s_message   msg;
406    s_pktHeader header;
407    s_route     *route = NULL;
408    s_link      *link = NULL, *virtualLink = NULL;
409    char        freeVirtualLink = 0;
410    char        *flags=NULL;
411    int         r, arcNetmail;
412 
413    w_log( LL_FUNC, "packMsg() begin");
414 
415    memset(&msg,'\0',sizeof(s_message));
416    convertMsgHeader(*xmsg, &msg);
417    convertMsgText(SQmsg, &msg);
418 
419    w_log(LL_DEBUGB, "%s::%u Msg from %u:%u/%u.%u to %u:%u/%u.%u",__FILE__,__LINE__, msg.origAddr.zone, msg.origAddr.net, msg.origAddr.node, msg.origAddr.point, msg.destAddr.zone, msg.destAddr.net, msg.destAddr.node, msg.destAddr.point );
420 
421 #ifdef DO_PERL
422    r = perlscanmsg(area->areaName, &msg);
423    if (r & 0x80) xmsg->attr |= (MSGKILL | MSGSENT);
424    if (r & 0x0f) {
425 	/* val:? xmsg->attr |= MSGSENT; */
426 	freeMsgBuffers(&msg);
427         w_log( LL_FUNC, "packMsg() end: perl hook proceed");
428 	return 0;
429    }
430 #endif
431    /*  clear trs, local & k/s flags */
432    msg.attributes &= ~(MSGFWD|MSGLOCAL|MSGKILL);
433 
434    /*  prepare virtual link... */
435    virtualLink = getLinkFromAddr(config, msg.destAddr);  /* maybe the link is in config? */
436    if (virtualLink == NULL) {
437       virtualLink = safe_malloc(sizeof(s_link));  /*  if not create new virtualLink link */
438       memset(virtualLink, '\0', sizeof(s_link));
439       virtualLink->hisAka = msg.destAddr;
440       virtualLink->ourAka = config->addr;
441       virtualLink->name = (char *) safe_malloc(strlen(msg.toUserName)+1);
442       strcpy(virtualLink->name, msg.toUserName);
443       freeVirtualLink = 1;  /* virtualLink is a temporary link, please free it.. */
444    }
445 
446    /*  calculate prio */
447    if ((xmsg->attr & MSGCRASH)==MSGCRASH) prio = flCrash;
448    if ((xmsg->attr & MSGHOLD)==MSGHOLD) prio = flHold;
449    if ((xmsg->attr & MSGXX2)==MSGXX2 ||
450 	   ((xmsg->attr & MSGHOLD)==MSGHOLD &&
451 		(xmsg->attr & MSGCRASH)==MSGCRASH)) prio = flDirect; /*  XX2 or Crash+Hold */
452    if (msg.text) {
453 	   flags = (char *) GetCtrlToken((byte *)msg.text,(byte *)"FLAGS");
454 	   if (flags) {
455 		   if (strstr(flags,"DIR")!=NULL) prio = flDirect;
456 		   if (strstr(flags,"IMM")!=NULL) prio = flImmediate; /*  most priority */
457 		   nfree(flags);
458 	   }
459    }
460 
461    if ((xmsg->attr & MSGFILE) == MSGFILE) {
462        /*  file attach */
463 
464        /*  we need route mail */
465        if (prio==flNormal) {
466 	   route = findRouteForNetmail(&msg);
467 	   link = getLinkForRoute(route, &msg);
468 	   if ((route != NULL) && (link != NULL) &&
469 	       (route->routeVia != nopack)) {
470 	       if (createOutboundFileName(link,route->flavour,
471 					  FLOFILE) == 0) {
472 		   processAttachs(link, &msg, xmsg->attr);
473 		   remove(link->bsyFile);
474 		   nfree(link->bsyFile);
475 		   /*  mark Mail as sent */
476 		   xmsg->attr |= MSGSENT;
477 		   if (0!=MsgWriteMsg(SQmsg, 0, xmsg, NULL, 0, 0, 0, NULL))
478                         w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
479 		   nfree(link->floFile);
480 /*		   w_log(LL_FROUTE, "File %s from %u:%u/%u.%u -> %u:%u/%u.%u via %u:%u/%u.%u", msg.subjectLine, msg.origAddr.zone, msg.origAddr.net, msg.origAddr.node, msg.origAddr.point, msg.destAddr.zone, msg.destAddr.net, msg.destAddr.node, msg.destAddr.point, link->hisAka.zone, link->hisAka.net, link->hisAka.node, link->hisAka.point);
481 */
482            { char* strorigaddr=aka2str5d(msg.origAddr);
483              char* strdestaddr=aka2str5d(msg.destAddr);
484              char* strviaaddr=aka2str5d(link->hisAka);
485              w_log(LL_FROUTE, "File %s: %s -> %s routed via %s", msg.subjectLine, strorigaddr, strdestaddr, strviaaddr);
486              nfree(strorigaddr);
487              nfree(strdestaddr);
488              nfree(strviaaddr);
489            }
490 	       }
491 	   }
492        }
493 	   else if (createOutboundFileName(virtualLink, prio, FLOFILE) == 0) {
494 		   processAttachs(virtualLink, &msg, xmsg->attr);
495 		   remove(virtualLink->bsyFile);
496 		   nfree(virtualLink->bsyFile);
497 		   /*  mark Mail as sent */
498 		   xmsg->attr |= MSGSENT;
499 		   if (0!=MsgWriteMsg(SQmsg, 0, xmsg, NULL, 0, 0, 0, NULL))
500                         w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
501 		   nfree(virtualLink->floFile);
502 /*		   w_log(LL_FROUTE, "File %s from %u:%u/%u.%u -> %u:%u/%u.%u", msg.subjectLine, msg.origAddr.zone, msg.origAddr.net, msg.origAddr.node, msg.origAddr.point, msg.destAddr.zone, msg.destAddr.net, msg.destAddr.node, msg.destAddr.point);
503 */
504            { char* strorigaddr=aka2str5d(msg.origAddr);
505              char* strdestaddr=aka2str5d(msg.destAddr);
506              w_log(LL_FROUTE, "File %s: %s -> %s", msg.subjectLine, strorigaddr, strdestaddr);
507              nfree(strorigaddr);
508              nfree(strdestaddr);
509            }
510 	   }
511    } /* endif file attach */
512 
513    /*  file requests always direct */
514    if ((xmsg->attr & MSGFRQ) == MSGFRQ) {
515 	   /*  if msg has request flag then put the subjectline into request file. */
516 	   if (createOutboundFileName(virtualLink, flNormal, REQUEST) == 0) {
517 		   processRequests(virtualLink, &msg);
518 		   remove(virtualLink->bsyFile);
519 		   nfree(virtualLink->bsyFile);
520 		   /*  mark Mail as sent */
521 		   xmsg->attr |= MSGSENT;
522 		   if (0!=MsgWriteMsg(SQmsg, 0, xmsg, NULL, 0, 0, 0, NULL))
523                         w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
524 		   nfree(virtualLink->floFile);
525            { char* strdestaddr=aka2str5d(msg.destAddr);
526              w_log(LL_FREQ, "File-request %s from %s", msg.subjectLine, strdestaddr);
527              nfree(strdestaddr);
528            }
529 	   }
530    }
531 
532    w_log(LL_DEBUGB, "%s::%u Msg from %u:%u/%u.%u to %u:%u/%u.%u",__FILE__,__LINE__, msg.origAddr.zone, msg.origAddr.net, msg.origAddr.node, msg.origAddr.point, msg.destAddr.zone, msg.destAddr.net, msg.destAddr.node, msg.destAddr.point );
533 
534    /*  no route */
535    if (prio!=flNormal || (xmsg->attr & MSGFRQ)==MSGFRQ) {
536 	   /*  direct, crash, immediate, hold messages */
537            if (virtualLink->arcNetmail &&
538                prio == virtualLink->echoMailFlavour) {
539                    arcNetmail = 1;
540                    if (virtualLink->pktFile && virtualLink->pktSize)
541                         if (fsize(virtualLink->pktFile) >= (long)(virtualLink->pktSize*1024)) {
542                              nfree(virtualLink->pktFile);
543                              nfree(virtualLink->packFile);
544                         }
545                    if (virtualLink->pktFile == NULL)
546                         r = createTempPktFileName(virtualLink);
547                    else
548                         r = 0;
549            } else {
550                    arcNetmail = 0;
551                    r = createOutboundFileName(virtualLink, prio, PKT);
552            }
553 	   if (r == 0) {
554 		   addViaToMsg(&msg, *(config->addr));
555 		   makePktHeader(virtualLink, &header);
556 		   pkt = openPktForAppending(arcNetmail ? virtualLink->pktFile : virtualLink->floFile, &header);
557 		   writeMsgToPkt(pkt, msg);
558 		   closeCreatedPkt(pkt);
559            { char* strorigaddr=aka2str5d(msg.origAddr);
560              char* strdestaddr=aka2str5d(msg.destAddr);
561              w_log(LL_ROUTE, "Msg packed with flavour '%s': %s -> %s", flv2str(prio), strorigaddr, strdestaddr);
562              nfree(strorigaddr);
563              nfree(strdestaddr);
564            }
565                    if (!arcNetmail) {
566 		         remove(virtualLink->bsyFile);
567 		         nfree(virtualLink->bsyFile);
568 		         nfree(virtualLink->floFile);
569                    }
570 		   /*  mark Mail as sent */
571 		   xmsg->attr |= MSGSENT;
572 		   if (0!=MsgWriteMsg(SQmsg, 0, xmsg, NULL, 0, 0, 0, NULL))
573                         w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
574 	   }
575    } else {
576            /*  no crash, no hold flag -> route netmail */
577            if (route == NULL) {                      /* val: don't call again! */
578 	   	route = findRouteForNetmail(&msg);
579 	   	link = getLinkForRoute(route, &msg);
580            }
581 
582 	   if ((route != NULL) && (link != NULL) && (route->routeVia != nopack)) {
583 		   prio = route->flavour;
584                    if (link->arcNetmail &&
585                        route->flavour == link->echoMailFlavour) {
586                            arcNetmail = 1;
587                            if (link->pktFile && link->pktSize)
588                                 if (fsize(link->pktFile) >= (long)(link->pktSize*1024)) {
589                                      nfree(link->pktFile);
590                                      nfree(link->packFile);
591                                 }
592 
593                            if (link->pktFile == NULL)
594                                 r = createTempPktFileName(link);
595                            else
596                                 r = 0;
597                    } else {
598                            arcNetmail = 0;
599                            r = createOutboundFileName(link, prio, PKT);
600                    }
601 		   if (r == 0) {
602 			   addViaToMsg(&msg, *(link->ourAka));
603 			   makePktHeader(NULL, &header);
604 			   header.destAddr = link->hisAka;
605 			   header.origAddr = *(link->ourAka);
606 			   if (link->pktPwd != NULL)
607 				   strcpy(&(header.pktPassword[0]), link->pktPwd);
608 			   pkt = openPktForAppending(arcNetmail ? link->pktFile : link->floFile, &header);
609 			   writeMsgToPkt(pkt, msg);
610 			   closeCreatedPkt(pkt);
611                { char* strOA=aka2str5d(msg.origAddr);
612                  char* strDA=aka2str5d(msg.destAddr);
613                  char* strVA=aka2str5d(link->hisAka);
614                  w_log(LL_ROUTE, "Msg from %s to %s packed via %s", strOA, strDA, strVA);
615                  nfree(strOA);
616                  nfree(strDA);
617                  nfree(strVA);
618                }
619                            if (!arcNetmail) {
620 			        remove(link->bsyFile);
621 			        nfree(link->bsyFile);
622 			        nfree(link->floFile);
623                            }
624 			   /*  mark Mail as sent */
625 			   xmsg->attr |= MSGSENT;
626 			   if (0!=MsgWriteMsg(SQmsg, 0, xmsg, NULL, 0, 0, 0, NULL))
627                              w_log(LL_ERR, "Could not update msg in area %s! Check the wholeness of messagebase, please.", area->areaName);
628 		   }
629 	   } else {
630                 if ((xmsg->attr & MSGFILE) == MSGFILE) w_log(LL_FROUTE, "no routeFile found or no-pack for %s - leave mail untouched", aka2str(msg.destAddr));
631 		else w_log(LL_ROUTE, "no route found or no-pack for %s - leave mail untouched", aka2str(msg.destAddr));
632 	   }
633    }
634 
635    /*  process carbon copy */
636    if (config->carbonOut) carbonCopy(&msg, xmsg, area);
637 
638    freeMsgBuffers(&msg);
639    if (freeVirtualLink==1) {
640       nfree(virtualLink->name);
641       nfree(virtualLink);
642    }
643 
644    if ((xmsg->attr & MSGSENT) == MSGSENT) {
645       w_log( LL_FUNC, "packMsg() rc=0");
646       return 0;
647    }
648    w_log( LL_FUNC, "packMsg() rc=1");
649    return 1;
650 }
651 
scanNMArea(s_area * area)652 void scanNMArea(s_area *area)
653 {
654    HAREA           netmail;
655    HMSG            msg;
656    dword           highestMsg, i, j;
657    XMSG            xmsg;
658    hs_addr         dest, orig;
659    hs_addr         intl_dest = {0}, intl_orig = {0};
660     char            *ctl;
661     int             ctllen;
662    int             for_us, from_us;
663    FILE            *f = NULL;
664 
665    /*  do not scan one area twice */
666    if (area->scn) return;
667 #ifndef DO_PERL
668    if (config->routeCount == 0) {
669        w_log(LL_ROUTE, "No routing -> Scanning stop");
670 #endif
671        /*  create flag for netmail trackers */
672        if (config->netmailFlag) {
673 	   if (NULL == (f = fopen(config->netmailFlag,"a")))
674 	       w_log(LL_ERR, "Could not create netmail flag: %s", config->netmailFlag);
675 	   else {
676 	       w_log(LL_FLAG, "Created netmail flag: %s", config->netmailFlag);
677 	       fclose(f);
678 	   }
679        }
680 #ifndef DO_PERL
681        return;
682    }
683 #endif
684 
685    netmail = MsgOpenArea((unsigned char *) area -> fileName, MSGAREA_NORMAL,
686                          (word)area -> msgbType);
687    if (netmail != NULL) {
688 
689        statScan.areas++;
690        area->scn++;
691        w_log(LL_START, "Scanning NetmailArea %s", area -> areaName);
692 
693        if (area->msgbType == MSGTYPE_SDM) noHighWaters = 1;
694        i = (noHighWaters) ? 0 : MsgGetHighWater(netmail);
695        highestMsg = MsgGetNumMsg(netmail);
696 
697        /*  scan all Messages and test if they are already sent. */
698        while (i < highestMsg) {
699            char *textforlog = NULL;
700 	   msg = MsgOpenMsg(netmail, MOPEN_RW, ++i);
701 
702 	   /*  msg does not exist */
703 	   if (msg == NULL) continue;
704 	   statScan.msgs++;
705 
706        ctllen = MsgGetCtrlLen(msg);
707        ctl = (char *) safe_malloc(ctllen+1);
708        ctl[ctllen] = '\0';
709 
710        MsgReadMsg(msg, &xmsg, 0, 0, NULL, ctllen, (byte *)ctl);
711        dest = xmsg.dest;
712        orig = xmsg.orig;
713        /*
714         * if @INTL and optionally @TOPT/@FMPT found, take address
715         * from there
716         */
717        memset(&intl_orig, 0, sizeof(intl_orig));
718        memset(&intl_dest, 0, sizeof(intl_dest));
719        /* TODO: use correctNMAddr from pktread.c? */
720        if (parseINTL(ctl, &intl_orig, &intl_dest) & INTL_FOUND)
721        {
722            if (addrComp(orig, intl_orig)) /* addresses are differ */
723            {
724                orig.zone = xmsg.orig.zone = intl_orig.zone;
725                orig.net = xmsg.orig.net = intl_orig.net;
726                orig.node = xmsg.orig.node = intl_orig.node;
727                orig.point = xmsg.orig.point = intl_orig.point;
728            }
729            if (addrComp(dest, intl_dest)) /* addresses are differ */
730            {
731                dest.zone = xmsg.dest.zone = intl_dest.zone;
732                dest.net = xmsg.dest.net = intl_dest.net;
733                dest.node = xmsg.dest.node = intl_dest.node;
734                dest.point = xmsg.dest.point = intl_dest.point;
735            }
736        }
737 
738        nfree(ctl);
739 
740 //       ctl = safe_strdup(aka2str(dest)); /* use this just as temp buffer */
741 //       w_log( LL_DEBUGB, "%s::%u Msg from %s to %s",__FILE__,__LINE__,
742 //             aka2str(orig), ctl);
743 //       nfree(ctl);
744        xscatprintf(&textforlog, "Msg #%d from %s to ", i, aka2str(orig));
745        xstrcat(&textforlog, aka2str(dest));
746        w_log( LL_DEBUGB, "%s::%u %s", __FILE__, __LINE__, textforlog);
747 
748        for_us = 0;
749        for (j=0; j < config->addrCount; j++)
750        {
751            if (addrComp(dest, config->addr[j])==0) {for_us = 1; break;}
752        }
753        /*  if not sent and not for us -> pack it */
754        if (((xmsg.attr & MSGSENT) != MSGSENT) &&
755            ((xmsg.attr & MSGLOCKED) != MSGLOCKED) &&
756            (for_us==0))
757        {
758            if (packMsg(msg, &xmsg, area) == 0) {
759                statScan.exported++;
760                area->scn++;
761            }
762        }
763 
764 	   MsgCloseMsg(msg);
765 
766 	   from_us = 0;
767 	   for (j=0; j < config->addrCount; j++)
768 	       if (addrComp(orig, config->addr[j])==0) {from_us = 1; break;}
769 
770 	   /*   non transit messages without k/s flag not killed */
771 	   if (!(xmsg.attr & MSGKILL) && !(xmsg.attr & MSGFWD)) from_us = 1;
772 
773 	   /*  transit messages from us will be killed */
774 	   if (from_us && (xmsg.attr & MSGFWD)) from_us = 0;
775 
776            if ((!config->keepTrsMail) && ((!for_us && !from_us) ||
777                         (xmsg.attr&MSGKILL)) && (xmsg.attr&MSGSENT)) {
778 	       MsgKillMsg(netmail, i);
779                w_log(LL_NETMAIL,"%s deleted", textforlog);
780 	       i--;
781 	   }
782            nfree(textforlog);
783 
784        } /* endfor */
785 
786        if (noHighWaters==0) MsgSetHighWater(netmail, i);
787        MsgCloseArea(netmail);
788        closeOpenedPkt();
789    } else {
790        w_log(LL_ERR, "Could not open NetmailArea %s", area -> areaName);
791    } /* endif */
792 }
793 
writeScanStatToLog(void)794 void writeScanStatToLog(void) {
795    unsigned i;
796 
797    w_log(LL_STAT, "Statistics");
798    w_log(LL_STAT, "    areas: % 4d   msgs: % 6d", statScan.areas, statScan.msgs);
799    w_log(LL_STAT, "    exported: % 4d", statScan.exported);
800 
801    /* Now write areas summary */
802    w_log(LL_SUMMARY, "Areas summary:");
803    for (i = 0; i < config->netMailAreaCount; i++)
804        if (config->netMailAreas[i].scn > 1)
805 	   w_log(LL_SUMMARY, "netmail area %s - %d msgs",
806 		 config->netMailAreas[i].areaName, config->netMailAreas[i].scn-1);
807    for (i = 0; i < config->echoAreaCount; i++)
808        if (config->echoAreas[i].scn > 1)
809 	   w_log(LL_SUMMARY, "echo area %s - %d msgs",
810 		 config->echoAreas[i].areaName, config->echoAreas[i].scn-1);
811 }
812 
getLocalArea(s_fidoconfig * config,char * areaName)813 s_area *getLocalArea(s_fidoconfig *config, char *areaName)
814 {
815    UINT i;
816 
817    for (i=0; i < config->localAreaCount; i++) {
818       if (stricmp(config->localAreas[i].areaName, areaName)==0)
819          return &(config->localAreas[i]);
820    }
821 
822    return NULL;
823 }
824 
825 
scanByName(char * name,e_scanMode mode)826 int scanByName(char *name, e_scanMode mode) {
827     s_area *area = NULL;
828 
829     if ((area = getNetMailArea(config, name)) != NULL) {
830       /* val: scan mode check */
831       if (area->scanMode == smNever) {
832         w_log(LL_SCANNING, "Area \'%s\': packing is off -> Skipped", name);
833         return 0;
834       }
835       else if (area->scanMode == smManual && mode != smManual) {
836         w_log(LL_SCANNING, "Area \'%s\': manual packing only -> Skipped", name);
837         return 0;
838       }
839       /* /val */
840       else {
841 	scanNMArea(area);
842 	return 1;
843       }
844     } else {
845 	/*  maybe it's echo area */
846 	area = getEchoArea(config, name);
847 	if (area != &(config->badArea)) {
848 	    if (area && area->msgbType != MSGTYPE_PASSTHROUGH &&
849 		area -> downlinkCount > 0) {
850                 /* val: scan mode check */
851                 if (area->scanMode == smNever) {
852                   w_log(LL_SCANNING, "Area \'%s\': scanning is off -> Skipped", name);
853                   return 0;
854                 }
855                 else if (area->scanMode == smManual && mode != smManual) {
856                   w_log(LL_SCANNING, "Area \'%s\': manual scanning only -> Skipped", name);
857                   return 0;
858                 }
859                 /* /val */
860 		scanEMArea(area);
861 		return 1;
862 	    }
863 	} else {
864 	    if (NULL != getLocalArea(config,name))
865 		w_log(LL_SCANNING, "Area \'%s\' is local -> Skipped", name);
866 	    else
867 		w_log(LL_SCANNING, "Area \'%s\' is not found -> Scanning stop", name);
868 	}
869     }
870     return 0;
871 }
872 
scanAllAreas(int type)873 void scanAllAreas(int type)
874 {
875     unsigned int i;
876     if (type & SCN_ECHOMAIL) {
877         for (i = 0; i< config->echoAreaCount; i++) {
878             if ((config->echoAreas[i].msgbType != MSGTYPE_PASSTHROUGH) && (config->echoAreas[i].downlinkCount > 0)) {
879                 /* val: scan only if mode is not set */
880                 if ( (config->echoAreas[i]).scanMode == smNone )
881                     scanEMArea(&(config->echoAreas[i]));
882             }
883         }
884     };
885     if (type & SCN_NETMAIL) {
886         for (i = 0; i < config->netMailAreaCount; i++) {
887             /* val: scan only if mode is not set */
888             if ( (config->netMailAreas[i]).scanMode == smNone )
889                 scanNMArea(&(config->netMailAreas[i]));
890         }
891     };
892 }
893 
scanExport(int type,char * str)894 void scanExport(int type, char *str) {
895 
896     unsigned int i = 0;
897     FILE *f = NULL;
898     FILE *ftmp = NULL;
899     char *tmplogname = NULL;
900     char *line = NULL;
901     struct stat st;
902     int processed=0;
903 
904     if ( !config->tempDir )
905     {
906         exit_hpt( "tempDir not defined in config. scanExport is not possible" , 1 );
907     }
908 
909     w_log( LL_FUNC, "scanExport() begin" );
910 
911     /*  zero statScan */
912     memset(&statScan, '\0', sizeof(s_statScan));
913     w_log(LL_START, "Start %s%s%s...",
914         type & SCN_ECHOMAIL ? "scanning" : "packing",
915         type & SCN_FILE ? " with -f " :
916         type & SCN_NAME ? " with -a " : "",
917         str == NULL ? "" : str);
918 
919     w_log( LL_SRCLINE, "%s:%d", __FILE__, __LINE__ );
920 
921     if (type & SCN_ALL) {
922         if (config->echotosslog)
923         {
924             f = fopen(config->echotosslog, "r");
925             if (f != NULL && config->packNetMailOnScan == 0) {
926                 ftmp = createTempTextFile(config->tempDir, &tmplogname); /* error diagnostic prints by createTempTextFile() */
927                 if (ftmp == NULL) {
928                     /* close file so all areas will be scanned instead of panic. */
929                     fclose(f);
930                     f = NULL;
931                 }
932             }
933         }
934     }
935 
936     w_log( LL_SRCLINE, "%s:%d", __FILE__, __LINE__ );
937 
938     if (type & SCN_FILE) {
939         if (str == NULL) str = config->echotosslog;
940         f = fopen(str, "r");
941         if (f != NULL && config->packNetMailOnScan == 0) {
942             ftmp = createTempTextFile(config->tempDir, &tmplogname); /* error diagnostic prints by createTempTextFile() */
943             if (ftmp == NULL) {
944                 /* close file so all areas will be scanned instead of panic. */
945                 fclose(f);
946                 f = NULL;
947             }
948         }
949     }
950 
951     w_log( LL_SRCLINE, "%s:%d", __FILE__, __LINE__ );
952 
953     if (type & SCN_NAME) {
954         if (type & SCN_NETMAIL) {
955             for (i = 0; i< config->netMailAreaCount; i++) {
956                 if (patimat(config->netMailAreas[i].areaName, str))
957                     scanByName(config->netMailAreas[i].areaName,
958                                                               smManual);
959             }
960         } else {
961             for (i = 0; i< config->echoAreaCount; i++) {
962                 if (patimat(config->echoAreas[i].areaName, str))
963                     scanByName(config->echoAreas[i].areaName, smManual);
964             }
965         }
966     } else if (f == NULL) {
967         if (type & SCN_FILE) {
968             w_log(LL_START, "EchoTossLogFile not found -> Scanning stopped");
969             nfree(tmplogname);
970             return;
971         }
972         /*  if echotoss file does not exist scan all areas */
973         w_log(LL_START, "EchoTossLogFile not found -> Scanning all areas");
974         scanAllAreas(type);
975     } else {
976         /*  else scan only those areas which are listed in the file */
977         w_log(LL_START, "EchoTossLogFile found -> Scanning only listed areas");
978 
979         processed = 0;
980         while (!feof(f)) {
981             line = readLine(f);
982 
983             if (line != NULL) {
984                 if (*line && line[strlen(line)-1] == '\r')
985                     line[strlen(line)-1] = '\0';  /* fix for DOSish echotoss.log */
986                 striptwhite(line);
987                 if (!ftmp) { /*  the same as if(config->packNetMailOnScan) { */
988                     scanByName(line, smListed);
989                 } else {
990                     processed |= 1; /* areas found, but not processed yet. */
991                     /* exclude NetmailAreas in echoTossLogFile */
992                    if (type & SCN_ECHOMAIL) {
993                        if (getNetMailArea(config, line) == NULL) {
994                            if(scanByName(line, smListed))
995                                processed |= 2;
996                        }
997                        else
998                        {
999                            fprintf(ftmp, "%s\n", line);
1000                            processed |= 2;
1001                        }
1002                     } else {
1003                        if (getNetMailArea(config, line) != NULL) {
1004                            if(scanByName(line, smListed))
1005                                processed |= 2;
1006                        }
1007                        else
1008                            fprintf(ftmp, "%s\n", line);
1009                     }
1010                 }
1011                 nfree(line);
1012             }
1013         }
1014     }
1015 
1016     w_log( LL_SRCLINE, "%s:%d", __FILE__, __LINE__ );
1017 
1018     if ((processed == 1) && ((type & SCN_FILE) != SCN_FILE)) {
1019         w_log(LL_START, "EchoTossLogFile found, but contains no areas -> processing all areas.");
1020         scanAllAreas(type);
1021     }
1022 
1023     w_log( LL_SRCLINE, "%s:%d", __FILE__, __LINE__ );
1024 
1025     if (f != NULL) {
1026         fclose(f);
1027         if (ftmp != NULL)
1028         {
1029             fclose(ftmp);
1030             memset(&st, 0, sizeof(st));
1031             stat(tmplogname, &st);
1032             if (type & SCN_ALL) {
1033                 if (st.st_size == 0) { /*  all entries was processed */
1034                     remove(config->echotosslog);
1035                     if (remove(tmplogname) != 0)
1036                         w_log(LL_ERR, "Couldn't remove temporary file\"%s\"", tmplogname);
1037                 } else { /*  we still have areas */
1038                     remove(config->echotosslog);
1039                     if (rename(tmplogname, config->echotosslog) != 0)
1040                         w_log(LL_ERR, "Couldn't rename \"%s\" -> \"%s\"", tmplogname, config->echotosslog);
1041                 }
1042             } else {
1043                 if (st.st_size == 0) {
1044                     remove(str);
1045                     if (remove(tmplogname) != 0)
1046                         w_log(LL_ERR, "Couldn't remove temporary file\"%s\"", tmplogname);
1047                 } else {
1048                     remove(str);
1049                     if (rename(tmplogname, str) != 0)
1050                         w_log(LL_ERR, "Couldn't rename \"%s\" -> \"%s\"", tmplogname, str);
1051                 }
1052             }
1053         }
1054         else
1055         {
1056             if (type & SCN_ALL) {
1057                 remove(config->echotosslog);
1058             }
1059             else if (type & SCN_FILE) {
1060                 remove(str);
1061             }
1062         }
1063     }
1064     nfree (tmplogname);
1065 
1066     tossTempOutbound(config->tempOutbound);
1067 
1068     writeDupeFiles();
1069     writeScanStatToLog();
1070 
1071     w_log( LL_FUNC, "scanExport() end" );
1072 }
1073