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